diff options
Diffstat (limited to 'server')
87 files changed, 0 insertions, 32793 deletions
diff --git a/server/.cvsignore b/server/.cvsignore deleted file mode 100644 index 88ac171b53..0000000000 --- a/server/.cvsignore +++ /dev/null @@ -1,14 +0,0 @@ -Makefile -.deps -.libs -*.lo -*.la -uri_delims.h -gen_uri_delims -test_char.h -gen_test_char -*.mak -exports.c -Debug -Release -apache.exports diff --git a/server/.indent.pro b/server/.indent.pro deleted file mode 100644 index a9fbe9f9a1..0000000000 --- a/server/.indent.pro +++ /dev/null @@ -1,54 +0,0 @@ --i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 --TBUFF --TFILE --TTRANS --TUINT4 --T_trans --Tallow_options_t --Tapache_sfio --Tarray_header --Tbool_int --Tbuf_area --Tbuff_struct --Tbuffy --Tcmd_how --Tcmd_parms --Tcommand_rec --Tcommand_struct --Tconn_rec --Tcore_dir_config --Tcore_server_config --Tdir_maker_func --Tevent --Tglobals_s --Thandler_func --Thandler_rec --Tjoblist_s --Tlisten_rec --Tmerger_func --Tmode_t --Tmodule --Tmodule_struct --Tmutex --Tn_long --Tother_child_rec --Toverrides_t --Tparent_score --Tpid_t --Tpiped_log --Tpool --Trequest_rec --Trequire_line --Trlim_t --Tscoreboard --Tsemaphore --Tserver_addr_rec --Tserver_rec --Tserver_rec_chain --Tshort_score --Ttable --Ttable_entry --Tthread --Tu_wide_int --Tvtime_t --Twide_int diff --git a/server/Makefile.in b/server/Makefile.in deleted file mode 100644 index 24aef10277..0000000000 --- a/server/Makefile.in +++ /dev/null @@ -1,69 +0,0 @@ - -TARGET_EXPORTS = apache.exports -CLEAN_TARGETS = gen_test_char gen_uri_delims test_char.h uri_delims.h \ - $(TARGET_EXPORTS) ApacheCoreOS2.def -EXTRACLEAN_TARGETS = exports.c - -SUBDIRS = mpm - -LTLIBRARY_NAME = libmain.la -LTLIBRARY_SOURCES = \ - uri_delims.h test_char.h \ - config.c log.c main.c vhost.c util.c util_date.c \ - util_script.c util_uri.c util_md5.c util_cfgtree.c util_ebcdic.c \ - rfc1413.c connection.c listen.c \ - mpm_common.c util_charset.c util_debug.c util_xml.c \ - util_filter.c exports.c buildmark.c scoreboard.c \ - error_bucket.c protocol.c core.c request.c - -targets = delete-exports $(LTLIBRARY_NAME) $(CORE_IMPLIB_FILE) - -include $(top_srcdir)/build/rules.mk -include $(top_srcdir)/build/library.mk - -gen_uri_delims_OBJECTS = gen_uri_delims.lo -gen_uri_delims: $(gen_uri_delims_OBJECTS) - $(LINK) $(EXTRA_LDFLAGS) $(gen_uri_delims_OBJECTS) $(EXTRA_LIBS) - -gen_test_char_OBJECTS = gen_test_char.lo util_debug.lo -gen_test_char: $(gen_test_char_OBJECTS) - $(LINK) $(EXTRA_LDFLAGS) $(gen_test_char_OBJECTS) $(EXTRA_LIBS) - -uri_delims.h: gen_uri_delims - ./gen_uri_delims > uri_delims.h - -test_char.h: gen_test_char - ./gen_test_char > test_char.h - -util_uri.lo: uri_delims.h -util.lo: test_char.h - -EXPORT_FILES = ../srclib/apr/apr.exports ../srclib/apr-util/aprutil.exports \ - $(TARGET_EXPORTS) - -delete-exports: - @if test -f $(TARGET_EXPORTS); then \ - headers="`find ../include/*.h -newer $(TARGET_EXPORTS)`" ; \ - if test -n "$$headers"; then \ - echo Found newer headers. Will rebuild $(TARGET_EXPORTS). ; \ - echo rm -f $(TARGET_EXPORTS) ; \ - rm -f $(TARGET_EXPORTS) ; \ - fi \ - fi - - -$(TARGET_EXPORTS): - $(AWK) -f $(top_srcdir)/srclib/apr/build/make_export.awk \ - $(top_srcdir)/include/*.h \ - $(top_srcdir)/os/$(OS_DIR)/*.h > $@ - -exports.c: $(EXPORT_FILES) - (cat $(EXPORT_FILES) | ../build/buildexports.sh ..) > $@ - -# wtf does this have to be explicit???? -exports.lo: exports.c - -# Rule to make def file for OS/2 core dll -ApacheCoreOS2.def: exports.c $(top_srcdir)/os/$(OS_DIR)/core_header.def - cat $(top_srcdir)/os/$(OS_DIR)/core_header.def > $@ - $(CPP) $< $(ALL_CPPFLAGS) $(ALL_INCLUDES) | grep "ap_hack_" | sed -e 's/^.*[)]\(.*\);$$/ "\1"/' >> $@ diff --git a/server/buildmark.c b/server/buildmark.c deleted file mode 100644 index b25783d097..0000000000 --- a/server/buildmark.c +++ /dev/null @@ -1,67 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "ap_config.h" -#include "httpd.h" - -#if defined(__DATE__) && defined(__TIME__) -static const char server_built[] = __DATE__ " " __TIME__; -#else -static const char server_built[] = "unknown"; -#endif - -AP_DECLARE(const char *) ap_get_server_built() -{ - return server_built; -} diff --git a/server/config.c b/server/config.c deleted file mode 100644 index 689b347777..0000000000 --- a/server/config.c +++ /dev/null @@ -1,1763 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_config.c: once was auxillary functions for reading httpd's config - * file and converting filenames into a namespace - * - * Rob McCool - * - * Wall-to-wall rewrite for Apache... commands which are part of the - * server core can now be found next door in "http_core.c". Now contains - * general command loop, and functions which do bookkeeping for the new - * Apache config stuff (modules and configuration vectors). - * - * rst - * - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_portable.h" -#include "apr_file_io.h" - -#define APR_WANT_STDIO -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_protocol.h" -#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_main.h" -#include "http_vhost.h" -#include "util_cfgtree.h" -#include "mpm.h" - - -AP_DECLARE_DATA const char *ap_server_argv0; - -AP_DECLARE_DATA const char *ap_server_root; - -AP_DECLARE_DATA apr_array_header_t *ap_server_pre_read_config; -AP_DECLARE_DATA apr_array_header_t *ap_server_post_read_config; -AP_DECLARE_DATA apr_array_header_t *ap_server_config_defines; - -AP_DECLARE_DATA ap_directive_t *ap_conftree; - -APR_HOOK_STRUCT( - APR_HOOK_LINK(header_parser) - APR_HOOK_LINK(pre_config) - APR_HOOK_LINK(post_config) - APR_HOOK_LINK(open_logs) - APR_HOOK_LINK(child_init) - APR_HOOK_LINK(handler) - APR_HOOK_LINK(quick_handler) - APR_HOOK_LINK(optional_fn_retrieve) -) - -AP_IMPLEMENT_HOOK_RUN_ALL(int,header_parser, - (request_rec *r),(r),OK,DECLINED) -AP_IMPLEMENT_HOOK_VOID(pre_config, - (apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp), - (pconf,plog,ptemp)) -AP_IMPLEMENT_HOOK_VOID(post_config, - (apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, - server_rec *s),(pconf,plog,ptemp,s)) -AP_IMPLEMENT_HOOK_VOID(open_logs, - (apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, - server_rec *s),(pconf,plog,ptemp,s)) -AP_IMPLEMENT_HOOK_VOID(child_init, - (apr_pool_t *pchild, server_rec *s),(pchild,s)) - -AP_IMPLEMENT_HOOK_RUN_FIRST(int,handler,(request_rec *r), - (r),DECLINED) -AP_IMPLEMENT_HOOK_RUN_FIRST(int,quick_handler,(request_rec *r), - (r),DECLINED) - -AP_IMPLEMENT_HOOK_VOID(optional_fn_retrieve,(void),()) - -/**************************************************************** - * - * We begin with the functions which deal with the linked list - * of modules which control just about all of the server operation. - */ - -/* total_modules is the number of modules that have been linked - * into the server. - */ -static int total_modules = 0; -/* dynamic_modules is the number of modules that have been added - * after the pre-loaded ones have been set up. It shouldn't be larger - * than DYNAMIC_MODULE_LIMIT. - */ -static int dynamic_modules = 0; -AP_DECLARE_DATA module *ap_top_module = NULL; -AP_DECLARE_DATA module **ap_loaded_modules=NULL; - -typedef int (*handler_func) (request_rec *); -typedef void *(*dir_maker_func) (apr_pool_t *, char *); -typedef void *(*merger_func) (apr_pool_t *, void *, void *); - -/* Dealing with config vectors. These are associated with per-directory, - * per-server, and per-request configuration, and have a void* pointer for - * each modules. The nature of the structure pointed to is private to the - * module in question... the core doesn't (and can't) know. However, there - * are defined interfaces which allow it to create instances of its private - * per-directory and per-server structures, and to merge the per-directory - * structures of a directory and its subdirectory (producing a new one in - * which the defaults applying to the base directory have been properly - * overridden). - */ - -static ap_conf_vector_t *create_empty_config(apr_pool_t *p) -{ - void *conf_vector = apr_pcalloc(p, sizeof(void *) * - (total_modules + DYNAMIC_MODULE_LIMIT)); - return conf_vector; -} - -static ap_conf_vector_t *create_default_per_dir_config(apr_pool_t *p) -{ - void **conf_vector = apr_pcalloc(p, sizeof(void *) * - (total_modules + DYNAMIC_MODULE_LIMIT)); - module *modp; - - for (modp = ap_top_module; modp; modp = modp->next) { - dir_maker_func df = modp->create_dir_config; - - if (df) - conf_vector[modp->module_index] = (*df) (p, NULL); - } - - return (ap_conf_vector_t *) conf_vector; -} - -ap_conf_vector_t *ap_merge_per_dir_configs(apr_pool_t *p, - ap_conf_vector_t *base, - ap_conf_vector_t *new_conf) -{ - void **conf_vector = apr_palloc(p, sizeof(void *) * total_modules); - void **base_vector = (void **) base; - void **new_vector = (void **) new_conf; - module *modp; - - for (modp = ap_top_module; modp; modp = modp->next) { - merger_func df = modp->merge_dir_config; - int i = modp->module_index; - - if (df && new_vector[i]) - conf_vector[i] = (*df) (p, base_vector[i], new_vector[i]); - else - conf_vector[i] = new_vector[i] ? new_vector[i] : base_vector[i]; - } - - return (ap_conf_vector_t *) conf_vector; -} - -static ap_conf_vector_t *create_server_config(apr_pool_t *p, server_rec *s) -{ - void **conf_vector = apr_pcalloc(p, sizeof(void *) * - (total_modules + DYNAMIC_MODULE_LIMIT)); - module *modp; - - for (modp = ap_top_module; modp; modp = modp->next) { - if (modp->create_server_config) - conf_vector[modp->module_index] = (*modp->create_server_config) (p, s); - } - - return (ap_conf_vector_t *) conf_vector; -} - -static void merge_server_configs(apr_pool_t *p, ap_conf_vector_t *base, - ap_conf_vector_t *virt) -{ - /* Can reuse the 'virt' vector for the spine of it, since we don't - * have to deal with the moral equivalent of .htaccess files here... - */ - - void **base_vector = (void **) base; - void **virt_vector = (void **) virt; - module *modp; - - for (modp = ap_top_module; modp; modp = modp->next) { - merger_func df = modp->merge_server_config; - int i = modp->module_index; - - if (!virt_vector[i]) - virt_vector[i] = base_vector[i]; - else if (df) - virt_vector[i] = (*df) (p, base_vector[i], virt_vector[i]); - } -} - -ap_conf_vector_t *ap_create_request_config(apr_pool_t *p) -{ - return create_empty_config(p); -} - -ap_conf_vector_t *ap_create_conn_config(apr_pool_t *p) -{ - return create_empty_config(p); -} - -AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_per_dir_config(apr_pool_t *p) -{ - return create_empty_config(p); -} - -int ap_invoke_handler(request_rec *r) -{ - const char *handler; - const char *p; - char *p2; - int result; - char hbuf[MAX_STRING_LEN]; - const char *old_handler = r->handler; - - if (!r->handler) { - handler = r->content_type ? r->content_type : ap_default_type(r); - if ((p=ap_strchr_c(handler, ';')) != NULL) { - apr_cpystrn(hbuf, handler, sizeof hbuf); - p2 = hbuf+(handler-p); - handler = hbuf; - /* MIME type arguments */ - while (p2 > handler && p2[-1] == ' ') - --p2; /* strip trailing spaces */ - *p2='\0'; - } - r->handler = handler; - } - - result = ap_run_handler(r); - - r->handler = old_handler; - - if (result == DECLINED && r->handler && r->filename) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, r, - "handler \"%s\" not found for: %s", r->handler, r->filename); - } - return result == DECLINED ? HTTP_INTERNAL_SERVER_ERROR : result; -} - -AP_DECLARE(int) ap_method_is_limited(cmd_parms *cmd, const char *method) { - int methnum; - int i; - char **xmethod; - - methnum = ap_method_number_of(method); - /* - * The simple case: a method hard-coded into Apache. - */ - if (methnum != M_INVALID) { - return (methnum & cmd->limited); - } - /* - * Some extension method we don't know implicitly. - */ - if ((cmd->limited_xmethods == NULL) - || (cmd->limited_xmethods->nelts == 0)) { - return 0; - } - xmethod = (char **) cmd->limited_xmethods->elts; - for (i = 0; i < cmd->limited_xmethods->nelts; ++i) { - if (strcmp(method, xmethod[i]) == 0) { - return 1; - } - } - return 0; -} - -AP_DECLARE(void) ap_register_hooks(module *m, apr_pool_t *p) -{ - if(m->register_hooks) - { - if(getenv("SHOW_HOOKS")) - { - printf("Registering hooks for %s\n",m->name); - apr_debug_module_hooks=1; - } - apr_current_hooking_module=m->name; - m->register_hooks(p); - } -} - -/* One-time setup for precompiled modules --- NOT to be done on restart */ - -AP_DECLARE(void) ap_add_module(module *m, apr_pool_t *p) -{ - /* This could be called from an AddModule httpd.conf command, - * after the file has been linked and the module structure within it - * teased out... - */ - - if (m->version != MODULE_MAGIC_NUMBER_MAJOR) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s: module \"%s\" is not compatible with this " - "version of Apache.", ap_server_argv0, m->name); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Please contact the vendor for the correct version."); - exit(1); - } - - if (m->next == NULL) { - m->next = ap_top_module; - ap_top_module = m; - } - if (m->module_index == -1) { - m->module_index = total_modules++; - dynamic_modules++; - - if (dynamic_modules > DYNAMIC_MODULE_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s: module \"%s\" could not be loaded, because" - " the dynamic", ap_server_argv0, m->name); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "module limit was reached. Please increase " - "DYNAMIC_MODULE_LIMIT and recompile."); - exit(1); - } - } - - /* Some C compilers put a complete path into __FILE__, but we want - * only the filename (e.g. mod_includes.c). So check for path - * components (Unix and DOS), and remove them. - */ - - if (ap_strrchr_c(m->name, '/')) - m->name = 1 + ap_strrchr_c(m->name, '/'); - if (ap_strrchr_c(m->name, '\\')) - m->name = 1 + ap_strrchr_c(m->name, '\\'); - -#ifdef _OSD_POSIX /* __FILE__="*POSIX(/home/martin/apache/src/modules/standard/mod_info.c)" */ - /* We cannot fix the string in-place, because it's const */ - if (m->name[strlen(m->name)-1]==')') { - char *tmp = strdup(m->name); /* FIXME:memory leak, albeit a small one */ - tmp[strlen(tmp)-1] = '\0'; - m->name = tmp; - } -#endif /*_OSD_POSIX*/ - - /* FIXME: is this the right place to call this? - * It doesn't appear to be - */ - ap_register_hooks(m, p); -} - -/* - * remove_module undoes what add_module did. There are some caveats: - * when the module is removed, its slot is lost so all the current - * per-dir and per-server configurations are invalid. So we should - * only ever call this function when you are invalidating almost - * all our current data. I.e. when doing a restart. - */ - -AP_DECLARE(void) ap_remove_module(module *m) -{ - module *modp; - - modp = ap_top_module; - if (modp == m) { - /* We are the top module, special case */ - ap_top_module = modp->next; - m->next = NULL; - } - else { - /* Not the top module, find use. When found modp will - * point to the module _before_ us in the list - */ - - while (modp && modp->next != m) { - modp = modp->next; - } - if (!modp) { - /* Uh-oh, this module doesn't exist */ - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, NULL, - "Cannot remove module %s: not found in module list", - m->name); - return; - } - /* Eliminate us from the module list */ - modp->next = modp->next->next; - } - - m->module_index = -1; /* simulate being unloaded, should - * be unnecessary */ - dynamic_modules--; - total_modules--; -} - -AP_DECLARE(void) ap_add_loaded_module(module *mod, apr_pool_t *p) -{ - module **m; - - /* - * Add module pointer to top of chained module list - */ - ap_add_module(mod, p); - - /* - * And module pointer to list of loaded modules - * - * Notes: 1. ap_add_module() would already complain if no more space - * exists for adding a dynamically loaded module - * 2. ap_add_module() accepts double inclusion, so we have - * to accept this, too. - */ - for (m = ap_loaded_modules; *m != NULL; m++) - ; - *m++ = mod; - *m = NULL; -} - -AP_DECLARE(void) ap_remove_loaded_module(module *mod) -{ - module **m; - module **m2; - int done; - - /* - * Remove module pointer from chained module list - */ - ap_remove_module(mod); - - /* - * Remove module pointer from list of loaded modules - * - * Note: 1. We cannot determine if the module was successfully - * removed by ap_remove_module(). - * 2. We have not to complain explicity when the module - * is not found because ap_remove_module() did it - * for us already. - */ - for (m = m2 = ap_loaded_modules, done = 0; *m2 != NULL; m2++) { - if (*m2 == mod && done == 0) - done = 1; - else - *m++ = *m2; - } - *m = NULL; -} - -AP_DECLARE(void) ap_setup_prelinked_modules(process_rec *process) -{ - module **m; - module **m2; - - apr_global_hook_pool=process->pconf; - - /* - * Initialise total_modules variable and module indices - */ - total_modules = 0; - for (m = ap_preloaded_modules; *m != NULL; m++) - (*m)->module_index = total_modules++; - - /* - * Initialise list of loaded modules - */ - ap_loaded_modules = (module **)apr_palloc(process->pool, - sizeof(module *)*(total_modules+DYNAMIC_MODULE_LIMIT+1)); - if (ap_loaded_modules == NULL) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Ouch! Out of memory in ap_setup_prelinked_modules()!"); - } - for (m = ap_preloaded_modules, m2 = ap_loaded_modules; *m != NULL; ) - *m2++ = *m++; - *m2 = NULL; - - /* - * Initialize chain of linked (=activate) modules - */ - for (m = ap_prelinked_modules; *m != NULL; m++) - ap_add_module(*m, process->pconf); - - apr_sort_hooks(); -} - -AP_DECLARE(const char *) ap_find_module_name(module *m) -{ - return m->name; -} - -AP_DECLARE(module *) ap_find_linked_module(const char *name) -{ - module *modp; - - for (modp = ap_top_module; modp; modp = modp->next) { - if (strcmp(modp->name, name) == 0) - return modp; - } - return NULL; -} - -/* Add a named module. Returns 1 if module found, 0 otherwise. */ -AP_DECLARE(int) ap_add_named_module(const char *name, apr_pool_t *p) -{ - module *modp; - int i = 0; - - for (modp = ap_loaded_modules[i]; modp; modp = ap_loaded_modules[++i]) { - if (strcmp(modp->name, name) == 0) { - /* Only add modules that are not already enabled. */ - if (modp->next == NULL) { - ap_add_module(modp, p); - } - return 1; - } - } - - return 0; -} - -/***************************************************************** - * - * Resource, access, and .htaccess config files now parsed by a common - * command loop. - * - * Let's begin with the basics; parsing the line and - * invoking the function... - */ - -static const char *invoke_cmd(const command_rec *cmd, cmd_parms *parms, - void *mconfig, const char *args) -{ - char *w, *w2, *w3; - const char *errmsg; - - if ((parms->override & cmd->req_override) == 0) - return apr_pstrcat(parms->pool, cmd->name, " not allowed here", NULL); - - parms->info = cmd->cmd_data; - parms->cmd = cmd; - - switch (cmd->args_how) { - case RAW_ARGS: -#ifdef RESOLVE_ENV_PER_TOKEN - args = ap_resolve_env(parms->pool,args); -#endif - return cmd->AP_RAW_ARGS(parms, mconfig, args); - - case NO_ARGS: - if (*args != 0) - return apr_pstrcat(parms->pool, cmd->name, " takes no arguments", - NULL); - - return cmd->AP_NO_ARGS(parms, mconfig); - - case TAKE1: - w = ap_getword_conf(parms->pool, &args); - - if (*w == '\0' || *args != 0) - return apr_pstrcat(parms->pool, cmd->name, " takes one argument", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return cmd->AP_TAKE1(parms, mconfig, w); - - case TAKE2: - w = ap_getword_conf(parms->pool, &args); - w2 = ap_getword_conf(parms->pool, &args); - - if (*w == '\0' || *w2 == '\0' || *args != 0) - return apr_pstrcat(parms->pool, cmd->name, " takes two arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return cmd->AP_TAKE2(parms, mconfig, w, w2); - - case TAKE12: - - w = ap_getword_conf(parms->pool, &args); - w2 = ap_getword_conf(parms->pool, &args); - - if (*w == '\0' || *args != 0) - return apr_pstrcat(parms->pool, cmd->name, " takes 1-2 arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return cmd->AP_TAKE2(parms, mconfig, w, *w2 ? w2 : NULL); - - case TAKE3: - - w = ap_getword_conf(parms->pool, &args); - w2 = ap_getword_conf(parms->pool, &args); - w3 = ap_getword_conf(parms->pool, &args); - - if (*w == '\0' || *w2 == '\0' || *w3 == '\0' || *args != 0) - return apr_pstrcat(parms->pool, cmd->name, " takes three arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return cmd->AP_TAKE3(parms, mconfig, w, w2, w3); - - case TAKE23: - - w = ap_getword_conf(parms->pool, &args); - w2 = ap_getword_conf(parms->pool, &args); - w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL; - - if (*w == '\0' || *w2 == '\0' || *args != 0) - return apr_pstrcat(parms->pool, cmd->name, - " takes two or three arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return cmd->AP_TAKE3(parms, mconfig, w, w2, w3); - - case TAKE123: - - w = ap_getword_conf(parms->pool, &args); - w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL; - w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL; - - if (*w == '\0' || *args != 0) - return apr_pstrcat(parms->pool, cmd->name, - " takes one, two or three arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return cmd->AP_TAKE3(parms, mconfig, w, w2, w3); - - case TAKE13: - - w = ap_getword_conf(parms->pool, &args); - w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL; - w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL; - - if (*w == '\0' || (w2 && *w2 && !w3) || *args != 0) - return apr_pstrcat(parms->pool, cmd->name, - " takes one or three arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - return cmd->AP_TAKE3(parms, mconfig, w, w2, w3); - - case ITERATE: - - while (*(w = ap_getword_conf(parms->pool, &args)) != '\0') - { - if ((errmsg = cmd->AP_TAKE1(parms, mconfig, w))) - return errmsg; - } - - return NULL; - - case ITERATE2: - - w = ap_getword_conf(parms->pool, &args); - - if (*w == '\0' || *args == 0) - return apr_pstrcat(parms->pool, cmd->name, - " requires at least two arguments", - cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL); - - while (*(w2 = ap_getword_conf(parms->pool, &args)) != '\0') - { - if ((errmsg = cmd->AP_TAKE2(parms, mconfig, w, w2))) - return errmsg; - } - - return NULL; - - case FLAG: - - w = ap_getword_conf(parms->pool, &args); - - if (*w == '\0' || (strcasecmp(w, "on") && strcasecmp(w, "off"))) - return apr_pstrcat(parms->pool, cmd->name, " must be On or Off", - NULL); - - return cmd->AP_FLAG(parms, mconfig, strcasecmp(w, "off") != 0); - - default: - - return apr_pstrcat(parms->pool, cmd->name, - " is improperly configured internally (server bug)", - NULL); - } -} - -AP_CORE_DECLARE(const command_rec *) ap_find_command(const char *name, const command_rec *cmds) -{ - while (cmds->name) - if (!strcasecmp(name, cmds->name)) - return cmds; - else - ++cmds; - - return NULL; -} - -AP_CORE_DECLARE(const command_rec *) ap_find_command_in_modules(const char *cmd_name, module **mod) -{ - const command_rec *cmdp; - module *modp; - - for (modp = *mod; modp; modp = modp->next) - if (modp->cmds && (cmdp = ap_find_command(cmd_name, modp->cmds))) { - *mod = modp; - return cmdp; - } - - return NULL; -} - -AP_CORE_DECLARE(void *) ap_set_config_vectors(server_rec *server, - ap_conf_vector_t *section_vector, - const char *section, - module *mod, apr_pool_t *pconf) -{ - void *section_config = ap_get_module_config(section_vector, mod); - void *server_config = ap_get_module_config(server->module_config, mod); - - if (!section_config && mod->create_dir_config) { - /* ### need to fix the create_dir_config functions' prototype... */ - section_config = (*mod->create_dir_config) (pconf, (char *)section); - ap_set_module_config(section_vector, mod, section_config); - } - - if (!server_config && mod->create_server_config) { - server_config = (*mod->create_server_config) (pconf, server); - ap_set_module_config(server->module_config, mod, server_config); - } - - return section_config; -} - -static const char *execute_now(char *cmd_line, const char *args, cmd_parms *parms, - apr_pool_t *p, apr_pool_t *ptemp, - ap_directive_t **sub_tree, ap_directive_t *parent); - -static const char * ap_build_config_sub(apr_pool_t *p, apr_pool_t *temp_pool, - const char *l, cmd_parms *parms, - ap_directive_t **current, - ap_directive_t **curr_parent, - ap_directive_t **conftree) -{ - const char *args; - char *cmd_name; - ap_directive_t *newdir; - module *mod = ap_top_module; - const command_rec *cmd; - - if (*l == '#' || *l == '\0') - return NULL; - -#if RESOLVE_ENV_PER_TOKEN - args = l; -#else - args = ap_resolve_env(temp_pool, l); -#endif - cmd_name = ap_getword_conf(p, &args); - if (*cmd_name == '\0') { - /* Note: this branch should not occur. An empty line should have - * triggered the exit further above. - */ - return NULL; - } - - newdir = apr_pcalloc(p, sizeof(ap_directive_t)); - newdir->filename = parms->config_file->name; - newdir->line_num = parms->config_file->line_number; - newdir->directive = cmd_name; - newdir->args = apr_pstrdup(p, args); - - if ((cmd = ap_find_command_in_modules(cmd_name, &mod)) != NULL) { - if (cmd->req_override & EXEC_ON_READ) { - const char *retval; - ap_directive_t *sub_tree = NULL; - - parms->err_directive = newdir; - retval = execute_now(cmd_name, args, parms, p, temp_pool, - &sub_tree, *curr_parent); - if (*current) { - (*current)->next = sub_tree; - } - else { - (*current) = sub_tree; - if (*curr_parent) { - (*curr_parent)->first_child = (*current); - } - if (*current) { - (*current)->parent = (*curr_parent); - } - } - if (*current) { - if (!*conftree) { - /* Before walking *current to the end of the list, - * set the head to *current. - */ - *conftree = *current; - } - while ((*current)->next != NULL) { - (*current) = (*current)->next; - (*current)->parent = (*curr_parent); - } - } - return retval; - } - } - - if (cmd_name[0] == '<') { - if (cmd_name[1] != '/') { - (*current) = ap_add_node(curr_parent, *current, newdir, 1); - } - else if (*curr_parent == NULL) { - parms->err_directive = newdir; - return apr_pstrcat(p, cmd_name, - " without matching <", cmd_name + 2, - " section", NULL); - } - else { - char *bracket = cmd_name + strlen(cmd_name) - 1; - - if (*bracket != '>') { - parms->err_directive = newdir; - return apr_pstrcat(p, cmd_name, - "> directive missing closing '>'", NULL); - } - *bracket = '\0'; - if (strcasecmp(cmd_name + 2, - (*curr_parent)->directive + 1) != 0) { - parms->err_directive = newdir; - return apr_pstrcat(p, "Expected </", - (*curr_parent)->directive + 1, "> but saw ", - cmd_name, ">", NULL); - } - *bracket = '>'; - - /* done with this section; move up a level */ - *current = *curr_parent; - *curr_parent = (*current)->parent; - } - } - else { - *current = ap_add_node(curr_parent, *current, newdir, 0); - } - - return NULL; -} - -const char *ap_build_cont_config(apr_pool_t *p, apr_pool_t *temp_pool, - cmd_parms *parms, - ap_directive_t **current, - ap_directive_t **curr_parent, - char *orig_directive) -{ - char l[MAX_STRING_LEN]; - char *bracket; - const char *retval; - ap_directive_t *sub_tree = NULL; - - bracket = apr_pstrcat(p, orig_directive + 1, ">", NULL); - while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) { - if (!memcmp(l, "</", 2) && - (strcasecmp(l + 2, bracket) == 0) && - (*curr_parent == NULL)) { - break; - } - retval = ap_build_config_sub(p, temp_pool, l, parms, current, - curr_parent, &sub_tree); - if (retval != NULL) - return retval; - if (sub_tree == NULL && curr_parent != NULL) { - sub_tree = *curr_parent; - } - if (sub_tree == NULL && current != NULL) { - sub_tree = *current; - } - } - *current = sub_tree; - return NULL; -} - -static const char *ap_walk_config_sub(const ap_directive_t *current, - cmd_parms *parms, - ap_conf_vector_t *section_vector) -{ - module *mod = ap_top_module; - - while (1) { - const command_rec *cmd; - - if (!(cmd = ap_find_command_in_modules(current->directive, &mod))) { - parms->err_directive = current; - return apr_pstrcat(parms->pool, "Invalid command '", - current->directive, - "', perhaps mis-spelled or defined by a module " - "not included in the server configuration", - NULL); - } - else { - void *dir_config = ap_set_config_vectors(parms->server, - section_vector, - parms->path, - mod, - parms->pool); - const char *retval; - - retval = invoke_cmd(cmd, parms, dir_config, current->args); - if (retval == NULL) { - return NULL; - } - if (strcmp(retval, DECLINE_CMD) != 0) { - /* If the directive in error has already been set, don't - * replace it. Otherwise, an error inside a container - * will be reported as occuring on the first line of the - * container. - */ - if (!parms->err_directive) { - parms->err_directive = current; - } - return retval; - } - - mod = mod->next; /* Next time around, skip this one */ - } - } - /* NOTREACHED */ -} - -AP_DECLARE(const char *) ap_walk_config(ap_directive_t *current, - cmd_parms *parms, - ap_conf_vector_t *section_vector) -{ - ap_conf_vector_t *oldconfig = parms->context; - - parms->context = section_vector; - - /* scan through all directives, executing each one */ - for (; current != NULL; current = current->next) { - const char *errmsg; - - parms->directive = current; - - /* actually parse the command and execute the correct function */ - errmsg = ap_walk_config_sub(current, parms, section_vector); - if (errmsg != NULL) { - /* restore the context (just in case) */ - parms->context = oldconfig; - return errmsg; - } - } - - parms->context = oldconfig; - return NULL; -} - - -AP_DECLARE(const char *) ap_build_config(cmd_parms *parms, - apr_pool_t *p, apr_pool_t *temp_pool, - ap_directive_t **conftree) -{ - ap_directive_t *current = *conftree; - ap_directive_t *curr_parent = NULL; - char l[MAX_STRING_LEN]; - const char *errmsg; - - if (current != NULL) { - while (current->next) { - current = current->next; - } - } - - while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) { - - errmsg = ap_build_config_sub(p, temp_pool, l, parms, - ¤t, &curr_parent, conftree); - if (errmsg != NULL) - return errmsg; - - if (*conftree == NULL && curr_parent != NULL) { - *conftree = curr_parent; - } - if (*conftree == NULL && current != NULL) { - *conftree = current; - } - } - - if (curr_parent != NULL) { - errmsg = ""; - while (curr_parent != NULL) { - errmsg = apr_psprintf(p, "%s%s%s:%u: %s> was not closed.", - errmsg, - *errmsg == '\0' ? "" : APR_EOL_STR, - curr_parent->filename, - curr_parent->line_num, - curr_parent->directive); - curr_parent = curr_parent->parent; - } - return errmsg; - } - - return NULL; -} - -/* - * Generic command functions... - */ - -AP_DECLARE_NONSTD(const char *) ap_set_string_slot(cmd_parms *cmd, - void *struct_ptr, - const char *arg) -{ - /* This one's pretty generic... */ - - int offset = (int) (long) cmd->info; - *(const char **) ((char *)struct_ptr + offset) = arg; - return NULL; -} - -AP_DECLARE_NONSTD(const char *) ap_set_int_slot(cmd_parms *cmd, - void *struct_ptr, - const char *arg) -{ - char *endptr; - char *error_str = NULL; - int offset = (int) (long) cmd->info; - - *(int *) ((char*)struct_ptr + offset) = strtol(arg, &endptr, 10); - - if ((*arg == '\0') || (*endptr != '\0')) { - error_str = apr_psprintf(cmd->pool, - "Invalid value for directive %s, expected integer", - cmd->directive->directive); - } - - return error_str; -} - -AP_DECLARE_NONSTD(const char *) ap_set_string_slot_lower(cmd_parms *cmd, - void *struct_ptr, - const char *arg_) -{ - /* This one's pretty generic... */ - char *arg=apr_pstrdup(cmd->pool,arg_); - - int offset = (int) (long) cmd->info; - ap_str_tolower(arg); - *(char **) ((char *)struct_ptr + offset) = arg; - return NULL; -} - -AP_DECLARE_NONSTD(const char *) ap_set_flag_slot(cmd_parms *cmd, - void *struct_ptr_v, int arg) -{ - /* This one's pretty generic too... */ - - int offset = (int) (long) cmd->info; - char *struct_ptr = (char *)struct_ptr_v; - *(int *) (struct_ptr + offset) = arg ? 1 : 0; - return NULL; -} - -AP_DECLARE_NONSTD(const char *) ap_set_file_slot(cmd_parms *cmd, void *struct_ptr, - const char *arg) -{ - /* Prepend server_root to relative arg. - This allows .htaccess to be independent of server_root, - so the server can be moved or mirrored with less pain. */ - char *p; - int offset = (int) (long) cmd->info; -#ifndef OS2 - arg = ap_os_canonical_filename(cmd->pool, arg); -#endif - if (ap_os_is_path_absolute(arg)) - p = apr_pstrdup(cmd->pool, arg); - else - p = ap_make_full_path(cmd->pool, ap_server_root, arg); - *(char **) ((char*)struct_ptr + offset) = p; - return NULL; -} - -/***************************************************************** - * - * Reading whole config files... - */ - -static cmd_parms default_parms = -{NULL, 0, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; - -AP_DECLARE(const char *) ap_server_root_relative(apr_pool_t *p, const char *file) -{ -#ifndef OS2 - file = ap_os_canonical_filename(p, file); -#endif - if(ap_os_is_path_absolute(file)) - return file; - return ap_make_full_path(p, ap_server_root, file); -} - -AP_DECLARE(const char *) ap_soak_end_container(cmd_parms *cmd, char *directive) -{ - char l[MAX_STRING_LEN]; - const char *args; - char *cmd_name; - - while(!(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) { -#if RESOLVE_ENV_PER_TOKEN - args = l; -#else - args = ap_resolve_env(cmd->temp_pool, l); -#endif - cmd_name = ap_getword_conf(cmd->pool, &args); - if (cmd_name[0] == '<') { - if (cmd_name[1] == '/') { - cmd_name[strlen(cmd_name) - 1] = '\0'; - if (strcasecmp(cmd_name + 2, directive + 1) != 0) { - return apr_pstrcat(cmd->pool, "Expected </", - directive + 1, "> but saw ", - cmd_name, ">", NULL); - } - return NULL; /* found end of container */ - } - else { - const char *msg; - - if ((msg = ap_soak_end_container(cmd, cmd_name)) != NULL) { - return msg; - } - } - } - } - return apr_pstrcat(cmd->pool, "Expected </", - directive + 1, "> before end of configuration", - NULL); -} - -static const char *execute_now(char *cmd_line, const char *args, cmd_parms *parms, - apr_pool_t *p, apr_pool_t *ptemp, - ap_directive_t **sub_tree, ap_directive_t *parent) -{ - module *mod = ap_top_module; - const command_rec *cmd; - - if (!(cmd = ap_find_command_in_modules(cmd_line, &mod))) { - return apr_pstrcat(parms->pool, "Invalid command '", - cmd_line, - "', perhaps mis-spelled or defined by a module " - "not included in the server configuration", - NULL); - } - else { - return invoke_cmd(cmd, parms, sub_tree, args); - } -} - -/* This structure and the following functions are needed for the - * table-based config file reading. They are passed to the - * cfg_open_custom() routine. - */ - -/* Structure to be passed to cfg_open_custom(): it contains an - * index which is incremented from 0 to nelts on each call to - * cfg_getline() (which in turn calls arr_elts_getstr()) - * and an apr_array_header_t pointer for the string array. - */ -typedef struct { - apr_array_header_t *array; - int curr_idx; -} arr_elts_param_t; - - -/* arr_elts_getstr() returns the next line from the string array. */ -static void *arr_elts_getstr(void *buf, size_t bufsiz, void *param) -{ - arr_elts_param_t *arr_param = (arr_elts_param_t *) param; - - /* End of array reached? */ - if (++arr_param->curr_idx > arr_param->array->nelts) - return NULL; - - /* return the line */ - apr_cpystrn(buf, ((char **) arr_param->array->elts)[arr_param->curr_idx - 1], bufsiz); - - return buf; -} - - -/* arr_elts_close(): dummy close routine (makes sure no more lines can be read) */ -static int arr_elts_close(void *param) -{ - arr_elts_param_t *arr_param = (arr_elts_param_t *) param; - arr_param->curr_idx = arr_param->array->nelts; - return 0; -} - -static void process_command_config(server_rec *s, apr_array_header_t *arr, - ap_directive_t **conftree, apr_pool_t *p, - apr_pool_t *ptemp) -{ - const char *errmsg; - cmd_parms parms; - arr_elts_param_t arr_parms; - - arr_parms.curr_idx = 0; - arr_parms.array = arr; - - parms = default_parms; - parms.pool = p; - parms.temp_pool = ptemp; - parms.server = s; - parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT); - - parms.config_file = ap_pcfg_open_custom(p, "-c/-C directives", - &arr_parms, NULL, - arr_elts_getstr, arr_elts_close); - - errmsg = ap_build_config(&parms, p, ptemp, conftree); - if (errmsg) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Syntax error in -C/-c directive:" APR_EOL_STR "%s", - errmsg); - exit(1); - } - - ap_cfg_closefile(parms.config_file); -} - -typedef struct { - char *fname; -} fnames; - -static int fname_alphasort(const void *fn1, const void *fn2) -{ - const fnames *f1 = fn1; - const fnames *f2 = fn2; - - return strcmp(f1->fname,f2->fname); -} - -void ap_process_resource_config(server_rec *s, const char *fname, - ap_directive_t **conftree, apr_pool_t *p, - apr_pool_t *ptemp) -{ - cmd_parms parms; - apr_finfo_t finfo; - const char *errmsg; - ap_configfile_t *cfp; - - fname = ap_server_root_relative(p, fname); - - /* don't require conf/httpd.conf if we have a -C or -c switch */ - if ((ap_server_pre_read_config->nelts - || ap_server_post_read_config->nelts) - && !(strcmp(fname, ap_server_root_relative(p, SERVER_CONFIG_FILE)))) { - if (apr_lstat(&finfo, fname, APR_FINFO_TYPE, p) != APR_SUCCESS) - return; - } - - /* - * here we want to check if the candidate file is really a - * directory, and most definitely NOT a symlink (to prevent - * horrible loops). If so, let's recurse and toss it back - * into the function. - */ - if (ap_is_rdirectory(ptemp, fname)) { - apr_dir_t *dirp; - apr_finfo_t dirent; - int current; - apr_array_header_t *candidates = NULL; - fnames *fnew; - apr_status_t rv; - char errmsg[120]; - - /* - * first course of business is to grok all the directory - * entries here and store 'em away. Recall we need full pathnames - * for this. - */ - fprintf(stderr, "Processing config directory: %s\n", fname); - rv = apr_dir_open(&dirp, fname, p); - if (rv != APR_SUCCESS) { - fprintf(stderr, "%s: could not open config directory %s: %s\n", - ap_server_argv0, fname, - apr_strerror(rv, errmsg, sizeof errmsg)); - exit(1); - } - candidates = apr_array_make(p, 1, sizeof(fnames)); - while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) { - /* strip out '.' and '..' */ - if (strcmp(dirent.name, ".") && - strcmp(dirent.name, "..")) { - fnew = (fnames *) apr_array_push(candidates); - fnew->fname = ap_make_full_path(p, fname, dirent.name); - } - } - apr_dir_close(dirp); - if (candidates->nelts != 0) { - qsort((void *) candidates->elts, candidates->nelts, - sizeof(fnames), fname_alphasort); - /* - * Now recurse these... we handle errors and subdirectories - * via the recursion, which is nice - */ - for (current = 0; current < candidates->nelts; ++current) { - fnew = &((fnames *) candidates->elts)[current]; - fprintf(stderr, " Processing config file: %s\n", fnew->fname); - ap_process_resource_config(s, fnew->fname, conftree, p, ptemp); - } - } - return; - } - - /* GCC's initialization extensions are soooo nice here... */ - - parms = default_parms; - parms.pool = p; - parms.temp_pool = ptemp; - parms.server = s; - parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT); - - if (ap_pcfg_openfile(&cfp, p, fname) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s: could not open document config file %s", - ap_server_argv0, fname); - exit(1); - } - - parms.config_file = cfp; - - errmsg = ap_build_config(&parms, p, ptemp, conftree); - - if (errmsg != NULL) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Syntax error on line %d of %s:", - parms.err_directive->line_num, - parms.err_directive->filename); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "%s", errmsg); - exit(1); - } - - ap_cfg_closefile(cfp); -} - -AP_DECLARE(void) ap_process_config_tree(server_rec *s, - ap_directive_t *conftree, - apr_pool_t *p, apr_pool_t *ptemp) -{ - const char *errmsg; - cmd_parms parms; - - parms = default_parms; - parms.pool = p; - parms.temp_pool = ptemp; - parms.server = s; - parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT); - parms.limited = -1; - - errmsg = ap_walk_config(conftree, &parms, s->lookup_defaults); - if (errmsg) { - ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, p, - "Syntax error on line %d of %s:", - parms.err_directive->line_num, - parms.err_directive->filename); - ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, p, - "%s", errmsg); - exit(1); - } -} - -int ap_parse_htaccess(ap_conf_vector_t **result, request_rec *r, int override, - const char *d, const char *access_name) -{ - ap_configfile_t *f = NULL; - cmd_parms parms; - char *filename = NULL; - const struct htaccess_result *cache; - struct htaccess_result *new; - ap_conf_vector_t *dc = NULL; - apr_status_t status; - - /* firstly, search cache */ - for (cache = r->htaccess; cache != NULL; cache = cache->next) - if (cache->override == override && strcmp(cache->dir, d) == 0) { - if (cache->htaccess != NULL) - *result = cache->htaccess; - return OK; - } - - parms = default_parms; - parms.override = override; - parms.pool = r->pool; - parms.temp_pool = r->pool; - parms.server = r->server; - parms.path = apr_pstrdup(r->pool, d); - - /* loop through the access names and find the first one */ - - while (access_name[0]) { - filename = ap_make_full_path(r->pool, d, - ap_getword_conf(r->pool, &access_name)); - status = ap_pcfg_openfile(&f, r->pool, filename); - - if (status == APR_SUCCESS) { - const char *errmsg; - ap_directive_t *temptree = NULL; - - dc = ap_create_per_dir_config(r->pool); - - parms.config_file = f; - errmsg = ap_build_config(&parms, r->pool, r->pool, &temptree); - if (errmsg == NULL) - errmsg = ap_walk_config(temptree, &parms, dc); - - ap_cfg_closefile(f); - - if (errmsg) { - ap_log_rerror(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, r, - "%s: %s", filename, errmsg); - return HTTP_INTERNAL_SERVER_ERROR; - } - *result = dc; - break; - } else { - if (!APR_STATUS_IS_ENOENT(status) - && !APR_STATUS_IS_ENOTDIR(status)) { - ap_log_rerror(APLOG_MARK, APLOG_CRIT, status, r, - "%s pcfg_openfile: unable to check htaccess file, " - "ensure it is readable", - filename); - apr_table_setn(r->notes, "error-notes", - "Server unable to read htaccess file, denying " - "access to be safe"); - return HTTP_FORBIDDEN; - } - } - } - - /* cache it */ - new = apr_palloc(r->pool, sizeof(struct htaccess_result)); - new->dir = parms.path; - new->override = override; - new->htaccess = dc; - - /* add to head of list */ - new->next = r->htaccess; - r->htaccess = new; - - return OK; -} - -AP_CORE_DECLARE(const char *) ap_init_virtual_host(apr_pool_t *p, - const char *hostname, - server_rec *main_server, - server_rec **ps) -{ - server_rec *s = (server_rec *) apr_pcalloc(p, sizeof(server_rec)); - - /* TODO: this crap belongs in http_core */ - s->process = main_server->process; - s->server_admin = NULL; - s->server_hostname = NULL; - s->error_fname = NULL; - s->timeout = 0; - s->keep_alive_timeout = 0; - s->keep_alive = -1; - s->keep_alive_max = -1; - s->error_log = main_server->error_log; - s->loglevel = main_server->loglevel; - /* useful default, otherwise we get a port of 0 on redirects */ - s->port = main_server->port; - s->next = NULL; - - s->is_virtual = 1; - s->names = apr_array_make(p, 4, sizeof(char **)); - s->wild_names = apr_array_make(p, 4, sizeof(char **)); - - s->module_config = create_empty_config(p); - s->lookup_defaults = ap_create_per_dir_config(p); - - s->limit_req_line = main_server->limit_req_line; - s->limit_req_fieldsize = main_server->limit_req_fieldsize; - s->limit_req_fields = main_server->limit_req_fields; - - *ps = s; - - return ap_parse_vhost_addrs(p, hostname, s); -} - - -AP_DECLARE(void) ap_fixup_virtual_hosts(apr_pool_t *p, server_rec *main_server) -{ - server_rec *virt; - - for (virt = main_server->next; virt; virt = virt->next) { - merge_server_configs(p, main_server->module_config, - virt->module_config); - - virt->lookup_defaults = - ap_merge_per_dir_configs(p, main_server->lookup_defaults, - virt->lookup_defaults); - - if (virt->server_admin == NULL) - virt->server_admin = main_server->server_admin; - - if (virt->timeout == 0) - virt->timeout = main_server->timeout; - - if (virt->keep_alive_timeout == 0) - virt->keep_alive_timeout = main_server->keep_alive_timeout; - - if (virt->keep_alive == -1) - virt->keep_alive = main_server->keep_alive; - - if (virt->keep_alive_max == -1) - virt->keep_alive_max = main_server->keep_alive_max; - - /* XXX: this is really something that should be dealt with by a - * post-config api phase */ - ap_core_reorder_directories(p, virt); - } - ap_core_reorder_directories(p, main_server); -} - -/***************************************************************** - * - * Getting *everything* configured... - */ - -static void init_config_globals(apr_pool_t *p) -{ - /* Global virtual host hash bucket pointers. Init to null. */ - ap_init_vhost_config(p); -} - -static server_rec *init_server_config(process_rec *process, apr_pool_t *p) -{ - apr_status_t rv; - server_rec *s = (server_rec *) apr_pcalloc(p, sizeof(server_rec)); - - apr_file_open_stderr(&s->error_log, p); - s->process = process; - s->port = 0; - s->server_admin = DEFAULT_ADMIN; - s->server_hostname = NULL; - s->error_fname = DEFAULT_ERRORLOG; - s->loglevel = DEFAULT_LOGLEVEL; - s->limit_req_line = DEFAULT_LIMIT_REQUEST_LINE; - s->limit_req_fieldsize = DEFAULT_LIMIT_REQUEST_FIELDSIZE; - s->limit_req_fields = DEFAULT_LIMIT_REQUEST_FIELDS; - s->timeout = DEFAULT_TIMEOUT; - s->keep_alive_timeout = DEFAULT_KEEPALIVE_TIMEOUT; - s->keep_alive_max = DEFAULT_KEEPALIVE; - s->keep_alive = 1; - s->next = NULL; - s->addrs = apr_pcalloc(p, sizeof(server_addr_rec)); - /* NOT virtual host; don't match any real network interface */ - rv = apr_sockaddr_info_get(&s->addrs->host_addr, - NULL, APR_INET, 0, 0, p); - ap_assert(rv == APR_SUCCESS); /* otherwise: bug or no storage */ - s->addrs->host_port = 0; /* matches any port */ - s->addrs->virthost = ""; /* must be non-NULL */ - s->names = s->wild_names = NULL; - - s->module_config = create_server_config(p, s); - s->lookup_defaults = create_default_per_dir_config(p); - - return s; -} - - -AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp, - const char *confname, - ap_directive_t **conftree) -{ - apr_pool_t *p = process->pconf; - server_rec *s = init_server_config(process, p); - - init_config_globals(p); - - /* All server-wide config files now have the SAME syntax... */ - - process_command_config(s, ap_server_pre_read_config, conftree, - p, ptemp); - - ap_process_resource_config(s, confname, conftree, p, ptemp); - - process_command_config(s, ap_server_post_read_config, conftree, - p, ptemp); - - return s; -} - -AP_DECLARE(void) ap_single_module_configure(apr_pool_t *p, server_rec *s, - module *m) -{ - if (m->create_server_config) - ap_set_module_config(s->module_config, m, - (*m->create_server_config)(p, s)); - if (m->create_dir_config) - ap_set_module_config(s->lookup_defaults, m, - (*m->create_dir_config)(p, NULL)); -} - -AP_DECLARE(void) ap_run_rewrite_args(process_rec *process) -{ - module *m; - - for (m = ap_top_module; m; m = m->next) - if (m->rewrite_args) - (*m->rewrite_args) (process); -} - -/******************************************************************** - * Configuration directives are restricted in terms of where they may - * appear in the main configuration files and/or .htaccess files according - * to the bitmask req_override in the command_rec structure. - * If any of the overrides set in req_override are also allowed in the - * context in which the command is read, then the command is allowed. - * The context is determined as follows: - * - * inside *.conf --> override = (RSRC_CONF|OR_ALL)&~(OR_AUTHCFG|OR_LIMIT); - * within <Directory> or <Location> --> override = OR_ALL|ACCESS_CONF; - * within .htaccess --> override = AllowOverride for current directory; - * - * the result is, well, a rather confusing set of possibilities for when - * a particular directive is allowed to be used. This procedure prints - * in English where the given (pc) directive can be used. - */ -static void show_overrides(const command_rec *pc, module *pm) -{ - int n = 0; - - printf("\tAllowed in *.conf "); - if ((pc->req_override & (OR_OPTIONS | OR_FILEINFO | OR_INDEXES)) || - ((pc->req_override & RSRC_CONF) && - ((pc->req_override & (ACCESS_CONF | OR_AUTHCFG | OR_LIMIT))))) - printf("anywhere"); - else if (pc->req_override & RSRC_CONF) - printf("only outside <Directory>, <Files> or <Location>"); - else - printf("only inside <Directory>, <Files> or <Location>"); - - /* Warn if the directive is allowed inside <Directory> or .htaccess - * but module doesn't support per-dir configuration */ - - if ((pc->req_override & (OR_ALL | ACCESS_CONF)) && !pm->create_dir_config) - printf(" [no per-dir config]"); - - if (pc->req_override & OR_ALL) { - printf(" and in .htaccess\n\twhen AllowOverride"); - - if ((pc->req_override & OR_ALL) == OR_ALL) - printf(" isn't None"); - else { - printf(" includes "); - - if (pc->req_override & OR_AUTHCFG) { - if (n++) - printf(" or "); - printf("AuthConfig"); - } - if (pc->req_override & OR_LIMIT) { - if (n++) - printf(" or "); - printf("Limit"); - } - if (pc->req_override & OR_OPTIONS) { - if (n++) - printf(" or "); - printf("Options"); - } - if (pc->req_override & OR_FILEINFO) { - if (n++) - printf(" or "); - printf("FileInfo"); - } - if (pc->req_override & OR_INDEXES) { - if (n++) - printf(" or "); - printf("Indexes"); - } - } - } - printf("\n"); -} - -/* Show the preloaded configuration directives, the help string explaining - * the directive arguments, in what module they are handled, and in - * what parts of the configuration they are allowed. Used for httpd -L. - */ -AP_DECLARE(void) ap_show_directives(void) -{ - const command_rec *pc; - int n; - - for (n = 0; ap_loaded_modules[n]; ++n) - for (pc = ap_loaded_modules[n]->cmds; pc && pc->name; ++pc) { - printf("%s (%s)\n", pc->name, ap_loaded_modules[n]->name); - if (pc->errmsg) - printf("\t%s\n", pc->errmsg); - show_overrides(pc, ap_loaded_modules[n]); - } -} - -/* Show the preloaded module names. Used for httpd -l. */ -AP_DECLARE(void) ap_show_modules(void) -{ - int n; - - printf("Compiled in modules:\n"); - for (n = 0; ap_loaded_modules[n]; ++n) - printf(" %s\n", ap_loaded_modules[n]->name); -} - -AP_DECLARE(const char *) ap_show_mpm(void) -{ - return MPM_NAME; -} diff --git a/server/config.m4 b/server/config.m4 deleted file mode 100644 index 761be95a53..0000000000 --- a/server/config.m4 +++ /dev/null @@ -1,29 +0,0 @@ -dnl ## Check for libraries - -AC_CHECK_LIB(nsl, gethostname, APR_ADDTO(LIBS,-lnsl)) -AC_CHECK_LIB(socket, socket, APR_ADDTO(LIBS,-lsocket)) -AC_CHECK_LIB(nsl, gethostbyaddr, APR_ADDTO(LIBS,-lnsl)) - -dnl ## Check for header files - -AC_CHECK_HEADERS(bstring.h unistd.h) - -dnl ## Check for typedefs, structures, and compiler characteristics. - -AC_CACHE_CHECK([for tm_gmtoff in struct tm], ac_cv_struct_tm_gmtoff, -[AC_TRY_COMPILE([#include <sys/types.h> -#include <$ac_cv_struct_tm>], [struct tm tm; tm.tm_gmtoff;], - ac_cv_struct_tm_gmtoff=yes, ac_cv_struct_tm_gmtoff=no)]) - -if test "$ac_cv_struct_tm_gmtoff" = "yes"; then - AC_DEFINE(HAVE_GMTOFF,, - [Define if struct tm has a tm_gmtoff member]) -fi - -dnl ## Check for library functions - -AC_CHECK_FUNCS(syslog) - -dnl Obsolete scoreboard code uses this. - AC_CHECK_HEADERS(sys/times.h) - AC_CHECK_FUNCS(times) diff --git a/server/connection.c b/server/connection.c deleted file mode 100644 index 297d4eef8e..0000000000 --- a/server/connection.c +++ /dev/null @@ -1,263 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr.h" -#include "apr_strings.h" - -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_connection.h" -#include "http_request.h" -#include "http_protocol.h" -#include "ap_mpm.h" -#include "mpm_default.h" -#include "http_config.h" -#include "http_vhost.h" -#include "scoreboard.h" -#include "http_log.h" -#include "util_filter.h" - -APR_HOOK_STRUCT( - APR_HOOK_LINK(pre_connection) - APR_HOOK_LINK(process_connection) -) - -AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_connection,(conn_rec *c),(c),OK,DECLINED) -AP_IMPLEMENT_HOOK_RUN_FIRST(int,process_connection,(conn_rec *c),(c),DECLINED) - -/* - * 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, errno, server_conf, - "setsockopt: (SO_LINGER)"); - /* not a fatal error */ - } -} - -#else -#define sock_enable_linger(s) /* NOOP */ -#endif /* USE_SO_LINGER */ - -AP_CORE_DECLARE(void) ap_flush_conn(conn_rec *c) -{ - apr_bucket_brigade *bb; - apr_bucket *b; - - bb = apr_brigade_create(c->pool); - b = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(c->output_filters, bb); -} - -/* we now proceed to read from the client until we get EOF, or until - * MAX_SECS_TO_LINGER has passed. the reasons for doing this are - * documented in a draft: - * - * http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-connection-00.txt - * - * in a nutshell -- if we don't make this effort we risk causing - * TCP RST packets to be sent which can tear down a connection before - * all the response data has been sent to the client. - */ -#define SECONDS_TO_LINGER 2 -void ap_lingering_close(conn_rec *c) -{ - char dummybuf[512]; - apr_size_t nbytes = sizeof(dummybuf); - apr_status_t rc; - apr_int32_t timeout; - apr_int32_t total_linger_time = 0; - -#ifdef NO_LINGCLOSE - ap_flush_conn(c); /* just close it */ - apr_socket_close(c->client_socket); - return; -#endif - - /* 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. - */ - - /* Send any leftover data to the client, but never try to again */ - ap_flush_conn(c); - - if (c->aborted) { - apr_socket_close(c->client_socket); - return; - } - - /* Shut down the socket for write, which will send a FIN - * to the peer. - */ - - if (apr_shutdown(c->client_socket, APR_SHUTDOWN_WRITE) != APR_SUCCESS || - c->aborted) { - apr_socket_close(c->client_socket); - return; - } - - /* Read all data from the peer until we reach "end-of-file" (FIN - * from peer) or we've exceeded our overall timeout. If the client does - * not send us bytes within 2 seconds (a value pulled from Apache 1.3 - * which seems to work well), close the connection. - */ - timeout = SECONDS_TO_LINGER * APR_USEC_PER_SEC; - apr_setsocketopt(c->client_socket, APR_SO_TIMEOUT, timeout); - for (;;) { - nbytes = sizeof(dummybuf); - rc = apr_recv(c->client_socket, dummybuf, &nbytes); - if (rc != APR_SUCCESS || nbytes == 0) break; - - total_linger_time += SECONDS_TO_LINGER; - if (total_linger_time >= MAX_SECS_TO_LINGER) { - break; - } - } - - apr_socket_close(c->client_socket); -} - -AP_CORE_DECLARE(void) ap_process_connection(conn_rec *c) -{ - ap_update_vhost_given_ip(c); - - ap_run_pre_connection(c); - - ap_run_process_connection(c); - -} - -/* Clearly some of this stuff doesn't belong in a generalised connection - structure, but for now... -*/ - -conn_rec *ap_new_connection(apr_pool_t *p, server_rec *server, - apr_socket_t *inout, long id) -{ - conn_rec *conn = (conn_rec *) apr_pcalloc(p, sizeof(conn_rec)); - apr_status_t rv; - - (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(id), - SERVER_BUSY_READ, (request_rec *) NULL); - - /* Got a connection structure, so initialize what fields we can - * (the rest are zeroed out by pcalloc). - */ - - conn->conn_config=ap_create_conn_config(p); - conn->notes = apr_table_make(p, 5); - - conn->pool = p; - if ((rv = apr_socket_addr_get(&conn->local_addr, APR_LOCAL, inout)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_INFO, rv, server, - "apr_socket_addr_get(APR_LOCAL)"); - apr_socket_close(inout); - return NULL; - } - apr_sockaddr_ip_get(&conn->local_ip, conn->local_addr); - if ((rv = apr_socket_addr_get(&conn->remote_addr, APR_REMOTE, inout)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_INFO, rv, server, - "apr_socket_addr_get(APR_REMOTE)"); - apr_socket_close(inout); - return NULL; - } - apr_sockaddr_ip_get(&conn->remote_ip, conn->remote_addr); - conn->base_server = server; - conn->client_socket = inout; - - conn->id = id; - - return conn; -} diff --git a/server/core.c b/server/core.c deleted file mode 100644 index 092eb62f09..0000000000 --- a/server/core.c +++ /dev/null @@ -1,3336 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_lib.h" -#include "apr_fnmatch.h" -#include "apr_thread_proc.h" /* for RLIMIT stuff */ - -#define APR_WANT_IOVEC -#define APR_WANT_STRFUNC -#define APR_WANT_MEMFUNC -#include "apr_want.h" - -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_protocol.h" /* For index_of_response(). Grump. */ -#include "http_request.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 "http_connection.h" -#include "apr_buckets.h" -#include "util_filter.h" -#include "util_ebcdic.h" -#include "mpm.h" - -#include "mod_core.h" - - -/* LimitXMLRequestBody handling */ -#define AP_LIMIT_UNSET ((long) -1) -#define AP_DEFAULT_LIMIT_XML_BODY ((size_t)1000000) - -#define AP_MIN_SENDFILE_BYTES (256) - -/* Server core module... This module provides support for really basic - * server operations, including options and commands which control the - * operation of other modules. Consider this the bureaucracy module. - * - * The core module also defines handlers, etc., do handle just enough - * to allow a server with the core module ONLY to actually serve documents - * (though it slaps DefaultType on all of 'em); this was useful in testing, - * but may not be worth preserving. - * - * This file could almost be mod_core.c, except for the stuff which affects - * the http_conf_globals. - */ - -static void *create_core_dir_config(apr_pool_t *a, char *dir) -{ - core_dir_config *conf; - - conf = (core_dir_config *)apr_pcalloc(a, sizeof(core_dir_config)); - if (!dir || dir[strlen(dir) - 1] == '/') { - conf->d = dir; - } - else if (strncmp(dir, "proxy:", 6) == 0) { - conf->d = apr_pstrdup(a, dir); - } - else { - conf->d = apr_pstrcat(a, dir, "/", NULL); - } - conf->d_is_fnmatch = conf->d ? (apr_is_fnmatch(conf->d) != 0) : 0; - conf->d_components = conf->d ? ap_count_dirs(conf->d) : 0; - - conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL; - conf->opts_add = conf->opts_remove = OPT_NONE; - conf->override = dir ? OR_UNSET : OR_UNSET|OR_ALL; - - conf->content_md5 = 2; - - conf->use_canonical_name = USE_CANONICAL_NAME_UNSET; - - conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET; - 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->limit_xml_body = AP_LIMIT_UNSET; - conf->sec = apr_array_make(a, 2, sizeof(ap_conf_vector_t *)); -#ifdef WIN32 - conf->script_interpreter_source = INTERPRETER_SOURCE_UNSET; -#endif - - conf->server_signature = srv_sig_unset; - - conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET; - conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME; - - conf->output_filters = apr_array_make(a, 2, sizeof(void *)); - conf->input_filters = apr_array_make(a, 2, sizeof(void *)); - return (void *)conf; -} - -static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv) -{ - core_dir_config *base = (core_dir_config *)basev; - core_dir_config *new = (core_dir_config *)newv; - core_dir_config *conf; - int i; - - conf = (core_dir_config *)apr_palloc(a, sizeof(core_dir_config)); - memcpy((char *)conf, (const char *)base, sizeof(core_dir_config)); - if (base->response_code_strings) { - conf->response_code_strings = - apr_palloc(a, sizeof(*conf->response_code_strings) - * RESPONSE_CODES); - memcpy(conf->response_code_strings, base->response_code_strings, - sizeof(*conf->response_code_strings) * RESPONSE_CODES); - } - - conf->d = new->d; - conf->d_is_fnmatch = new->d_is_fnmatch; - conf->d_components = new->d_components; - conf->r = new->r; - - if (new->opts & OPT_UNSET) { - /* there was no explicit setting of new->opts, so we merge - * preserve the invariant (opts_add & opts_remove) == 0 - */ - conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add; - conf->opts_remove = (conf->opts_remove & ~new->opts_add) - | new->opts_remove; - conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add; - if ((base->opts & OPT_INCNOEXEC) && (new->opts & OPT_INCLUDES)) { - conf->opts = (conf->opts & ~OPT_INCNOEXEC) | OPT_INCLUDES; - } - } - else { - /* otherwise we just copy, because an explicit opts setting - * overrides all earlier +/- modifiers - */ - conf->opts = new->opts; - conf->opts_add = new->opts_add; - conf->opts_remove = new->opts_remove; - } - - if (!(new->override & OR_UNSET)) { - conf->override = new->override; - } - if (new->ap_default_type) { - conf->ap_default_type = new->ap_default_type; - } - - if (new->ap_auth_type) { - conf->ap_auth_type = new->ap_auth_type; - } - if (new->ap_auth_name) { - conf->ap_auth_name = new->ap_auth_name; - } - if (new->ap_requires) { - conf->ap_requires = new->ap_requires; - } - - if (new->response_code_strings) { - if (conf->response_code_strings == NULL) { - conf->response_code_strings = apr_palloc(a, - sizeof(*conf->response_code_strings) * RESPONSE_CODES); - memcpy(conf->response_code_strings, new->response_code_strings, - sizeof(*conf->response_code_strings) * RESPONSE_CODES); - } - else { - for (i = 0; i < RESPONSE_CODES; ++i) { - if (new->response_code_strings[i] != NULL) { - conf->response_code_strings[i] - = new->response_code_strings[i]; - } - } - } - } - if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) { - conf->hostname_lookups = new->hostname_lookups; - } - if ((new->do_rfc1413 & 2) == 0) { - conf->do_rfc1413 = new->do_rfc1413; - } - if ((new->content_md5 & 2) == 0) { - conf->content_md5 = new->content_md5; - } - if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) { - 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; - } - - if (new->limit_xml_body != AP_LIMIT_UNSET) - conf->limit_xml_body = new->limit_xml_body; - else - conf->limit_xml_body = base->limit_xml_body; - - conf->sec = apr_array_append(a, base->sec, new->sec); - - if (new->satisfy != SATISFY_NOSPEC) { - conf->satisfy = new->satisfy; - } - -#ifdef WIN32 - if (new->script_interpreter_source != INTERPRETER_SOURCE_UNSET) { - conf->script_interpreter_source = new->script_interpreter_source; - } -#endif - - if (new->server_signature != srv_sig_unset) { - conf->server_signature = new->server_signature; - } - - if (new->add_default_charset != ADD_DEFAULT_CHARSET_UNSET) { - conf->add_default_charset = new->add_default_charset; - if (new->add_default_charset_name) { - conf->add_default_charset_name = new->add_default_charset_name; - } - } - conf->output_filters = apr_array_append(a, base->output_filters, - new->output_filters); - conf->input_filters = apr_array_append(a, base->input_filters, - new->input_filters); - - return (void*)conf; -} - -static void *create_core_server_config(apr_pool_t *a, server_rec *s) -{ - core_server_config *conf; - int is_virtual = s->is_virtual; - - conf = (core_server_config *)apr_pcalloc(a, sizeof(core_server_config)); -#ifdef GPROF - conf->gprof_dir = NULL; -#endif - conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME; - conf->ap_document_root = is_virtual ? NULL : DOCUMENT_LOCATION; - conf->sec = apr_array_make(a, 40, sizeof(ap_conf_vector_t *)); - conf->sec_url = apr_array_make(a, 40, sizeof(ap_conf_vector_t *)); - - return (void *)conf; -} - -static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) -{ - core_server_config *base = (core_server_config *)basev; - core_server_config *virt = (core_server_config *)virtv; - core_server_config *conf; - - conf = (core_server_config *)apr_pcalloc(p, sizeof(core_server_config)); - *conf = *virt; - if (!conf->access_name) { - conf->access_name = base->access_name; - } - if (!conf->ap_document_root) { - conf->ap_document_root = base->ap_document_root; - } - conf->sec = apr_array_append(p, base->sec, virt->sec); - conf->sec_url = apr_array_append(p, base->sec_url, virt->sec_url); - - return conf; -} - -/* Add per-directory configuration entry (for <directory> section); - * these are part of the core server config. - */ - -AP_CORE_DECLARE(void) ap_add_per_dir_conf(server_rec *s, void *dir_config) -{ - core_server_config *sconf = ap_get_module_config(s->module_config, - &core_module); - void **new_space = (void **)apr_array_push(sconf->sec); - - *new_space = dir_config; -} - -AP_CORE_DECLARE(void) ap_add_per_url_conf(server_rec *s, void *url_config) -{ - core_server_config *sconf = ap_get_module_config(s->module_config, - &core_module); - void **new_space = (void **)apr_array_push(sconf->sec_url); - - *new_space = url_config; -} - -AP_CORE_DECLARE(void) ap_add_file_conf(core_dir_config *conf, void *url_config) -{ - void **new_space = (void **)apr_array_push(conf->sec); - - *new_space = url_config; -} - -/* core_reorder_directories reorders the directory sections such that the - * 1-component sections come first, then the 2-component, and so on, finally - * followed by the "special" sections. A section is "special" if it's a regex, - * or if it doesn't start with / -- consider proxy: matching. All movements - * are in-order to preserve the ordering of the sections from the config files. - * See directory_walk(). - */ - -#if defined(HAVE_DRIVE_LETTERS) -#define IS_SPECIAL(entry_core) \ - ((entry_core)->r != NULL \ - || ((entry_core)->d[0] != '/' && (entry_core)->d[1] != ':')) -#elif defined(NETWARE) -/* XXX: Fairly certain this is correct... '/' must prefix the path - * or else in the case xyz:/ or abc/xyz:/, '/' must follow the ':'. - * If there is no leading '/' or embedded ':/', then we are special. - */ -#define IS_SPECIAL(entry_core) \ - ((entry_core)->r != NULL \ - || ((entry_core)->d[0] != '/' \ - && strchr((entry_core)->d, ':') \ - && *(strchr((entry_core)->d, ':') + 1) != '/')) -#else -#define IS_SPECIAL(entry_core) \ - ((entry_core)->r != NULL || (entry_core)->d[0] != '/') -#endif - -/* We need to do a stable sort, qsort isn't stable. So to make it stable - * we'll be maintaining the original index into the list, and using it - * as the minor key during sorting. The major key is the number of - * components (where a "special" section has infinite components). - */ -struct reorder_sort_rec { - ap_conf_vector_t *elt; - int orig_index; -}; - -static int reorder_sorter(const void *va, const void *vb) -{ - const struct reorder_sort_rec *a = va; - const struct reorder_sort_rec *b = vb; - core_dir_config *core_a; - core_dir_config *core_b; - - core_a = ap_get_module_config(a->elt, &core_module); - core_b = ap_get_module_config(b->elt, &core_module); - if (IS_SPECIAL(core_a)) { - if (!IS_SPECIAL(core_b)) { - return 1; - } - } - else if (IS_SPECIAL(core_b)) { - return -1; - } - else { - /* we know they're both not special */ - if (core_a->d_components < core_b->d_components) { - return -1; - } - else if (core_a->d_components > core_b->d_components) { - return 1; - } - } - /* Either they're both special, or they're both not special and have the - * same number of components. In any event, we now have to compare - * the minor key. */ - return a->orig_index - b->orig_index; -} - -void ap_core_reorder_directories(apr_pool_t *p, server_rec *s) -{ - core_server_config *sconf; - apr_array_header_t *sec; - struct reorder_sort_rec *sortbin; - int nelts; - ap_conf_vector_t **elts; - int i; - apr_pool_t *tmp; - - sconf = ap_get_module_config(s->module_config, &core_module); - sec = sconf->sec; - nelts = sec->nelts; - elts = (ap_conf_vector_t **)sec->elts; - - /* we have to allocate tmp space to do a stable sort */ - apr_pool_create(&tmp, p); - sortbin = apr_palloc(tmp, sec->nelts * sizeof(*sortbin)); - for (i = 0; i < nelts; ++i) { - sortbin[i].orig_index = i; - sortbin[i].elt = elts[i]; - } - - qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter); - - /* and now copy back to the original array */ - for (i = 0; i < nelts; ++i) { - elts[i] = sortbin[i].elt; - } - - apr_pool_destroy(tmp); -} - -/***************************************************************** - * - * There are some elements of the core config structures in which - * other modules have a legitimate interest (this is ugly, but necessary - * to preserve NCSA back-compatibility). So, we have a bunch of accessors - * here... - */ - -AP_DECLARE(int) ap_allow_options(request_rec *r) -{ - core_dir_config *conf = - (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); - - return conf->opts; -} - -AP_DECLARE(int) ap_allow_overrides(request_rec *r) -{ - core_dir_config *conf; - conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - - return conf->override; -} - -AP_DECLARE(const char *) ap_auth_type(request_rec *r) -{ - core_dir_config *conf; - - conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - return conf->ap_auth_type; -} - -AP_DECLARE(const char *) ap_auth_name(request_rec *r) -{ - core_dir_config *conf; - - conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - return conf->ap_auth_name; -} - -AP_DECLARE(const char *) ap_default_type(request_rec *r) -{ - core_dir_config *conf; - - conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - return conf->ap_default_type - ? conf->ap_default_type - : DEFAULT_CONTENT_TYPE; -} - -AP_DECLARE(const char *) ap_document_root(request_rec *r) /* Don't use this! */ -{ - core_server_config *conf; - - conf = (core_server_config *)ap_get_module_config(r->server->module_config, - &core_module); - return conf->ap_document_root; -} - -AP_DECLARE(const apr_array_header_t *) ap_requires(request_rec *r) -{ - core_dir_config *conf; - - conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - return conf->ap_requires; -} - -AP_DECLARE(int) ap_satisfies(request_rec *r) -{ - core_dir_config *conf; - - conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - - return conf->satisfy; -} - -/* Should probably just get rid of this... the only code that cares is - * part of the core anyway (and in fact, it isn't publicised to other - * modules). - */ - -char *ap_response_code_string(request_rec *r, int error_index) -{ - core_dir_config *conf; - - conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - - if (conf->response_code_strings == NULL) { - return NULL; - } - return conf->response_code_strings[error_index]; -} - - -/* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */ -static APR_INLINE void do_double_reverse (conn_rec *conn) -{ - apr_sockaddr_t *sa; - apr_status_t rv; - - if (conn->double_reverse) { - /* already done */ - return; - } - if (conn->remote_host == NULL || conn->remote_host[0] == '\0') { - /* single reverse failed, so don't bother */ - conn->double_reverse = -1; - return; - } - rv = apr_sockaddr_info_get(&sa, conn->remote_host, APR_UNSPEC, 0, 0, conn->pool); - if (rv == APR_SUCCESS) { - while (sa) { - if (sa->ipaddr_len == conn->remote_addr->ipaddr_len && - !memcmp(sa->ipaddr_ptr, conn->remote_addr->ipaddr_ptr, - sa->ipaddr_len)) { - conn->double_reverse = 1; - return; - } -#if APR_HAVE_IPV6 - /* match IPv4-mapped IPv6 addresses with IPv4 A record */ - if (conn->remote_addr->sa.sin.sin_family == APR_INET6 && - sa->sa.sin.sin_family == APR_INET && - IN6_IS_ADDR_V4MAPPED((struct in6_addr *)conn->remote_addr->ipaddr_ptr) && - !memcmp(&((struct in6_addr *)conn->remote_addr->ipaddr_ptr)->s6_addr[12], - sa->ipaddr_ptr, - sizeof (((struct in_addr *)0)->s_addr))) { - conn->double_reverse = 1; - return; - } -#endif - sa = sa->next; - } - } - conn->double_reverse = -1; -} - -AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, - int type, int *str_is_ip) -{ - int hostname_lookups; - - if (str_is_ip) { /* if caller wants to know */ - *str_is_ip = 0; - } - - /* If we haven't checked the host name, and we want to */ - if (dir_config) { - hostname_lookups = - ((core_dir_config *)ap_get_module_config(dir_config, &core_module)) - ->hostname_lookups; - if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) { - hostname_lookups = HOSTNAME_LOOKUP_OFF; - } - } - else { - /* the default */ - hostname_lookups = HOSTNAME_LOOKUP_OFF; - } - - if (type != REMOTE_NOLOOKUP - && conn->remote_host == NULL - && (type == REMOTE_DOUBLE_REV - || hostname_lookups != HOSTNAME_LOOKUP_OFF)) { - apr_sockaddr_t *remote_addr; - - apr_socket_addr_get(&remote_addr, APR_REMOTE, conn->client_socket); - if (apr_getnameinfo(&conn->remote_host, remote_addr, 0) == APR_SUCCESS) { - ap_str_tolower(conn->remote_host); - - if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) { - do_double_reverse(conn); - if (conn->double_reverse != 1) { - conn->remote_host = NULL; - } - } - } - /* if failed, set it to the NULL string to indicate error */ - if (conn->remote_host == NULL) { - conn->remote_host = ""; - } - } - if (type == REMOTE_DOUBLE_REV) { - do_double_reverse(conn); - if (conn->double_reverse == -1) { - return NULL; - } - } - -/* - * Return the desired information; either the remote DNS name, if found, - * or either NULL (if the hostname was requested) or the IP address - * (if any identifier was requested). - */ - if (conn->remote_host != NULL && conn->remote_host[0] != '\0') { - return conn->remote_host; - } - else { - if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) { - return NULL; - } - else { - if (str_is_ip) { /* if caller wants to know */ - *str_is_ip = 1; - } - return conn->remote_ip; - } - } -} - -AP_DECLARE(const char *) ap_get_remote_logname(request_rec *r) -{ - core_dir_config *dir_conf; - - if (r->connection->remote_logname != NULL) { - return r->connection->remote_logname; - } - -/* If we haven't checked the identity, and we want to */ - dir_conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - - if (dir_conf->do_rfc1413 & 1) { - return ap_rfc1413(r->connection, r->server); - } - else { - return NULL; - } -} - -/* There are two options regarding what the "name" of a server is. The - * "canonical" name as defined by ServerName and Port, or the "client's - * name" as supplied by a possible Host: header or full URI. We never - * trust the port passed in the client's headers, we always use the - * port of the actual socket. - * - * The DNS option to UseCanonicalName causes this routine to do a - * reverse lookup on the local IP address of the connection and use - * that for the ServerName. This makes its value more reliable while - * at the same time allowing Demon's magic virtual hosting to work. - * The assumption is that DNS lookups are sufficiently quick... - * -- fanf 1998-10-03 - */ -AP_DECLARE(const char *) ap_get_server_name(request_rec *r) -{ - conn_rec *conn = r->connection; - core_dir_config *d; - - d = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - - if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) { - return r->hostname ? r->hostname : r->server->server_hostname; - } - if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) { - if (conn->local_host == NULL) { - apr_sockaddr_t *local_addr; - - apr_socket_addr_get(&local_addr, APR_LOCAL, conn->client_socket); - if (apr_getnameinfo(&conn->local_host, local_addr, 0) != APR_SUCCESS) - conn->local_host = apr_pstrdup(conn->pool, r->server->server_hostname); - else { - ap_str_tolower(conn->local_host); - } - } - return conn->local_host; - } - /* default */ - return r->server->server_hostname; -} - -AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r) -{ - apr_port_t port; - core_dir_config *d = - (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); - - port = r->server->port ? r->server->port : ap_default_port(r); - - if (d->use_canonical_name == USE_CANONICAL_NAME_OFF - || d->use_canonical_name == USE_CANONICAL_NAME_DNS) { - if (r->hostname) { - apr_sockaddr_t *localsa; - - apr_socket_addr_get(&localsa, APR_LOCAL, r->connection->client_socket); - apr_sockaddr_port_get(&port, localsa); - } - } - /* default */ - return port; -} - -AP_DECLARE(char *) ap_construct_url(apr_pool_t *p, const char *uri, - request_rec *r) -{ - unsigned port = ap_get_server_port(r); - const char *host = ap_get_server_name(r); - - if (ap_is_default_port(port, r)) { - return apr_pstrcat(p, ap_http_method(r), "://", host, uri, NULL); - } - return apr_psprintf(p, "%s://%s:%u%s", ap_http_method(r), host, port, uri); -} - -AP_DECLARE(unsigned long) ap_get_limit_req_body(const request_rec *r) -{ - core_dir_config *d = - (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); - - return d->limit_req_body; -} - -#ifdef WIN32 -static apr_status_t get_win32_registry_default_value(apr_pool_t *p, HKEY hkey, - char* relativepath, - char **value) -{ - HKEY hkeyOpen; - DWORD type; - DWORD size = 0; - DWORD result = RegOpenKeyEx(hkey, relativepath, 0, - KEY_QUERY_VALUE, &hkeyOpen); - - if (result != ERROR_SUCCESS) - return APR_FROM_OS_ERROR(result); - - /* Read to NULL buffer to determine value size */ - result = RegQueryValueEx(hkeyOpen, "", 0, &type, NULL, &size); - - if (result == ERROR_SUCCESS) { - if ((size < 2) || (type != REG_SZ && type != REG_EXPAND_SZ)) { - result = ERROR_INVALID_PARAMETER; - } - else { - *value = apr_palloc(p, size); - /* Read value based on size query above */ - result = RegQueryValueEx(hkeyOpen, "", 0, &type, *value, &size); - } - } - - /* TODO: This might look fine, but we need to provide some warning - * somewhere that some environment variables may -not- be translated, - * seeing as we may have chopped the environment table down somewhat. - */ - if ((result == ERROR_SUCCESS) && (type == REG_EXPAND_SZ)) - { - char *tmp = *value; - size = ExpandEnvironmentStrings(tmp, *value, 0); - if (size) { - *value = apr_palloc(p, size); - size = ExpandEnvironmentStrings(tmp, *value, size); - } - } - - RegCloseKey(hkeyOpen); - return APR_FROM_OS_ERROR(result); -} - -static char* get_interpreter_from_win32_registry(apr_pool_t *p, const char* ext, - char** arguments, int strict) -{ - char execcgi_path[] = "SHELL\\EXECCGI\\COMMAND"; - char execopen_path[] = "SHELL\\OPEN\\COMMAND"; - char typeName[MAX_PATH]; - int cmdOfName = FALSE; - HKEY hkeyName; - HKEY hkeyType; - DWORD type; - int size; - int result; - char *buffer; - char *s; - - if (!ext) - return NULL; - /* - * Future optimization: - * When the registry is successfully searched, store the strings for - * interpreter and arguments in an ext hash to speed up subsequent look-ups - */ - - /* Open the key associated with the script filetype extension */ - result = RegOpenKeyEx(HKEY_CLASSES_ROOT, ext, 0, KEY_QUERY_VALUE, - &hkeyType); - - if (result != ERROR_SUCCESS) - return NULL; - - /* Retrieve the name of the script filetype extension */ - size = sizeof(typeName); - result = RegQueryValueEx(hkeyType, "", NULL, &type, typeName, &size); - - if (result == ERROR_SUCCESS && type == REG_SZ && typeName[0]) { - /* Open the key associated with the script filetype extension */ - result = RegOpenKeyEx(HKEY_CLASSES_ROOT, typeName, 0, - KEY_QUERY_VALUE, &hkeyName); - - if (result == ERROR_SUCCESS) - cmdOfName = TRUE; - } - - /* Open the key for the script command path by: - * - * 1) the 'named' filetype key for ExecCGI/Command - * 2) the extension's type key for ExecCGI/Command - * - * and if the strict arg is false, then continue trying: - * - * 3) the 'named' filetype key for Open/Command - * 4) the extension's type key for Open/Command - */ - - if (cmdOfName) { - result = get_win32_registry_default_value(p, hkeyName, - execcgi_path, &buffer); - } - - if (!cmdOfName || (result != ERROR_SUCCESS)) { - result = get_win32_registry_default_value(p, hkeyType, - execcgi_path, &buffer); - } - - if (!strict && cmdOfName && (result != ERROR_SUCCESS)) { - result = get_win32_registry_default_value(p, hkeyName, - execopen_path, &buffer); - } - - if (!strict && (result != ERROR_SUCCESS)) { - result = get_win32_registry_default_value(p, hkeyType, - execopen_path, &buffer); - } - - if (cmdOfName) - RegCloseKey(hkeyName); - - RegCloseKey(hkeyType); - - if (result != ERROR_SUCCESS) - return NULL; - - /* - * The canonical way shell command entries are entered in the Win32 - * registry is as follows: - * shell [options] "%1" [args] - * where - * shell - full path name to interpreter or shell to run. - * E.g., c:\usr\local\ntreskit\perl\bin\perl.exe - * options - optional switches - * E.g., \C - * "%1" - Place holder for file to run the shell against. - * Typically quoted. - * options - additional arguments - * E.g., /silent - * - * If we find a %1 or a quoted %1, lop off the remainder to arguments. - */ - if (buffer && *buffer) { - if ((s = strstr(buffer, "\"%1"))) - { - *s = '\0'; - *arguments = s + 4; - } - else if ((s = strstr(buffer, "%1"))) - { - *s = '\0'; - *arguments = buffer + 2; - } - else - *arguments = strchr(buffer, '\0'); - while (**arguments && isspace(**arguments)) - ++*arguments; - } - - return buffer; -} - -AP_DECLARE (file_type_e) ap_get_win32_interpreter(const request_rec *r, - char** interpreter, - char** arguments) -{ - HANDLE hFile; - DWORD nBytesRead; - BOOLEAN bResult; - char buffer[1024]; - core_dir_config *d; - int i; - file_type_e fileType = eFileTypeUNKNOWN; - char *ext = NULL; - char *exename = NULL; - - d = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - - /* Find the file extension */ - exename = strrchr(r->filename, '/'); - if (!exename) { - exename = strrchr(r->filename, '\\'); - } - if (!exename) { - exename = r->filename; - } - else { - exename++; - } - ext = strrchr(exename, '.'); - - if (ext && (!strcasecmp(ext,".bat") || !strcasecmp(ext,".cmd"))) - { - char *comspec = getenv("COMSPEC"); - if (comspec) { - *interpreter = apr_pstrcat(r->pool, "\"", comspec, "\" /c ", NULL); - return eFileTypeSCRIPT; - } - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r->server, - "Failed to start a '%s' file as a script." APR_EOL_STR - "\tCOMSPEC variable is missing from the environment.", ext); - return eFileTypeUNKNOWN; - } - - /* If the file has an extension and it is not .com and not .exe and - * we've been instructed to search the registry, then do it! - */ - if (ext && strcasecmp(ext,".exe") && strcasecmp(ext,".com") && - (d->script_interpreter_source == INTERPRETER_SOURCE_REGISTRY || - d->script_interpreter_source == INTERPRETER_SOURCE_REGISTRY_STRICT)) { - /* Check the registry */ - int strict = (d->script_interpreter_source - == INTERPRETER_SOURCE_REGISTRY_STRICT); - *interpreter = get_interpreter_from_win32_registry(r->pool, ext, - arguments, strict); - if (*interpreter) - return eFileTypeSCRIPT; - else if (d->script_interpreter_source == INTERPRETER_SOURCE_REGISTRY_STRICT) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r->server, - "ScriptInterpreterSource config directive set to \"registry-strict\"." APR_EOL_STR - "\tInterpreter not found for files of type '%s'.", ext); - return eFileTypeUNKNOWN; - } - else - { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r->server, - "ScriptInterpreterSource config directive set to \"registry\"." APR_EOL_STR - "\tInterpreter not found for files of type '%s', " - "trying \"script\" method...", ext); - } - } - - /* Need to peek into the file figure out what it really is... */ - /* This is wrong for Unicode FS ... should move to APR */ - hFile = CreateFile(r->filename, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { - return eFileTypeUNKNOWN; - } - bResult = ReadFile(hFile, (void*) &buffer, sizeof(buffer) - 1, - &nBytesRead, NULL); - if (!bResult || (nBytesRead == 0)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, GetLastError(), r, - "ReadFile(%s) failed", r->filename); - CloseHandle(hFile); - return eFileTypeUNKNOWN; - } - CloseHandle(hFile); - buffer[nBytesRead] = '\0'; - - /* Script or executable, that is the question... */ - if ((buffer[0] == '#') && (buffer[1] == '!')) { - /* Assuming file is a script since it starts with a shebang */ - fileType = eFileTypeSCRIPT; - for (i = 2; i < sizeof(buffer); i++) { - if ((buffer[i] == '\r') - || (buffer[i] == '\n')) { - break; - } - } - buffer[i] = '\0'; - for (i = 2; buffer[i] == ' ' ; ++i) - ; - *interpreter = apr_pstrdup(r->pool, buffer + i ); - } - else { - /* Not a script, is it an executable? */ - IMAGE_DOS_HEADER *hdr = (IMAGE_DOS_HEADER*)buffer; - if ((nBytesRead >= sizeof(IMAGE_DOS_HEADER)) && (hdr->e_magic == IMAGE_DOS_SIGNATURE)) { - if (hdr->e_lfarlc < 0x40) - fileType = eFileTypeEXE16; - else - fileType = eFileTypeEXE32; - } - else - fileType = eFileTypeUNKNOWN; - } - - return fileType; -} -#endif - -/***************************************************************** - * - * Commands... this module handles almost all of the NCSA httpd.conf - * commands, but most of the old srm.conf is in the the modules. - */ - - -/* returns a parent if it matches the given directive */ -static const ap_directive_t * find_parent(const ap_directive_t *dirp, - const char *what) -{ - while (dirp->parent != NULL) { - dirp = dirp->parent; - /* ### it would be nice to have atom-ized directives */ - if (strcasecmp(dirp->directive, what) == 0) - return dirp; - } - return NULL; -} - -AP_DECLARE(const char *) ap_check_cmd_context(cmd_parms *cmd, - unsigned forbidden) -{ - const char *gt = (cmd->cmd->name[0] == '<' - && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>') - ? ">" : ""; - const ap_directive_t *found; - - if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, gt, - " cannot occur within <VirtualHost> section", NULL); - } - - if ((forbidden & NOT_IN_LIMIT) && cmd->limited != -1) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, gt, - " cannot occur within <Limit> section", NULL); - } - - if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE - && cmd->path != NULL) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, gt, - " cannot occur within <Directory/Location/Files> " - "section", NULL); - } - - if (((forbidden & NOT_IN_DIRECTORY) - && ((found = find_parent(cmd->directive, "<Directory")) - || (found = find_parent(cmd->directive, "<DirectoryMatch")))) - || ((forbidden & NOT_IN_LOCATION) - && ((found = find_parent(cmd->directive, "<Location")) - || (found = find_parent(cmd->directive, "<LocationMatch")))) - || ((forbidden & NOT_IN_FILES) - && ((found = find_parent(cmd->directive, "<Files")) - || (found = find_parent(cmd->directive, "<FilesMatch"))))) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, gt, - " cannot occur within ", found->directive, - "> section", NULL); - } - - return NULL; -} - -static const char *set_access_name(cmd_parms *cmd, void *dummy, - const char *arg) -{ - void *sconf = cmd->server->module_config; - core_server_config *conf = ap_get_module_config(sconf, &core_module); - - const char *err = ap_check_cmd_context(cmd, - NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - conf->access_name = apr_pstrdup(cmd->pool, arg); - return NULL; -} - -#ifdef GPROF -static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, const char *arg) -{ - void *sconf = cmd->server->module_config; - core_server_config *conf = ap_get_module_config(sconf, &core_module); - - const char *err = ap_check_cmd_context(cmd, - NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - conf->gprof_dir = apr_pstrdup(cmd->pool, arg); - return NULL; -} -#endif /*GPROF*/ - -static const char *set_add_default_charset(cmd_parms *cmd, - void *d_, const char *arg) -{ - core_dir_config *d=d_; - - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - if (!strcasecmp(arg, "Off")) { - d->add_default_charset = ADD_DEFAULT_CHARSET_OFF; - } - else if (!strcasecmp(arg, "On")) { - d->add_default_charset = ADD_DEFAULT_CHARSET_ON; - d->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME; - } - else { - d->add_default_charset = ADD_DEFAULT_CHARSET_ON; - d->add_default_charset_name = arg; - } - return NULL; -} - -static const char *set_document_root(cmd_parms *cmd, void *dummy, - const char *arg) -{ - void *sconf = cmd->server->module_config; - core_server_config *conf = ap_get_module_config(sconf, &core_module); - - const char *err = ap_check_cmd_context(cmd, - NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - arg = ap_os_canonical_filename(cmd->pool, arg); - if (/* TODO: ap_configtestonly && ap_docrootcheck && */ !ap_is_directory(cmd->pool, arg)) { - if (cmd->server->is_virtual) { - ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, cmd->pool, - "Warning: DocumentRoot [%s] does not exist", - arg); - } - else { - return "DocumentRoot must be a directory"; - } - } - - conf->ap_document_root = arg; - return NULL; -} - -AP_DECLARE(void) ap_custom_response(request_rec *r, int status, char *string) -{ - core_dir_config *conf = - ap_get_module_config(r->per_dir_config, &core_module); - int idx; - - if(conf->response_code_strings == NULL) { - conf->response_code_strings = - apr_pcalloc(r->pool, - sizeof(*conf->response_code_strings) * - RESPONSE_CODES); - } - - idx = ap_index_of_response(status); - - conf->response_code_strings[idx] = - ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ? - apr_pstrdup(r->pool, string) : apr_pstrcat(r->pool, "\"", string, NULL); -} - -static const char *set_error_document(cmd_parms *cmd, void *conf_, - const char *errno_str, const char *msg) -{ - core_dir_config *conf=conf_; - int error_number, index_number, idx500; - enum { MSG, LOCAL_PATH, REMOTE_PATH } what = MSG; - - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - /* 1st parameter should be a 3 digit number, which we recognize; - * convert it into an array index - */ - error_number = atoi(errno_str); - idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR); - - if (error_number == HTTP_INTERNAL_SERVER_ERROR) { - index_number = idx500; - } - else if ((index_number = ap_index_of_response(error_number)) == idx500) { - return apr_pstrcat(cmd->pool, "Unsupported HTTP response code ", - errno_str, NULL); - } - - /* Heuristic to determine second argument. */ - if (ap_strchr_c(msg,' ')) - what = MSG; - else if (msg[0] == '/') - what = LOCAL_PATH; - else if (ap_is_url(msg)) - what = REMOTE_PATH; - else - what = MSG; - - /* The entry should be ignored if it is a full URL for a 401 error */ - - if (error_number == 401 && what == REMOTE_PATH) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, cmd->server, - "cannot use a full URL in a 401 ErrorDocument " - "directive --- ignoring!"); - } - else { /* Store it... */ - if (conf->response_code_strings == NULL) { - conf->response_code_strings = - apr_pcalloc(cmd->pool, - sizeof(*conf->response_code_strings) * RESPONSE_CODES); - } - /* hack. Prefix a " if it is a msg; as that is what - * http_protocol.c relies on to distinguish between - * a msg and a (local) path. - */ - conf->response_code_strings[index_number] = (what == MSG) ? - apr_pstrcat(cmd->pool, "\"",msg,NULL) : - apr_pstrdup(cmd->pool, msg); - } - - return NULL; -} - -static const char *set_override(cmd_parms *cmd, void *d_, const char *l) -{ - core_dir_config *d=d_; - char *w; - - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - d->override = OR_NONE; - while (l[0]) { - w = ap_getword_conf(cmd->pool, &l); - if (!strcasecmp(w, "Limit")) { - d->override |= OR_LIMIT; - } - else if (!strcasecmp(w, "Options")) { - d->override |= OR_OPTIONS; - } - else if (!strcasecmp(w, "FileInfo")) { - d->override |= OR_FILEINFO; - } - else if (!strcasecmp(w, "AuthConfig")) { - d->override |= OR_AUTHCFG; - } - else if (!strcasecmp(w, "Indexes")) { - d->override |= OR_INDEXES; - } - else if (!strcasecmp(w, "None")) { - d->override = OR_NONE; - } - else if (!strcasecmp(w, "All")) { - d->override = OR_ALL; - } - else { - return apr_pstrcat(cmd->pool, "Illegal override option ", w, NULL); - } - d->override &= ~OR_UNSET; - } - - return NULL; -} - -static const char *set_options(cmd_parms *cmd, void *d_, const char *l) -{ - core_dir_config *d=d_; - allow_options_t opt; - int first = 1; - char action; - - while (l[0]) { - char *w = ap_getword_conf(cmd->pool, &l); - action = '\0'; - - if (*w == '+' || *w == '-') { - action = *(w++); - } - else if (first) { - d->opts = OPT_NONE; - first = 0; - } - - if (!strcasecmp(w, "Indexes")) { - opt = OPT_INDEXES; - } - else if (!strcasecmp(w, "Includes")) { - opt = OPT_INCLUDES; - } - else if (!strcasecmp(w, "IncludesNOEXEC")) { - opt = (OPT_INCLUDES | OPT_INCNOEXEC); - } - else if (!strcasecmp(w, "FollowSymLinks")) { - opt = OPT_SYM_LINKS; - } - else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) { - opt = OPT_SYM_OWNER; - } - else if (!strcasecmp(w, "execCGI")) { - opt = OPT_EXECCGI; - } - else if (!strcasecmp(w, "MultiViews")) { - opt = OPT_MULTI; - } - else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */ - opt = OPT_MULTI|OPT_EXECCGI; - } - else if (!strcasecmp(w, "None")) { - opt = OPT_NONE; - } - else if (!strcasecmp(w, "All")) { - opt = OPT_ALL; - } - else { - return apr_pstrcat(cmd->pool, "Illegal option ", w, NULL); - } - - /* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */ - if (action == '-') { - d->opts_remove |= opt; - d->opts_add &= ~opt; - d->opts &= ~opt; - } - else if (action == '+') { - d->opts_add |= opt; - d->opts_remove &= ~opt; - d->opts |= opt; - } - else { - d->opts |= opt; - } - } - - return NULL; -} - -static const char *satisfy(cmd_parms *cmd, void *c_, const char *arg) -{ - core_dir_config *c=c_; - - if (!strcasecmp(arg, "all")) { - c->satisfy = SATISFY_ALL; - } - else if (!strcasecmp(arg, "any")) { - c->satisfy = SATISFY_ANY; - } - else { - return "Satisfy either 'any' or 'all'."; - } - return NULL; -} - -static const char *require(cmd_parms *cmd, void *c_, const char *arg) -{ - require_line *r; - core_dir_config *c=c_; - - if (!c->ap_requires) { - c->ap_requires = apr_array_make(cmd->pool, 2, sizeof(require_line)); - } - r = (require_line *)apr_array_push(c->ap_requires); - r->requirement = apr_pstrdup(cmd->pool, arg); - r->method_mask = cmd->limited; - return NULL; -} - -AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy, - const char *arg) { - const char *limited_methods = ap_getword(cmd->pool, &arg, '>'); - void *tog = cmd->cmd->cmd_data; - int limited = 0; - const char *errmsg; - - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - while (limited_methods[0]) { - char *method = ap_getword_conf(cmd->pool, &limited_methods); - int methnum = ap_method_number_of(method); - - if (methnum == M_TRACE && !tog) { - return "TRACE cannot be controlled by <Limit>"; - } - else if (methnum == M_INVALID) { - char **xmethod; - register int i, j, k; - - /* - * Deal with <Limit> by adding the method to the list. - */ - if (!tog) { - if (cmd->limited_xmethods == NULL) { - cmd->limited_xmethods = apr_array_make(cmd->pool, 2, - sizeof(char *)); - } - xmethod = (char **) apr_array_push(cmd->limited_xmethods); - *xmethod = apr_pstrdup(cmd->pool, method); - } - /* - * <LimitExcept>, so remove any/all occurrences of the method - * in the extension array. - */ - else if ((cmd->limited_xmethods != NULL) - && (cmd->limited_xmethods->nelts != 0)) { - xmethod = (char **) cmd->limited_xmethods->elts; - for (i = 0; i < cmd->limited_xmethods->nelts; ) { - if (strcmp(xmethod[i], method) == 0) { - for (j = i, k = i + 1; - k < cmd->limited_xmethods->nelts; - ++j, ++k) { - xmethod[j] = xmethod[k]; - } - cmd->limited_xmethods->nelts--; - } - } - } - } - limited |= (1 << methnum); - } - - /* Killing two features with one function, - * if (tog == NULL) <Limit>, else <LimitExcept> - */ - cmd->limited = tog ? ~limited : limited; - - errmsg = ap_walk_config(cmd->directive->first_child, cmd, cmd->context); - - cmd->limited = -1; - - return errmsg; -} - -/* We use this in <DirectoryMatch> and <FilesMatch>, to ensure that - * people don't get bitten by wrong-cased regex matches - */ - -#ifdef WIN32 -#define USE_ICASE REG_ICASE -#else -#define USE_ICASE 0 -#endif - -/* - * Report a missing-'>' syntax error. - */ -static char *unclosed_directive(cmd_parms *cmd) -{ - return apr_pstrcat(cmd->pool, cmd->cmd->name, - "> directive missing closing '>'", NULL); -} - -static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg) -{ - const char *errmsg; - const char *endp = ap_strrchr_c(arg, '>'); - int old_overrides = cmd->override; - char *old_path = cmd->path; - core_dir_config *conf; - ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool); - regex_t *r = NULL; - const command_rec *thiscmd = cmd->cmd; - - const char *err = ap_check_cmd_context(cmd, - NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - if (endp == NULL) { - return unclosed_directive(cmd); - } - - arg=apr_pstrndup(cmd->pool, arg, endp-arg); - - cmd->path = ap_getword_conf(cmd->pool, &arg); - cmd->override = OR_ALL|ACCESS_CONF; - - if (thiscmd->cmd_data) { /* <DirectoryMatch> */ - r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE); - } - else if (!strcmp(cmd->path, "~")) { - cmd->path = ap_getword_conf(cmd->pool, &arg); - r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE); - } -#if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE) - else if (strcmp(cmd->path, "/") == 0) { - /* Treat 'default' path / as an inalienable root */ - cmd->path = apr_pstrdup(cmd->pool, cmd->path); - } -#endif -#if defined(HAVE_UNC_PATHS) - else if (strcmp(cmd->path, "//") == 0) { - /* Treat UNC path // as an inalienable root */ - cmd->path = apr_pstrdup(cmd->pool, cmd->path); - } -#endif - else { - /* Ensure that the pathname is canonical */ - cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path); - } - - /* initialize our config and fetch it */ - conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path, - &core_module, cmd->pool); - - errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf); - if (errmsg != NULL) - return errmsg; - - conf->r = r; - - ap_add_per_dir_conf(cmd->server, new_dir_conf); - - if (*arg != '\0') { - return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name, - "> arguments not (yet) supported.", NULL); - } - - cmd->path = old_path; - cmd->override = old_overrides; - - return NULL; -} - -static const char *urlsection(cmd_parms *cmd, void *mconfig, const char *arg) -{ - const char *errmsg; - const char *endp = ap_strrchr_c(arg, '>'); - int old_overrides = cmd->override; - char *old_path = cmd->path; - core_dir_config *conf; - regex_t *r = NULL; - const command_rec *thiscmd = cmd->cmd; - ap_conf_vector_t *new_url_conf = ap_create_per_dir_config(cmd->pool); - const char *err = ap_check_cmd_context(cmd, - NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - if (endp == NULL) { - return unclosed_directive(cmd); - } - - arg=apr_pstrndup(cmd->pool, arg, endp-arg); - - cmd->path = ap_getword_conf(cmd->pool, &arg); - cmd->override = OR_ALL|ACCESS_CONF; - - if (thiscmd->cmd_data) { /* <LocationMatch> */ - r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED); - } - else if (!strcmp(cmd->path, "~")) { - cmd->path = ap_getword_conf(cmd->pool, &arg); - r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED); - } - - /* initialize our config and fetch it */ - conf = ap_set_config_vectors(cmd->server, new_url_conf, cmd->path, - &core_module, cmd->pool); - - errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_url_conf); - if (errmsg != NULL) - return errmsg; - - conf->d = apr_pstrdup(cmd->pool, cmd->path); /* No mangling, please */ - conf->d_is_fnmatch = apr_is_fnmatch(conf->d) != 0; - conf->r = r; - - ap_add_per_url_conf(cmd->server, new_url_conf); - - if (*arg != '\0') { - return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name, - "> arguments not (yet) supported.", NULL); - } - - cmd->path = old_path; - cmd->override = old_overrides; - - return NULL; -} - -static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg) -{ - const char *errmsg; - const char *endp = ap_strrchr_c(arg, '>'); - int old_overrides = cmd->override; - char *old_path = cmd->path; - core_dir_config *conf; - regex_t *r = NULL; - const command_rec *thiscmd = cmd->cmd; - core_dir_config *c=mconfig; - ap_conf_vector_t *new_file_conf = ap_create_per_dir_config(cmd->pool); - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_LOCATION); - - if (err != NULL) { - return err; - } - - if (endp == NULL) { - return unclosed_directive(cmd); - } - - arg=apr_pstrndup(cmd->pool, arg, endp-arg); - - cmd->path = ap_getword_conf(cmd->pool, &arg); - /* Only if not an .htaccess file */ - if (!old_path) { - cmd->override = OR_ALL|ACCESS_CONF; - } - - if (thiscmd->cmd_data) { /* <FilesMatch> */ - r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE); - } - else if (!strcmp(cmd->path, "~")) { - cmd->path = ap_getword_conf(cmd->pool, &arg); - r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE); - } - else { - /* Ensure that the pathname is canonical */ - cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path); - } - - /* initialize our config and fetch it */ - conf = ap_set_config_vectors(cmd->server, new_file_conf, cmd->path, - &core_module, cmd->pool); - - errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_file_conf); - if (errmsg != NULL) - return errmsg; - - conf->d = cmd->path; - conf->d_is_fnmatch = apr_is_fnmatch(conf->d) != 0; - conf->r = r; - - ap_add_file_conf(c, new_file_conf); - - if (*arg != '\0') { - return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name, - "> arguments not (yet) supported.", NULL); - } - - cmd->path = old_path; - cmd->override = old_overrides; - - return NULL; -} - -static const char *start_ifmod(cmd_parms *cmd, void *mconfig, const char *arg) -{ - const char *endp = ap_strrchr_c(arg, '>'); - int not = (arg[0] == '!'); - module *found; - - if (endp == NULL) { - return unclosed_directive(cmd); - } - - arg=apr_pstrndup(cmd->pool, arg, endp-arg); - - if (not) { - arg++; - } - - found = ap_find_linked_module(arg); - - if ((!not && found) || (not && !found)) { - ap_directive_t *parent = NULL; - ap_directive_t *current = NULL; - const char *retval; - - retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd, - ¤t, &parent, "<IfModule"); - *(ap_directive_t **)mconfig = current; - return retval; - } - else { - *(ap_directive_t **)mconfig = NULL; - return ap_soak_end_container(cmd, "<IfModule"); - } -} - -AP_DECLARE(int) ap_exists_config_define(const char *name) -{ - char **defines; - int i; - - defines = (char **)ap_server_config_defines->elts; - for (i = 0; i < ap_server_config_defines->nelts; i++) { - if (strcmp(defines[i], name) == 0) { - return 1; - } - } - return 0; -} - -static const char *start_ifdefine(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *endp; - int defined; - int not = 0; - - endp = ap_strrchr_c(arg, '>'); - if (endp == NULL) { - return unclosed_directive(cmd); - } - - arg=apr_pstrndup(cmd->pool, arg, endp-arg); - - if (arg[0] == '!') { - not = 1; - arg++; - } - - defined = ap_exists_config_define(arg); - if ((!not && defined) || (not && !defined)) { - ap_directive_t *parent = NULL; - ap_directive_t *current = NULL; - const char *retval; - - retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd, - ¤t, &parent, "<IfDefine"); - *(ap_directive_t **)dummy = current; - return retval; - } - else { - *(ap_directive_t **)dummy = NULL; - return ap_soak_end_container(cmd, "<IfDefine"); - } -} - -/* httpd.conf commands... beginning with the <VirtualHost> business */ - -static const char *virtualhost_section(cmd_parms *cmd, void *dummy, - const char *arg) -{ - server_rec *main_server = cmd->server, *s; - const char *errmsg; - const char *endp = ap_strrchr_c(arg, '>'); - apr_pool_t *p = cmd->pool; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - if (endp == NULL) { - return unclosed_directive(cmd); - } - - arg=apr_pstrndup(cmd->pool, arg, endp-arg); - - /* FIXME: There's another feature waiting to happen here -- since you - can now put multiple addresses/names on a single <VirtualHost> - you might want to use it to group common definitions and then - define other "subhosts" with their individual differences. But - personally I'd rather just do it with a macro preprocessor. -djg */ - if (main_server->is_virtual) { - return "<VirtualHost> doesn't nest!"; - } - - errmsg = ap_init_virtual_host(p, arg, main_server, &s); - if (errmsg) { - return errmsg; - } - - s->next = main_server->next; - main_server->next = s; - - s->defn_name = cmd->directive->filename; - s->defn_line_number = cmd->directive->line_num; - - cmd->server = s; - - errmsg = ap_walk_config(cmd->directive->first_child, cmd, - s->lookup_defaults); - - cmd->server = main_server; - - return errmsg; -} - -static const char *set_server_alias(cmd_parms *cmd, void *dummy, - const char *arg) -{ - if (!cmd->server->names) { - return "ServerAlias only used in <VirtualHost>"; - } - while (*arg) { - char **item, *name = ap_getword_conf(cmd->pool, &arg); - if (ap_is_matchexp(name)) { - item = (char **)apr_array_push(cmd->server->wild_names); - } - else { - item = (char **)apr_array_push(cmd->server->names); - } - *item = name; - } - return NULL; -} - -static const char *add_filter(cmd_parms *cmd, void *dummy, const char *arg) -{ - core_dir_config *conf = dummy; - char **newfilter; - - newfilter = (char **)apr_array_push(conf->output_filters); - *newfilter = apr_pstrdup(cmd->pool, arg); - return NULL; -} - -static const char *add_input_filter(cmd_parms *cmd, void *dummy, const char *arg) -{ - core_dir_config *conf = dummy; - char **newfilter; - - newfilter = (char **)apr_array_push(conf->input_filters); - *newfilter = apr_pstrdup(cmd->pool, arg); - return NULL; -} - -static const char *set_server_string_slot(cmd_parms *cmd, void *dummy, - const char *arg) -{ - /* This one's pretty generic... */ - - int offset = (int)(long)cmd->info; - char *struct_ptr = (char *)cmd->server; - - const char *err = ap_check_cmd_context(cmd, - NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - *(const char **)(struct_ptr + offset) = arg; - return NULL; -} - -static const char *server_port(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - int port; - - if (err != NULL) { - return err; - } - port = atoi(arg); - if (port <= 0 || port >= 65536) { /* 65536 == 1<<16 */ - return apr_pstrcat(cmd->temp_pool, "The port number \"", arg, - "\" is outside the appropriate range " - "(i.e., 1..65535).", NULL); - } - cmd->server->port = port; - return NULL; -} - -static const char *set_signature_flag(cmd_parms *cmd, void *d_, - const char *arg) -{ - core_dir_config *d=d_; - - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - if (strcasecmp(arg, "On") == 0) { - d->server_signature = srv_sig_on; - } - else if (strcasecmp(arg, "Off") == 0) { - d->server_signature = srv_sig_off; - } - else if (strcasecmp(arg, "EMail") == 0) { - d->server_signature = srv_sig_withmail; - } - else { - return "ServerSignature: use one of: off | on | email"; - } - return NULL; -} - -static const char *set_server_root(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - - if (err != NULL) { - return err; - } - - arg = ap_os_canonical_filename(cmd->pool, arg); - - if (!ap_is_directory(cmd->pool, arg)) { - return "ServerRoot must be a valid directory"; - } - ap_server_root = arg; - return NULL; -} - -static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - cmd->server->timeout = atoi(arg); - return NULL; -} - -static const char *set_idcheck(cmd_parms *cmd, void *d_, int arg) -{ - core_dir_config *d=d_; - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - d->do_rfc1413 = arg != 0; - return NULL; -} - -static const char *set_hostname_lookups(cmd_parms *cmd, void *d_, - const char *arg) -{ - core_dir_config *d=d_; - - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - if (!strcasecmp(arg, "on")) { - d->hostname_lookups = HOSTNAME_LOOKUP_ON; - } - else if (!strcasecmp(arg, "off")) { - d->hostname_lookups = HOSTNAME_LOOKUP_OFF; - } - else if (!strcasecmp(arg, "double")) { - d->hostname_lookups = HOSTNAME_LOOKUP_DOUBLE; - } - else { - return "parameter must be 'on', 'off', or 'double'"; - } - return NULL; -} - -static const char *set_serverpath(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - cmd->server->path = arg; - cmd->server->pathlen = strlen(arg); - return NULL; -} - -static const char *set_content_md5(cmd_parms *cmd, void *d_, int arg) -{ - core_dir_config *d=d_; - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - d->content_md5 = arg != 0; - return NULL; -} - -static const char *set_use_canonical_name(cmd_parms *cmd, void *d_, - const char *arg) -{ - core_dir_config *d=d_; - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - if (strcasecmp(arg, "on") == 0) { - d->use_canonical_name = USE_CANONICAL_NAME_ON; - } - else if (strcasecmp(arg, "off") == 0) { - d->use_canonical_name = USE_CANONICAL_NAME_OFF; - } - else if (strcasecmp(arg, "dns") == 0) { - d->use_canonical_name = USE_CANONICAL_NAME_DNS; - } - else { - return "parameter must be 'on', 'off', or 'dns'"; - } - return NULL; -} - - -static const char *include_config (cmd_parms *cmd, void *dummy, - const char *name) -{ - ap_directive_t *conftree = NULL; - - ap_process_resource_config(cmd->server, - ap_server_root_relative(cmd->pool, name), - &conftree, cmd->pool, cmd->temp_pool); - *(ap_directive_t **)dummy = conftree; - return NULL; -} - -static const char *set_loglevel(cmd_parms *cmd, void *dummy, const char *arg) -{ - char *str; - - const char *err = ap_check_cmd_context(cmd, - NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - if ((str = ap_getword_conf(cmd->pool, &arg))) { - if (!strcasecmp(str, "emerg")) { - cmd->server->loglevel = APLOG_EMERG; - } - else if (!strcasecmp(str, "alert")) { - cmd->server->loglevel = APLOG_ALERT; - } - else if (!strcasecmp(str, "crit")) { - cmd->server->loglevel = APLOG_CRIT; - } - else if (!strcasecmp(str, "error")) { - cmd->server->loglevel = APLOG_ERR; - } - else if (!strcasecmp(str, "warn")) { - cmd->server->loglevel = APLOG_WARNING; - } - else if (!strcasecmp(str, "notice")) { - cmd->server->loglevel = APLOG_NOTICE; - } - else if (!strcasecmp(str, "info")) { - cmd->server->loglevel = APLOG_INFO; - } - else if (!strcasecmp(str, "debug")) { - cmd->server->loglevel = APLOG_DEBUG; - } - else { - return "LogLevel requires level keyword: one of " - "emerg/alert/crit/error/warn/notice/info/debug"; - } - } - else { - return "LogLevel requires level keyword"; - } - - return NULL; -} - -AP_DECLARE(const char *) ap_psignature(const char *prefix, request_rec *r) -{ - char sport[20]; - core_dir_config *conf; - - conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - if ((conf->server_signature == srv_sig_off) - || (conf->server_signature == srv_sig_unset)) { - return ""; - } - - apr_snprintf(sport, sizeof sport, "%u", (unsigned) ap_get_server_port(r)); - - if (conf->server_signature == srv_sig_withmail) { - return apr_pstrcat(r->pool, prefix, "<ADDRESS>" AP_SERVER_BASEVERSION - " Server at <A HREF=\"mailto:", - r->server->server_admin, "\">", - ap_get_server_name(r), "</A> Port ", sport, - "</ADDRESS>\n", NULL); - } - return apr_pstrcat(r->pool, prefix, "<ADDRESS>" AP_SERVER_BASEVERSION - " Server at ", ap_get_server_name(r), " Port ", sport, - "</ADDRESS>\n", NULL); -} - -/* - * Load an authorisation realm into our location configuration, applying the - * usual rules that apply to realms. - */ -static const char *set_authname(cmd_parms *cmd, void *mconfig, - const char *word1) -{ - core_dir_config *aconfig = (core_dir_config *)mconfig; - - aconfig->ap_auth_name = ap_escape_quotes(cmd->pool, word1); - return NULL; -} - -#ifdef _OSD_POSIX /* BS2000 Logon Passwd file */ -static const char *set_bs2000_account(cmd_parms *cmd, void *dummy, char *name) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - return os_set_account(cmd->pool, name); -} -#endif /*_OSD_POSIX*/ - -/* - * Handle a request to include the server's OS platform in the Server - * response header field (the ServerTokens directive). Unfortunately - * this requires a new global in order to communicate the setting back to - * http_main so it can insert the information in the right place in the - * string. - */ - -static char *server_version = NULL; -static int version_locked = 0; - -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 */ - SrvTk_PRODUCT_ONLY /* eg: Apache */ -}; -static enum server_token_type ap_server_tokens = SrvTk_FULL; - -static apr_status_t reset_version(void *dummy) -{ - version_locked = 0; - ap_server_tokens = SrvTk_FULL; - server_version = NULL; - return APR_SUCCESS; -} - -AP_DECLARE(const char *) ap_get_server_version(void) -{ - return (server_version ? server_version : AP_SERVER_BASEVERSION); -} - -AP_DECLARE(void) ap_add_version_component(apr_pool_t *pconf, 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) { - apr_pool_cleanup_register(pconf, NULL, reset_version, - apr_pool_cleanup_null); - server_version = apr_pstrdup(pconf, component); - } - else { - /* - * Tack the given component identifier to the end of - * the existing string. - */ - server_version = apr_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(apr_pool_t *pconf) -{ - if (ap_server_tokens == SrvTk_PRODUCT_ONLY) { - ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT); - } - else if (ap_server_tokens == SrvTk_MIN) { - ap_add_version_component(pconf, AP_SERVER_BASEVERSION); - } - else { - ap_add_version_component(pconf, AP_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 const char *set_serv_tokens(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - if (!strcasecmp(arg, "OS")) { - ap_server_tokens = SrvTk_OS; - } - else if (!strcasecmp(arg, "Min") || !strcasecmp(arg, "Minimal")) { - ap_server_tokens = SrvTk_MIN; - } - else if (!strcasecmp(arg, "Prod") || !strcasecmp(arg, "ProductOnly")) { - ap_server_tokens = SrvTk_PRODUCT_ONLY; - } - else { - ap_server_tokens = SrvTk_FULL; - } - return NULL; -} - -static const char *set_limit_req_line(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, - NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - int lim; - - if (err != NULL) { - return err; - } - lim = atoi(arg); - if (lim < 0) { - return apr_pstrcat(cmd->temp_pool, "LimitRequestLine \"", arg, - "\" must be a non-negative integer", NULL); - } - if (lim > DEFAULT_LIMIT_REQUEST_LINE) { - return apr_psprintf(cmd->temp_pool, "LimitRequestLine \"%s\" " - "must not exceed the precompiled maximum of %d", - arg, DEFAULT_LIMIT_REQUEST_LINE); - } - cmd->server->limit_req_line = lim; - return NULL; -} - -static const char *set_limit_req_fieldsize(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, - NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - int lim; - - if (err != NULL) { - return err; - } - lim = atoi(arg); - if (lim < 0) { - return apr_pstrcat(cmd->temp_pool, "LimitRequestFieldsize \"", arg, - "\" must be a non-negative integer (0 = no limit)", - NULL); - } - if (lim > DEFAULT_LIMIT_REQUEST_FIELDSIZE) { - return apr_psprintf(cmd->temp_pool, "LimitRequestFieldsize \"%s\" " - "must not exceed the precompiled maximum of %d", - arg, DEFAULT_LIMIT_REQUEST_FIELDSIZE); - } - cmd->server->limit_req_fieldsize = lim; - return NULL; -} - -static const char *set_limit_req_fields(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, - NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - int lim; - - if (err != NULL) { - return err; - } - lim = atoi(arg); - if (lim < 0) { - return apr_pstrcat(cmd->temp_pool, "LimitRequestFields \"", arg, - "\" must be a non-negative integer (0 = no limit)", - NULL); - } - cmd->server->limit_req_fields = lim; - return NULL; -} - -static const char *set_limit_req_body(cmd_parms *cmd, void *conf_, - const char *arg) -{ - core_dir_config *conf=conf_; - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - /* WTF: If strtoul is not portable, then write a replacement. - * Instead we have an idiotic define in httpd.h that prevents - * it from being used even when it is available. Sheesh. - */ - conf->limit_req_body = (unsigned long)strtol(arg, (char **)NULL, 10); - return NULL; -} - -static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_, - const char *arg) -{ - core_dir_config *conf = conf_; - const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); - if (err != NULL) { - return err; - } - - conf->limit_xml_body = atol(arg); - if (conf->limit_xml_body < 0) - return "LimitXMLRequestBody requires a non-negative integer."; - - return NULL; -} - -AP_DECLARE(size_t) ap_get_limit_xml_body(const request_rec *r) -{ - core_dir_config *conf; - - conf = ap_get_module_config(r->per_dir_config, &core_module); - if (conf->limit_xml_body == AP_LIMIT_UNSET) - return AP_DEFAULT_LIMIT_XML_BODY; - return (size_t)conf->limit_xml_body; -} - -#ifdef WIN32 -static const char *set_interpreter_source(cmd_parms *cmd, core_dir_config *d, - char *arg) -{ - if (!strcasecmp(arg, "registry")) { - d->script_interpreter_source = INTERPRETER_SOURCE_REGISTRY; - } else if (!strcasecmp(arg, "registry-strict")) { - d->script_interpreter_source = INTERPRETER_SOURCE_REGISTRY_STRICT; - } else if (!strcasecmp(arg, "script")) { - d->script_interpreter_source = INTERPRETER_SOURCE_SHEBANG; - } else { - return apr_pstrcat(cmd->temp_pool, "ScriptInterpreterSource \"", arg, - "\" must be \"registry\", \"registry-strict\" or " - "\"script\"", NULL); - } - return NULL; -} -#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, void *conf_, - const char *arg, const char *arg2) -{ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, 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, void *conf_, - const char *arg, const char *arg2) -{ - core_dir_config *conf=conf_; - - unixd_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, void *conf_, - const char *arg, const char * arg2) -{ - core_dir_config *conf=conf_; - -#if defined(RLIMIT_AS) - unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2 ,RLIMIT_AS); -#elif defined(RLIMIT_DATA) - unixd_set_rlimit(cmd, &conf->limit_mem, arg, arg2, RLIMIT_DATA); -#elif defined(RLIMIT_VMEM) - unixd_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, void *conf_, - const char *arg, const char * arg2) -{ - core_dir_config *conf=conf_; - - unixd_set_rlimit(cmd, &conf->limit_nproc, arg, arg2, RLIMIT_NPROC); - return NULL; -} -#endif - -static apr_status_t writev_it_all(apr_socket_t *s, - struct iovec *vec, int nvec, - apr_size_t len, apr_size_t *nbytes) -{ - apr_size_t bytes_written = 0; - apr_status_t rv; - apr_size_t n = len; - apr_size_t i = 0; - - *nbytes = 0; - - /* XXX handle checking for non-blocking socket */ - while (bytes_written != len) { - rv = apr_sendv(s, vec + i, nvec - i, &n); - bytes_written += n; - if (rv != APR_SUCCESS) - return rv; - *nbytes += n; - - /* If the write did not complete, adjust the iovecs and issue - * apr_sendv again - */ - if (bytes_written < len) { - /* Skip over the vectors that have already been written */ - apr_size_t cnt = vec[i].iov_len; - while (n >= cnt && i + 1 < nvec) { - i++; - cnt += vec[i].iov_len; - } - if (n < cnt) { - /* Handle partial write of vec i */ - vec[i].iov_base = (char *) vec[i].iov_base + - (vec[i].iov_len - (cnt - n)); - vec[i].iov_len = cnt -n; - } - } - n = len - bytes_written; - } - - return APR_SUCCESS; -} - -/* sendfile_it_all() - * send the entire file using sendfile() - * handle partial writes - * return only when all bytes have been sent or an error is encountered. - */ - -#if APR_HAS_SENDFILE -static apr_status_t sendfile_it_all(conn_rec *c, - apr_file_t *fd, - apr_hdtr_t *hdtr, - apr_off_t file_offset, - apr_size_t file_bytes_left, - apr_size_t total_bytes_left, - apr_int32_t flags) -{ - apr_status_t rv; -#ifdef AP_DEBUG - apr_int32_t timeout = 0; -#endif - - AP_DEBUG_ASSERT((apr_getsocketopt(c->client_socket, APR_SO_TIMEOUT, - &timeout) == APR_SUCCESS) && - timeout > 0); /* socket must be in timeout mode */ - do { - apr_size_t tmplen = file_bytes_left; - - rv = apr_sendfile(c->client_socket, fd, hdtr, &file_offset, &tmplen, - flags); - total_bytes_left -= tmplen; - if (!total_bytes_left || rv != APR_SUCCESS) { - return rv; /* normal case & error exit */ - } - - AP_DEBUG_ASSERT(total_bytes_left > 0 && tmplen > 0); - - /* partial write, oooh noooo... - * Skip over any header data which was written - */ - while (tmplen && hdtr->numheaders) { - if (tmplen >= hdtr->headers[0].iov_len) { - tmplen -= hdtr->headers[0].iov_len; - --hdtr->numheaders; - ++hdtr->headers; - } - else { - char *iov_base = (char *)hdtr->headers[0].iov_base; - - hdtr->headers[0].iov_len -= tmplen; - iov_base += tmplen; - hdtr->headers[0].iov_base = iov_base; - tmplen = 0; - } - } - - /* Skip over any file data which was written */ - - if (tmplen <= file_bytes_left) { - file_offset += tmplen; - file_bytes_left -= tmplen; - continue; - } - tmplen -= file_bytes_left; - file_bytes_left = 0; - file_offset = 0; - - /* Skip over any trailer data which was written */ - - while (tmplen && hdtr->numtrailers) { - if (tmplen >= hdtr->trailers[0].iov_len) { - tmplen -= hdtr->trailers[0].iov_len; - --hdtr->numtrailers; - ++hdtr->trailers; - } - else { - char *iov_base = (char *)hdtr->trailers[0].iov_base; - - hdtr->trailers[0].iov_len -= tmplen; - iov_base += tmplen; - hdtr->trailers[0].iov_base = iov_base; - tmplen = 0; - } - } - } while (1); -} -#endif - -/* - * send_the_file() - * Sends the contents of file fd along with header/trailer bytes, if any, - * to the network. send_the_file will return only when all the bytes have been - * sent (i.e., it handles partial writes) or on a network error condition. - */ -static apr_status_t send_the_file(conn_rec *c, apr_file_t *fd, - apr_hdtr_t *hdtr, apr_off_t offset, - apr_size_t length, apr_size_t *nbytes) -{ - apr_status_t rv = APR_SUCCESS; - apr_int32_t togo; /* Remaining number of bytes in the file to send */ - apr_size_t sendlen = 0; - apr_size_t bytes_sent; - apr_int32_t i; - apr_off_t o; /* Track the file offset for partial writes */ - char buffer[8192]; - - *nbytes = 0; - - /* Send the headers - * writev_it_all handles partial writes. - * XXX: optimization... if headers are less than MIN_WRITE_SIZE, copy - * them into buffer - */ - if ( hdtr && hdtr->numheaders > 0 ) { - for (i = 0; i < hdtr->numheaders; i++) { - sendlen += hdtr->headers[i].iov_len; - } - rv = writev_it_all(c->client_socket, hdtr->headers, hdtr->numheaders, - sendlen, &bytes_sent); - if (rv == APR_SUCCESS) - *nbytes += bytes_sent; /* track total bytes sent */ - } - - /* Seek the file to 'offset' */ - if (offset != 0 && rv == APR_SUCCESS) { - rv = apr_file_seek(fd, APR_SET, &offset); - } - - /* Send the file, making sure to handle partial writes */ - togo = length; - while (rv == APR_SUCCESS && togo) { - sendlen = togo > sizeof(buffer) ? sizeof(buffer) : togo; - o = 0; - rv = apr_file_read(fd, buffer, &sendlen); - while (rv == APR_SUCCESS && sendlen) { - bytes_sent = sendlen; - rv = apr_send(c->client_socket, &buffer[o], &bytes_sent); - if (rv == APR_SUCCESS) { - sendlen -= bytes_sent; /* sendlen != bytes_sent ==> partial write */ - o += bytes_sent; /* o is where we are in the buffer */ - *nbytes += bytes_sent; - togo -= bytes_sent; /* track how much of the file we've sent */ - } - } - } - - /* Send the trailers - * XXX: optimization... if it will fit, send this on the last send in the - * loop above - */ - sendlen = 0; - if ( rv == APR_SUCCESS && hdtr && hdtr->numtrailers > 0 ) { - for (i = 0; i < hdtr->numtrailers; i++) { - sendlen += hdtr->trailers[i].iov_len; - } - rv = writev_it_all(c->client_socket, hdtr->trailers, hdtr->numtrailers, - sendlen, &bytes_sent); - if (rv == APR_SUCCESS) - *nbytes += bytes_sent; - } - - return rv; -} - -/* Note --- ErrorDocument will now work from .htaccess files. - * The AllowOverride of Fileinfo allows webmasters to turn it off - */ - -static const command_rec core_cmds[] = { - -/* Old access config file commands */ - -AP_INIT_RAW_ARGS("<Directory", dirsection, NULL, RSRC_CONF, - "Container for directives affecting resources located in the specified " - "directories"), -AP_INIT_RAW_ARGS("<Location", urlsection, NULL, RSRC_CONF, - "Container for directives affecting resources accessed through the " - "specified URL paths"), -AP_INIT_RAW_ARGS("<VirtualHost", virtualhost_section, NULL, RSRC_CONF, - "Container to map directives to a particular virtual host, takes one or " - "more host addresses"), -AP_INIT_RAW_ARGS("<Files", filesection, NULL, OR_ALL, - "Container for directives affecting files matching specified patterns"), -AP_INIT_RAW_ARGS("<Limit", ap_limit_section, NULL, OR_ALL, - "Container for authentication directives when accessed using specified HTTP " - "methods"), -AP_INIT_RAW_ARGS("<LimitExcept", ap_limit_section, (void*)1, OR_ALL, - "Container for authentication directives to be applied when any HTTP " - "method other than those specified is used to access the resource"), -AP_INIT_TAKE1("<IfModule", start_ifmod, NULL, EXEC_ON_READ | OR_ALL, - "Container for directives based on existance of specified modules"), -AP_INIT_TAKE1("<IfDefine", start_ifdefine, NULL, EXEC_ON_READ | OR_ALL, - "Container for directives based on existance of command line defines"), -AP_INIT_RAW_ARGS("<DirectoryMatch", dirsection, (void*)1, RSRC_CONF, - "Container for directives affecting resources located in the " - "specified directories"), -AP_INIT_RAW_ARGS("<LocationMatch", urlsection, (void*)1, RSRC_CONF, - "Container for directives affecting resources accessed through the " - "specified URL paths"), -AP_INIT_RAW_ARGS("<FilesMatch", filesection, (void*)1, OR_ALL, - "Container for directives affecting files matching specified patterns"), -AP_INIT_TAKE1("AuthType", ap_set_string_slot, - (void*)XtOffsetOf(core_dir_config, ap_auth_type), OR_AUTHCFG, - "An HTTP authorization type (e.g., \"Basic\")"), -AP_INIT_TAKE1("AuthName", set_authname, NULL, OR_AUTHCFG, - "The authentication realm (e.g. \"Members Only\")"), -AP_INIT_RAW_ARGS("Require", require, NULL, OR_AUTHCFG, - "Selects which authenticated users or groups may access a protected space"), -AP_INIT_TAKE1("Satisfy", satisfy, NULL, OR_AUTHCFG, - "access policy if both allow and require used ('all' or 'any')"), -#ifdef GPROF -AP_INIT_TAKE1("GprofDir", set_gprof_dir, NULL, RSRC_CONF, - "Directory to plop gmon.out files"), -#endif -AP_INIT_TAKE1("AddDefaultCharset", set_add_default_charset, NULL, OR_FILEINFO, - "The name of the default charset to add to any Content-Type without one or 'Off' to disable"), - -/* Old resource config file commands */ - -AP_INIT_RAW_ARGS("AccessFileName", set_access_name, NULL, RSRC_CONF, - "Name(s) of per-directory config files (default: .htaccess)"), -AP_INIT_TAKE1("DocumentRoot", set_document_root, NULL, RSRC_CONF, - "Root directory of the document tree"), -AP_INIT_TAKE2("ErrorDocument", set_error_document, NULL, OR_FILEINFO, - "Change responses for HTTP errors"), -AP_INIT_RAW_ARGS("AllowOverride", set_override, NULL, ACCESS_CONF, - "Controls what groups of directives can be configured by per-directory " - "config files"), -AP_INIT_RAW_ARGS("Options", set_options, NULL, OR_OPTIONS, - "Set a number of attributes for a given directory"), -AP_INIT_TAKE1("DefaultType", ap_set_string_slot, - (void*)XtOffsetOf (core_dir_config, ap_default_type), - OR_FILEINFO, "the default MIME type for untypable files"), - -/* Old server config file commands */ - -AP_INIT_TAKE1("Port", server_port, NULL, RSRC_CONF, "A TCP port number"), -AP_INIT_TAKE1("HostnameLookups", set_hostname_lookups, NULL, - ACCESS_CONF|RSRC_CONF, - "\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to " - "enable double-reverse DNS lookups"), -AP_INIT_TAKE1("ServerAdmin", set_server_string_slot, - (void *)XtOffsetOf (server_rec, server_admin), RSRC_CONF, - "The email address of the server administrator"), -AP_INIT_TAKE1("ServerName", set_server_string_slot, - (void *)XtOffsetOf (server_rec, server_hostname), RSRC_CONF, - "The hostname of the server"), -AP_INIT_TAKE1("ServerSignature", set_signature_flag, NULL, OR_ALL, - "En-/disable server signature (on|off|email)"), -AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF, - "Common directory of server-related files (logs, confs, etc.)"), -AP_INIT_TAKE1("ErrorLog", set_server_string_slot, - (void *)XtOffsetOf (server_rec, error_fname), RSRC_CONF, - "The filename of the error log"), -AP_INIT_RAW_ARGS("ServerAlias", set_server_alias, NULL, RSRC_CONF, - "A name or names alternately used to access the server"), -AP_INIT_TAKE1("ServerPath", set_serverpath, NULL, RSRC_CONF, - "The pathname the server can be reached at"), -AP_INIT_TAKE1("Timeout", set_timeout, NULL, RSRC_CONF, - "Timeout duration (sec)"), -AP_INIT_FLAG("IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF, - "Enable identd (RFC 1413) user lookups - SLOW"), -AP_INIT_FLAG("ContentDigest", set_content_md5, NULL, OR_OPTIONS, - "whether or not to send a Content-MD5 header with each request"), -AP_INIT_TAKE1("UseCanonicalName", set_use_canonical_name, NULL, - RSRC_CONF|ACCESS_CONF, - "How to work out the ServerName : Port when constructing URLs"), -/* TODO: RlimitFoo should all be part of mod_cgi, not in the core */ -/* TODO: ListenBacklog in MPM */ -AP_INIT_TAKE1("Include", include_config, NULL, - (RSRC_CONF | ACCESS_CONF | EXEC_ON_READ), - "Name of the config file to be included"), -AP_INIT_TAKE1("LogLevel", set_loglevel, NULL, RSRC_CONF, - "Level of verbosity in error logging"), -AP_INIT_TAKE1("NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF, - "A numeric IP address:port, or the name of a host"), -#ifdef _OSD_POSIX -AP_INIT_TAKE1("BS2000Account", set_bs2000_account, NULL, RSRC_CONF, - "Name of server User's bs2000 logon account name"), -#endif -#ifdef WIN32 -AP_INIT_TAKE1("ScriptInterpreterSource", set_interpreter_source, NULL, - OR_FILEINFO, - "Where to find interpreter to run Win32 scripts (Registry or script shebang line)"), -#endif -AP_INIT_TAKE1("ServerTokens", set_serv_tokens, NULL, RSRC_CONF, - "Determine tokens displayed in the Server: header - Min(imal), OS or Full"), -AP_INIT_TAKE1("LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF, - "Limit on maximum size of an HTTP request line"), -AP_INIT_TAKE1("LimitRequestFieldsize", set_limit_req_fieldsize, NULL, - RSRC_CONF, - "Limit on maximum size of an HTTP request header field"), -AP_INIT_TAKE1("LimitRequestFields", set_limit_req_fields, NULL, RSRC_CONF, - "Limit (0 = unlimited) on max number of header fields in a request message"), -AP_INIT_TAKE1("LimitRequestBody", set_limit_req_body, - (void*)XtOffsetOf(core_dir_config, limit_req_body), OR_ALL, - "Limit (in bytes) on maximum size of request message body"), -AP_INIT_TAKE1("LimitXMLRequestBody", set_limit_xml_req_body, NULL, OR_ALL, - "Limit (in bytes) on maximum size of an XML-based request " - "body"), - -/* System Resource Controls */ -#ifdef RLIMIT_CPU -AP_INIT_TAKE12("RLimitCPU", set_limit_cpu, - (void*)XtOffsetOf(core_dir_config, limit_cpu), - OR_ALL, "Soft/hard limits for max CPU usage in seconds"), -#else -AP_INIT_TAKE12("RLimitCPU", no_set_limit, NULL, - OR_ALL, "Soft/hard limits for max CPU usage in seconds"), -#endif -#if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined (RLIMIT_AS) -AP_INIT_TAKE12("RLimitMEM", set_limit_mem, - (void*)XtOffsetOf(core_dir_config, limit_mem), - OR_ALL, "Soft/hard limits for max memory usage per process"), -#else -AP_INIT_TAKE12("RLimitMEM", no_set_limit, NULL, - OR_ALL, "Soft/hard limits for max memory usage per process"), -#endif -#ifdef RLIMIT_NPROC -AP_INIT_TAKE12("RLimitNPROC", set_limit_nproc, - (void*)XtOffsetOf(core_dir_config, limit_nproc), - OR_ALL, "soft/hard limits for max number of processes per uid"), -#else -AP_INIT_TAKE12("RLimitNPROC", no_set_limit, NULL, - OR_ALL, "soft/hard limits for max number of processes per uid"), -#endif -/* XXX These should be allowable in .htaccess files, but currently it won't - * play well with the Options stuff. Until that is fixed, I would prefer - * to leave it just in the conf file. Other should feel free to disagree - * with me. Rbb. - */ -AP_INIT_ITERATE("SetOutputFilter", add_filter, NULL, ACCESS_CONF, - "filters to be run"), -AP_INIT_ITERATE("SetInputFilter", add_input_filter, NULL, ACCESS_CONF, - "filters to be run on the request body"), -{ NULL } -}; - -/***************************************************************** - * - * Core handlers for various phases of server operation... - */ - -AP_DECLARE_NONSTD(int) ap_core_translate(request_rec *r) -{ - void *sconf = r->server->module_config; - core_server_config *conf = ap_get_module_config(sconf, &core_module); - - if (r->proxyreq) { - return HTTP_FORBIDDEN; - } - if ((r->uri[0] != '/') && strcmp(r->uri, "*")) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid URI in request %s", r->the_request); - return HTTP_BAD_REQUEST; - } - - if (r->server->path - && !strncmp(r->uri, r->server->path, r->server->pathlen) - && (r->server->path[r->server->pathlen - 1] == '/' - || r->uri[r->server->pathlen] == '/' - || r->uri[r->server->pathlen] == '\0')) { - r->filename = apr_pstrcat(r->pool, conf->ap_document_root, - (r->uri + r->server->pathlen), NULL); - } - else { - /* - * Make sure that we do not mess up the translation by adding two - * /'s in a row. This happens under windows when the document - * root ends with a / - */ - if ((conf->ap_document_root[strlen(conf->ap_document_root)-1] == '/') - && (*(r->uri) == '/')) { - r->filename = apr_pstrcat(r->pool, conf->ap_document_root, r->uri+1, - NULL); - } - else { - r->filename = apr_pstrcat(r->pool, conf->ap_document_root, r->uri, - NULL); - } - } - - return OK; -} - -static int do_nothing(request_rec *r) { return OK; } - -static int default_handler(request_rec *r) -{ - apr_bucket_brigade *bb; - apr_bucket *e; - core_dir_config *d; - int errstatus; - apr_file_t *fd = NULL; - apr_status_t status; - /* XXX if/when somebody writes a content-md5 filter we either need to - * remove this support or coordinate when to use the filter vs. - * when to use this code - * The current choice of when to compute the md5 here matches the 1.3 - * support fairly closely (unlike 1.3, we don't handle computing md5 - * when the charset is translated). - */ - int bld_content_md5; - - /* - * The old way of doing handlers meant that this handler would - * match literally anything - this way will require handler to - * have a / in the middle, which probably captures the original - * intent, but may cause problems at first - Ben 7th Jan 01 - */ - if(strcmp(r->handler,"default-handler") - && ap_strcmp_match(r->handler,"*/*")) - return DECLINED; - - d = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - bld_content_md5 = (d->content_md5 & 1) - && r->output_filters->frec->ftype != AP_FTYPE_CONTENT; - - ap_allow_methods(r, MERGE_ALLOW, "GET", "OPTIONS", "POST", NULL); - - if ((errstatus = ap_discard_request_body(r)) != OK) { - return errstatus; - } - - if (r->method_number == M_INVALID) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Invalid method in request %s", r->the_request); - return HTTP_NOT_IMPLEMENTED; - } - if (r->method_number == M_OPTIONS) { - return ap_send_http_options(r); - } - if (r->method_number == M_PUT) { - return HTTP_METHOD_NOT_ALLOWED; - } - if (r->finfo.filetype == 0 || (r->path_info && *r->path_info)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, - "File does not exist: %s",r->path_info ? - apr_pstrcat(r->pool, r->filename, r->path_info, NULL) - : r->filename); - return HTTP_NOT_FOUND; - } - - if (r->method_number != M_GET && r->method_number != M_POST) { - return HTTP_METHOD_NOT_ALLOWED; - } - - if ((status = apr_file_open(&fd, r->filename, APR_READ | APR_BINARY, 0, r->pool)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, - "file permissions deny server access: %s", r->filename); - return HTTP_FORBIDDEN; - } - ap_update_mtime(r, r->finfo.mtime); - ap_set_last_modified(r); - ap_set_etag(r); - apr_table_setn(r->headers_out, "Accept-Ranges", "bytes"); - ap_set_content_length(r, r->finfo.size); - if ((errstatus = ap_meets_conditions(r)) != OK) { - apr_file_close(fd); - return errstatus; - } - - if (bld_content_md5) { - apr_table_setn(r->headers_out, "Content-MD5", - ap_md5digest(r->pool, fd)); - } - - bb = apr_brigade_create(r->pool); - e = apr_bucket_file_create(fd, 0, r->finfo.size); - - APR_BRIGADE_INSERT_HEAD(bb, e); - e = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, e); - - return ap_pass_brigade(r->output_filters, bb); -} - -static int core_input_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_size_t *readbytes) -{ - apr_bucket *e; - - if (!f->ctx) { /* If we haven't passed up the socket yet... */ - f->ctx = (void *)1; - e = apr_bucket_socket_create(f->c->client_socket); - APR_BRIGADE_INSERT_TAIL(b, e); - return APR_SUCCESS; - } - else { - /* Either some code lost track of the socket - * bucket or we already found out that the - * client closed. - */ - return APR_EOF; - } -} - -/* Default filter. This filter should almost always be used. Its only job - * is to send the headers if they haven't already been sent, and then send - * the actual data. - */ -typedef struct CORE_OUTPUT_FILTER_CTX { - apr_bucket_brigade *b; -} core_output_filter_ctx_t; - -#define MAX_IOVEC_TO_WRITE 16 - -static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b) -{ - apr_status_t rv; - conn_rec *c = f->c; - core_output_filter_ctx_t *ctx = f->ctx; - - if (ctx == NULL) { - f->ctx = ctx = apr_pcalloc(c->pool, sizeof(core_output_filter_ctx_t)); - } - - /* If we have a saved brigade, concatenate the new brigade to it */ - if (ctx->b) { - APR_BRIGADE_CONCAT(ctx->b, b); - b = ctx->b; - ctx->b = NULL; - } - - /* Perform multiple passes over the brigade, sending batches of output - to the connection. */ - while (b) { - apr_size_t nbytes = 0; - apr_bucket *e; - - /* tail of brigade if we need another pass */ - apr_bucket_brigade *more = NULL; - - /* one group of iovecs per pass over the brigade */ - apr_size_t nvec = 0; - apr_size_t nvec_trailers = 0; - struct iovec vec[MAX_IOVEC_TO_WRITE]; - struct iovec vec_trailers[MAX_IOVEC_TO_WRITE]; - - /* one file per pass over the brigade */ - apr_file_t *fd = NULL; - apr_size_t flen = 0; - apr_off_t foffset = 0; - - /* Iterate over the brigade: collect iovecs and/or a file */ - APR_BRIGADE_FOREACH(e, b) { - if (APR_BUCKET_IS_EOS(e) || APR_BUCKET_IS_FLUSH(e)) { - break; - } - /* It doesn't make any sense to use sendfile for a file bucket - * that represents 10 bytes. - */ - else if (APR_BUCKET_IS_FILE(e) - && (e->length >= AP_MIN_SENDFILE_BYTES)) { - apr_bucket_file *a = e->data; - - /* We can't handle more than one file bucket at a time - * so we split here and send the file we have already - * found. - */ - if (fd) { - more = apr_brigade_split(b, e); - break; - } - - fd = a->fd; - flen = e->length; - foffset = e->start; - } - else { - const char *str; - apr_size_t n; - - rv = apr_bucket_read(e, &str, &n, APR_BLOCK_READ); - if (n) { - if (!fd) { - if (nvec == MAX_IOVEC_TO_WRITE) { - /* woah! too many. stop now. */ - more = apr_brigade_split(b, e); - break; - } - vec[nvec].iov_base = (char*) str; - vec[nvec].iov_len = n; - nvec++; - } - else { - /* The bucket is a trailer to a file bucket */ - - if (nvec_trailers == MAX_IOVEC_TO_WRITE) { - /* woah! too many. stop now. */ - more = apr_brigade_split(b, e); - break; - } - vec_trailers[nvec_trailers].iov_base = (char*) str; - vec_trailers[nvec_trailers].iov_len = n; - nvec_trailers++; - } - nbytes += n; - } - } - } - - /* Completed iterating over the brigades, now determine if we want - * to buffer the brigade or send the brigade out on the network. - * - * Save if: - * - * 1) we didn't see a file, we don't have more passes over the - * brigade to perform, we haven't accumulated enough bytes to - * send, AND we didn't stop at a FLUSH bucket. - * (IOW, we will save away plain old bytes) - * or - * 2) we hit the EOS and have a keep-alive connection - * (IOW, this response is a bit more complex, but we save it - * with the hope of concatenating with another response) - */ - if ((!fd && !more && - (nbytes + flen < AP_MIN_BYTES_TO_WRITE) && !APR_BUCKET_IS_FLUSH(e)) - || (nbytes + flen < AP_MIN_BYTES_TO_WRITE && APR_BUCKET_IS_EOS(e) && c->keepalive)) { - /* NEVER save an EOS in here. If we are saving a brigade with - * an EOS bucket, then we are doing keepalive connections, and - * we want to process to second request fully. - */ - if (APR_BUCKET_IS_EOS(e)) { - apr_bucket *bucket = NULL; - /* If we are in here, then this request is a keepalive. We - * need to be certain that any data in a bucket is valid - * after the request_pool is cleared. - */ - if (ctx->b == NULL) { - ctx->b = apr_brigade_create(f->c->pool); - } - - APR_BRIGADE_FOREACH(bucket, b) { - const char *str; - apr_size_t n; - - rv = apr_bucket_read(bucket, &str, &n, APR_BLOCK_READ); - - /* This apr_brigade_write does not use a flush function - because we assume that we will not write enough data - into it to cause a flush. However, if we *do* write - "too much", then we could end up with transient - buckets which would suck. This works for now, but is - a bit shaky if changes are made to some of the - buffering sizes. Let's do an assert to prevent - potential future problems... */ - AP_DEBUG_ASSERT(AP_MIN_BYTES_TO_WRITE <= - APR_BUCKET_BUFF_SIZE); - apr_brigade_write(ctx->b, NULL, NULL, str, n); - } - apr_brigade_destroy(b); - } - else { - ap_save_brigade(f, &ctx->b, &b); - } - return APR_SUCCESS; - } - - if (fd) { - apr_hdtr_t hdtr; -#if APR_HAS_SENDFILE - apr_int32_t flags = 0; -#endif - - memset(&hdtr, '\0', sizeof(hdtr)); - if (nvec) { - hdtr.numheaders = nvec; - hdtr.headers = vec; - } - if (nvec_trailers) { - hdtr.numtrailers = nvec_trailers; - hdtr.trailers = vec_trailers; - } -#if APR_HAS_SENDFILE - if (!c->keepalive) { - /* Prepare the socket to be reused */ - flags |= APR_SENDFILE_DISCONNECT_SOCKET; - } - rv = sendfile_it_all(c, /* the connection */ - fd, /* the file to send */ - &hdtr, /* header and trailer iovecs */ - foffset, /* offset in the file to begin - sending from */ - flen, /* length of file */ - nbytes + flen, /* total length including - headers */ - flags); /* apr_sendfile flags */ - - /* If apr_sendfile() returns APR_ENOTIMPL, call send_the_file() - * to loop on apr_file_read/apr_send to send the file. Our Windows - * binary distributions (which work on Windows 9x/NT) are - * compiled on Windows NT. TransmitFile is not available on - * Windows 95/98 and we discover this at runtime when - * apr_sendfile() returns APR_ENOTIMPL. Having apr_sendfile() - * return APR_ENOTIMPL seems the cleanest way to handle this - * case. - */ - if (rv == APR_ENOTIMPL) -#endif - { - apr_size_t unused_bytes_sent; - - rv = send_the_file(c, fd, &hdtr, foffset, flen, - &unused_bytes_sent); - } - fd = NULL; - } - else { - apr_size_t unused_bytes_sent; - - rv = writev_it_all(c->client_socket, - vec, nvec, - nbytes, &unused_bytes_sent); - } - - apr_brigade_destroy(b); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, c->base_server, - "core_output_filter: writing data to the network"); - if (more) - apr_brigade_destroy(more); - if (APR_STATUS_IS_ECONNABORTED(rv) || - APR_STATUS_IS_ECONNRESET(rv)) { - c->aborted = 1; - } - return rv; - } - - b = more; - more = NULL; - } /* end while () */ - - return APR_SUCCESS; -} - -static void core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - ap_set_version(pconf); -} - -static void core_open_logs(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - ap_open_logs(s, pconf); -} - -static void core_insert_filter(request_rec *r) -{ - int i; - core_dir_config *conf = (core_dir_config *) - ap_get_module_config(r->per_dir_config, - &core_module); - char **items = (char **)conf->output_filters->elts; - - for (i = 0; i < conf->output_filters->nelts; i++) { - char *foobar = items[i]; - ap_add_output_filter(foobar, NULL, r, r->connection); - } - - items = (char **)conf->input_filters->elts; - for (i = 0; i < conf->input_filters->nelts; i++) { - char *foobar = items[i]; - ap_add_input_filter(foobar, NULL, r, r->connection); - } -} - -static int core_create_req(request_rec *r) -{ - if (r->main) { - ap_set_module_config(r->request_config, &core_module, - ap_get_module_config(r->main->request_config, &core_module)); - } - else { - core_request_config *req_cfg; - - req_cfg = apr_pcalloc(r->pool, sizeof(core_request_config)); - req_cfg->bb = apr_brigade_create(r->pool); - ap_set_module_config(r->request_config, &core_module, req_cfg); - } - return OK; -} - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST); - ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST); - ap_hook_open_logs(core_open_logs,NULL,NULL,APR_HOOK_MIDDLE); - ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST); - /* FIXME: I suspect we can eliminate the need for these - Ben */ - ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST); - ap_hook_access_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST); - ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE); - - /* register the core's insert_filter hook and register core-provided - * filters - */ - ap_hook_insert_filter(core_insert_filter, NULL, NULL, APR_HOOK_MIDDLE); - - ap_register_input_filter("CORE_IN", core_input_filter, AP_FTYPE_NETWORK); - ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter, - AP_FTYPE_HTTP_HEADER); - ap_register_output_filter("CORE", core_output_filter, AP_FTYPE_NETWORK); - ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter, - AP_FTYPE_CONTENT); - ap_register_output_filter("OLD_WRITE", ap_old_write_filter, - AP_FTYPE_CONTENT - 1); -} - -AP_DECLARE_DATA module core_module = { - STANDARD20_MODULE_STUFF, - create_core_dir_config, /* create per-directory config structure */ - merge_core_dir_configs, /* merge per-directory config structures */ - create_core_server_config, /* create per-server config structure */ - merge_core_server_configs, /* merge per-server config structures */ - core_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/server/error_bucket.c b/server/error_bucket.c deleted file mode 100644 index 7a786ff4d8..0000000000 --- a/server/error_bucket.c +++ /dev/null @@ -1,106 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "http_protocol.h" -#include "apr_buckets.h" -#include "apr_strings.h" -#include <stdlib.h> -#if APR_HAVE_STRINGS_H -#include <strings.h> -#endif - -static apr_status_t error_read(apr_bucket *b, const char **str, - apr_size_t *len, apr_read_type_e block) -{ - *str = NULL; - *len = 0; - return APR_SUCCESS; -} - -AP_DECLARE(apr_bucket *) ap_bucket_error_make(apr_bucket *b, int error, - const char *buf, apr_pool_t *p) -{ - ap_bucket_error *h; - - h = malloc(sizeof(*h)); - if (h == NULL) { - return NULL; - } - h->status = error; - h->data = (buf) ? apr_pstrdup(p, buf) : NULL; - - b->length = 0; - b->start = 0; - b->type = &ap_bucket_type_error; - b->data = h; - return b; -} - -AP_DECLARE(apr_bucket *) ap_bucket_error_create(int error, - const char *buf, apr_pool_t *p) -{ - apr_bucket *b = (apr_bucket *)calloc(1, sizeof(*b)); - - APR_BUCKET_INIT(b); - return ap_bucket_error_make(b, error, buf, p); -} - -AP_DECLARE_DATA const apr_bucket_type_t ap_bucket_type_error = { - "ERROR", 5, - free, - error_read, - apr_bucket_setaside_notimpl, - apr_bucket_split_notimpl, - apr_bucket_copy_notimpl -}; diff --git a/server/gen_test_char.c b/server/gen_test_char.c deleted file mode 100644 index 5bc1f97f01..0000000000 --- a/server/gen_test_char.c +++ /dev/null @@ -1,128 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr.h" -#include "apr_lib.h" - -#if APR_HAVE_STDIO_H -#include <stdio.h> -#endif - -/* we need some of the portability definitions... for strchr */ -#include "ap_config.h" -#include "httpd.h" - -/* A bunch of functions in util.c scan strings looking for certain characters. - * To make that more efficient we encode a lookup table. - */ -#define T_ESCAPE_SHELL_CMD (0x01) -#define T_ESCAPE_PATH_SEGMENT (0x02) -#define T_OS_ESCAPE_PATH (0x04) -#define T_HTTP_TOKEN_STOP (0x08) - -int main(int argc, char *argv[]) -{ - unsigned c; - unsigned char flags; - - printf( -"/* this file is automatically generated by gen_test_char, do not edit */\n" -"#define T_ESCAPE_SHELL_CMD (%u)\n" -"#define T_ESCAPE_PATH_SEGMENT (%u)\n" -"#define T_OS_ESCAPE_PATH (%u)\n" -"#define T_HTTP_TOKEN_STOP (%u)\n" -"\n" -"static const unsigned char test_char_table[256] = {\n" -" 0,", - T_ESCAPE_SHELL_CMD, - T_ESCAPE_PATH_SEGMENT, - T_OS_ESCAPE_PATH, - T_HTTP_TOKEN_STOP); - - /* we explicitly dealt with NUL above - * in case some strchr() do bogosity with it */ - - for (c = 1; c < 256; ++c) { - flags = 0; - if (c % 20 == 0) - printf("\n "); - - /* escape_shell_cmd */ - if (strchr("&;`'\"|*?~<>^()[]{}$\\\n", c)) { - flags |= T_ESCAPE_SHELL_CMD; - } - - if (!apr_isalnum(c) && !strchr("$-_.+!*'(),:@&=~", c)) { - flags |= T_ESCAPE_PATH_SEGMENT; - } - - if (!apr_isalnum(c) && !strchr("$-_.+!*'(),:@&=/~", c)) { - flags |= T_OS_ESCAPE_PATH; - } - - /* these are the "tspecials" from RFC2068 */ - if (apr_iscntrl(c) || strchr(" \t()<>@,;:\\/[]?={}", c)) { - flags |= T_HTTP_TOKEN_STOP; - } - printf("%u%c", flags, (c < 255) ? ',' : ' '); - - } - printf("\n};\n"); - - return 0; -} diff --git a/server/gen_test_char.dsp b/server/gen_test_char.dsp deleted file mode 100644 index 26c12386db..0000000000 --- a/server/gen_test_char.dsp +++ /dev/null @@ -1,90 +0,0 @@ -# Microsoft Developer Studio Project File - Name="gen_test_char" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=gen_test_char - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "gen_test_char.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "gen_test_char.mak" CFG="gen_test_char - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "gen_test_char - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "gen_test_char - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "gen_test_char - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /I "..\include" /I "..\srclib\apr\include" /I "..\srclib\apr-util\include" /I "..\os\win32" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fd"Release\gen_test_char" /FD /c -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:console /incremental:no /pdb:"Release\gen_test_char.pdb" /machine:I386 -# ADD LINK32 kernel32.lib /nologo /subsystem:console /incremental:no /pdb:"Release\gen_test_char.pdb" /machine:I386 - -!ELSEIF "$(CFG)" == "gen_test_char - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /I "..\include" /I "..\srclib\apr\include" /I "..\srclib\apr-util\include" /I "..\os\win32" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fd"Debug\gen_test_char" /FD /c -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:console /incremental:no /pdb:"Debug\gen_test_char.pdb" /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib /nologo /subsystem:console /incremental:no /pdb:"Debug\gen_test_char.pdb" /debug /machine:I386 - -!ENDIF - -# Begin Target - -# Name "gen_test_char - Win32 Release" -# Name "gen_test_char - Win32 Debug" -# Begin Source File - -SOURCE=.\gen_test_char.c -# End Source File -# End Target -# End Project diff --git a/server/gen_test_char.mak b/server/gen_test_char.mak deleted file mode 100644 index c884e79eb4..0000000000 --- a/server/gen_test_char.mak +++ /dev/null @@ -1,300 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on gen_test_char.dsp -!IF "$(CFG)" == "" -CFG=gen_test_char - Win32 Debug -!MESSAGE No configuration specified. Defaulting to gen_test_char - Win32 Debug. -!ENDIF - -!IF "$(CFG)" != "gen_test_char - Win32 Release" && "$(CFG)" !=\ - "gen_test_char - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "gen_test_char.mak" CFG="gen_test_char - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "gen_test_char - Win32 Release" (based on\ - "Win32 (x86) Console Application") -!MESSAGE "gen_test_char - Win32 Debug" (based on\ - "Win32 (x86) Console Application") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "gen_test_char - Win32 Release" - -OUTDIR=. -INTDIR=.\Release -# Begin Custom Macros -OutDir=. -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\gen_test_char.exe" - -!ELSE - -ALL : "aprutil - Win32 Release" "apr - Win32 Release"\ - "$(OUTDIR)\gen_test_char.exe" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"apr - Win32 ReleaseCLEAN" "aprutil - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\gen_test_char.idb" - -@erase "$(INTDIR)\gen_test_char.obj" - -@erase "$(OUTDIR)\gen_test_char.exe" - -"$(INTDIR)" : - if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /I "..\include" /I "..\srclib\apr\include" /I\ - "..\srclib\apr-util\include" /I "..\os\win32" /D "WIN32" /D "NDEBUG" /D\ - "_CONSOLE" /D "_MBCS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\gen_test_char" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\gen_test_char.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:console /incremental:no\ - /pdb:"$(OUTDIR)\Release\gen_test_char.pdb" /machine:I386\ - /out:"$(OUTDIR)\gen_test_char.exe" -LINK32_OBJS= \ - "$(INTDIR)\gen_test_char.obj" \ - "..\srclib\apr-util\LibR\aprutil.lib" \ - "..\srclib\apr\LibR\apr.lib" - -"$(OUTDIR)\gen_test_char.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "gen_test_char - Win32 Debug" - -OUTDIR=. -INTDIR=.\Debug -# Begin Custom Macros -OutDir=. -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\gen_test_char.exe" - -!ELSE - -ALL : "aprutil - Win32 Debug" "apr - Win32 Debug" "$(OUTDIR)\gen_test_char.exe" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"apr - Win32 DebugCLEAN" "aprutil - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\gen_test_char.idb" - -@erase "$(INTDIR)\gen_test_char.obj" - -@erase "$(OUTDIR)\Debug\gen_test_char.pdb" - -@erase "$(OUTDIR)\gen_test_char.exe" - -"$(INTDIR)" : - if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /I "..\include" /I\ - "..\srclib\apr\include" /I "..\srclib\apr-util\include" /I "..\os\win32" /D\ - "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fo"$(INTDIR)\\"\ - /Fd"$(INTDIR)\gen_test_char" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\gen_test_char.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:console /incremental:no\ - /pdb:"$(OUTDIR)\Debug\gen_test_char.pdb" /debug /machine:I386\ - /out:"$(OUTDIR)\gen_test_char.exe" -LINK32_OBJS= \ - "$(INTDIR)\gen_test_char.obj" \ - "..\srclib\apr-util\LibD\aprutil.lib" \ - "..\srclib\apr\LibD\apr.lib" - -"$(OUTDIR)\gen_test_char.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "gen_test_char - Win32 Release" || "$(CFG)" ==\ - "gen_test_char - Win32 Debug" - -!IF "$(CFG)" == "gen_test_char - Win32 Release" - -"apr - Win32 Release" : - cd "..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\apr.mak CFG="apr - Win32 Release" - cd "..\..\server" - -"apr - Win32 ReleaseCLEAN" : - cd "..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\apr.mak CFG="apr - Win32 Release" RECURSE=1\ - - cd "..\..\server" - -!ELSEIF "$(CFG)" == "gen_test_char - Win32 Debug" - -"apr - Win32 Debug" : - cd "..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F .\apr.mak CFG="apr - Win32 Debug" - cd "..\..\server" - -"apr - Win32 DebugCLEAN" : - cd "..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) CLEAN /F .\apr.mak CFG="apr - Win32 Debug" RECURSE=1 - cd "..\..\server" - -!ENDIF - -!IF "$(CFG)" == "gen_test_char - Win32 Release" - -"aprutil - Win32 Release" : - cd "..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Release" - cd "..\..\server" - -"aprutil - Win32 ReleaseCLEAN" : - cd "..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\aprutil.mak" CFG="aprutil - Win32 Release"\ - RECURSE=1 - cd "..\..\server" - -!ELSEIF "$(CFG)" == "gen_test_char - Win32 Debug" - -"aprutil - Win32 Debug" : - cd "..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\aprutil.mak" CFG="aprutil - Win32 Debug" - cd "..\..\server" - -"aprutil - Win32 DebugCLEAN" : - cd "..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) CLEAN /F ".\aprutil.mak" CFG="aprutil - Win32 Debug"\ - RECURSE=1 - cd "..\..\server" - -!ENDIF - -SOURCE=.\gen_test_char.c -DEP_CPP_GEN_T=\ - "..\include\ap_config.h"\ - "..\include\ap_mmn.h"\ - "..\include\ap_release.h"\ - "..\include\httpd.h"\ - "..\include\pcreposix.h"\ - "..\include\util_uri.h"\ - "..\os\win32\os.h"\ - "..\srclib\apr-util\include\apr_hooks.h"\ - "..\srclib\apr-util\include\apu.h"\ - "..\srclib\apr\include\apr.h"\ - "..\srclib\apr\include\apr_errno.h"\ - "..\srclib\apr\include\apr_file_info.h"\ - "..\srclib\apr\include\apr_file_io.h"\ - "..\srclib\apr\include\apr_general.h"\ - "..\srclib\apr\include\apr_lib.h"\ - "..\srclib\apr\include\apr_network_io.h"\ - "..\srclib\apr\include\apr_pools.h"\ - "..\srclib\apr\include\apr_tables.h"\ - "..\srclib\apr\include\apr_time.h"\ - "..\srclib\apr\include\apr_user.h"\ - "..\srclib\apr\include\apr_want.h"\ - -NODEP_CPP_GEN_T=\ - "..\include\ap_config_auto.h"\ - - -"$(INTDIR)\gen_test_char.obj" : $(SOURCE) $(DEP_CPP_GEN_T) "$(INTDIR)" - - - -!ENDIF - diff --git a/server/gen_uri_delims.c b/server/gen_uri_delims.c deleted file mode 100644 index df82916083..0000000000 --- a/server/gen_uri_delims.c +++ /dev/null @@ -1,89 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include <stdio.h> - -/* generate a apr_table_t of 256 values, where certain characters are - * marked "interesting"... for the uri parsing process. - */ - -int main(int argc, char *argv[]) -{ - int i; - char *value; - - printf("/* this file is automatically generated by " - "gen_uri_delims, do not edit */\n"); - printf("static const unsigned char uri_delims[256] = {"); - for (i = 0; i < 256; ++i) { - if (i % 20 == 0) - printf("\n "); - switch (i) { - case ':': value = "T_COLON"; break; - case '/': value = "T_SLASH"; break; - case '?': value = "T_QUESTION"; break; - case '#': value = "T_HASH"; break; - case '\0': value = "T_NUL"; break; - default: value = "0"; break; - } - printf("%s%c", value, (i < 255) ? ',' : ' '); - } - printf("\n};\n"); - - return 0; -} diff --git a/server/gen_uri_delims.dsp b/server/gen_uri_delims.dsp deleted file mode 100644 index fafe5bfea0..0000000000 --- a/server/gen_uri_delims.dsp +++ /dev/null @@ -1,90 +0,0 @@ -# Microsoft Developer Studio Project File - Name="gen_uri_delims" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Console Application" 0x0103 - -CFG=gen_uri_delims - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "gen_uri_delims.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "gen_uri_delims.mak" CFG="gen_uri_delims - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "gen_uri_delims - Win32 Release" (based on "Win32 (x86) Console Application") -!MESSAGE "gen_uri_delims - Win32 Debug" (based on "Win32 (x86) Console Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -RSC=rc.exe - -!IF "$(CFG)" == "gen_uri_delims - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fd"Release\gen_uri_delims" /FD /c -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:console /incremental:no /pdb:"Release\gen_uri_delims.pdb" /machine:I386 -# ADD LINK32 kernel32.lib /nologo /subsystem:console /incremental:no /pdb:"Release\gen_uri_delims.pdb" /machine:I386 - -!ELSEIF "$(CFG)" == "gen_uri_delims - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fd"Debug\gen_uri_delims" /FD /c -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:console /incremental:no /pdb:"Debug\gen_uri_delims.pdb" /debug /machine:I386 -# ADD LINK32 kernel32.lib /nologo /subsystem:console /incremental:no /pdb:"Debug\gen_uri_delims.pdb" /debug /machine:I386 - -!ENDIF - -# Begin Target - -# Name "gen_uri_delims - Win32 Release" -# Name "gen_uri_delims - Win32 Debug" -# Begin Source File - -SOURCE=.\gen_uri_delims.c -# End Source File -# End Target -# End Project diff --git a/server/gen_uri_delims.mak b/server/gen_uri_delims.mak deleted file mode 100644 index 5084add7e0..0000000000 --- a/server/gen_uri_delims.mak +++ /dev/null @@ -1,203 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on gen_uri_delims.dsp -!IF "$(CFG)" == "" -CFG=gen_uri_delims - Win32 Debug -!MESSAGE No configuration specified. Defaulting to gen_uri_delims - Win32\ - Debug. -!ENDIF - -!IF "$(CFG)" != "gen_uri_delims - Win32 Release" && "$(CFG)" !=\ - "gen_uri_delims - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "gen_uri_delims.mak" CFG="gen_uri_delims - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "gen_uri_delims - Win32 Release" (based on\ - "Win32 (x86) Console Application") -!MESSAGE "gen_uri_delims - Win32 Debug" (based on\ - "Win32 (x86) Console Application") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "gen_uri_delims - Win32 Release" - -OUTDIR=. -INTDIR=.\Release -# Begin Custom Macros -OutDir=. -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\gen_uri_delims.exe" - -!ELSE - -ALL : "$(OUTDIR)\gen_uri_delims.exe" - -!ENDIF - -CLEAN : - -@erase "$(INTDIR)\gen_uri_delims.idb" - -@erase "$(INTDIR)\gen_uri_delims.obj" - -@erase "$(OUTDIR)\gen_uri_delims.exe" - -"$(INTDIR)" : - if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS"\ - /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\gen_uri_delims" /FD /c -CPP_OBJS=.\Release/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\gen_uri_delims.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:console /incremental:no\ - /pdb:"$(OUTDIR)\Release\gen_uri_delims.pdb" /machine:I386\ - /out:"$(OUTDIR)\gen_uri_delims.exe" -LINK32_OBJS= \ - "$(INTDIR)\gen_uri_delims.obj" - -"$(OUTDIR)\gen_uri_delims.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ELSEIF "$(CFG)" == "gen_uri_delims - Win32 Debug" - -OUTDIR=. -INTDIR=.\Debug -# Begin Custom Macros -OutDir=. -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\gen_uri_delims.exe" - -!ELSE - -ALL : "$(OUTDIR)\gen_uri_delims.exe" - -!ENDIF - -CLEAN : - -@erase "$(INTDIR)\gen_uri_delims.idb" - -@erase "$(INTDIR)\gen_uri_delims.obj" - -@erase "$(OUTDIR)\Debug\gen_uri_delims.pdb" - -@erase "$(OUTDIR)\gen_uri_delims.exe" - -"$(INTDIR)" : - if not exist "$(INTDIR)/$(NULL)" mkdir "$(INTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D\ - "_MBCS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\gen_uri_delims" /FD /c -CPP_OBJS=.\Debug/ -CPP_SBRS=. - -.c{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_OBJS)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(CPP_SBRS)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -RSC=rc.exe -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\gen_uri_delims.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:console /incremental:no\ - /pdb:"$(OUTDIR)\Debug\gen_uri_delims.pdb" /debug /machine:I386\ - /out:"$(OUTDIR)\gen_uri_delims.exe" -LINK32_OBJS= \ - "$(INTDIR)\gen_uri_delims.obj" - -"$(OUTDIR)\gen_uri_delims.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -!ENDIF - - -!IF "$(CFG)" == "gen_uri_delims - Win32 Release" || "$(CFG)" ==\ - "gen_uri_delims - Win32 Debug" -SOURCE=.\gen_uri_delims.c - -"$(INTDIR)\gen_uri_delims.obj" : $(SOURCE) "$(INTDIR)" - - - -!ENDIF - diff --git a/server/listen.c b/server/listen.c deleted file mode 100644 index a525de09ba..0000000000 --- a/server/listen.c +++ /dev/null @@ -1,390 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr_network_io.h" -#include "apr_strings.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "ap_listen.h" -#include "http_log.h" -#include "mpm.h" -#include "mpm_common.h" - - -ap_listen_rec *ap_listeners; -#if APR_HAVE_IPV6 -static int default_family = APR_UNSPEC; -#else -static int default_family = APR_INET; -#endif -static ap_listen_rec *old_listeners; -static int ap_listenbacklog; -static int send_buffer_size; - -/* TODO: make_sock is just begging and screaming for APR abstraction */ -static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) -{ - apr_socket_t *s = server->sd; - int one = 1; - apr_status_t stat; - - stat = apr_setsocketopt(s, APR_SO_REUSEADDR, one); - if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, - "make_sock: for address %pI, setsockopt: (SO_REUSEADDR)", - server->bind_addr); - apr_socket_close(s); - return stat; - } - - stat = apr_setsocketopt(s, APR_SO_KEEPALIVE, one); - if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, - "make_sock: for address %pI, setsockopt: (SO_KEEPALIVE)", - server->bind_addr); - apr_socket_close(s); - return stat; - } - - /* - * 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 <johnh@isi.edu> 25-Oct-96 - * - * If no size is specified, use the kernel default. - */ - if (send_buffer_size) { - stat = apr_setsocketopt(s, APR_SO_SNDBUF, send_buffer_size); - if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { - ap_log_perror(APLOG_MARK, APLOG_WARNING, stat, p, - "make_sock: failed to set SendBufferSize for " - "address %pI, using default", - server->bind_addr); - /* not a fatal error */ - } - } - -#if APR_TCP_NODELAY_INHERITED - ap_sock_disable_nagle(s); -#endif - - if ((stat = apr_bind(s, server->bind_addr)) != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, - "make_sock: could not bind to address %pI", - server->bind_addr); - apr_socket_close(s); - return stat; - } - - if ((stat = apr_listen(s, ap_listenbacklog)) != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_ERR, stat, p, - "make_sock: unable to listen for connections on address %pI", - server->bind_addr); - apr_socket_close(s); - return stat; - } - -#ifdef APR_HAS_SO_ACCEPTFILTER -#ifndef ACCEPT_FILTER_NAME -#define ACCEPT_FILTER_NAME "dataready" -#endif - apr_socket_accept_filter(s, ACCEPT_FILTER_NAME, ""); -#endif - - server->sd = s; - server->active = 1; - return APR_SUCCESS; -} - -static apr_status_t close_listeners_on_exec(void *v) -{ - ap_listen_rec *lr; - - for (lr = ap_listeners; lr; lr = lr->next) { - apr_socket_close(lr->sd); - lr->active = 0; - } - return APR_SUCCESS; -} - - -static void find_default_family(apr_pool_t *p) -{ -#if APR_HAVE_IPV6 - /* We know the platform supports IPv6, but this particular - * system may not have IPv6 enabled. See if we can get an - * AF_INET6 socket. - */ - if (default_family == APR_UNSPEC) { - apr_socket_t *tmp_sock; - - if (apr_socket_create(&tmp_sock, APR_INET6, SOCK_STREAM, - p) == APR_SUCCESS) { - apr_socket_close(tmp_sock); - default_family = APR_INET6; - } - else { - default_family = APR_INET; - } - } -#endif -} - - -static void alloc_listener(process_rec *process, char *addr, apr_port_t port) -{ - ap_listen_rec **walk; - ap_listen_rec *new; - apr_status_t status; - char *oldaddr; - apr_port_t oldport; - apr_sockaddr_t *sa; - - if (!addr) { /* don't bind to specific interface */ - find_default_family(process->pool); - switch(default_family) { - case APR_INET: - addr = "0.0.0.0"; - break; -#if APR_HAVE_IPV6 - case APR_INET6: - addr = "::"; - break; -#endif - default: - ap_assert(1 != 1); /* should not occur */ - } - } - - /* see if we've got an old listener for this address:port */ - for (walk = &old_listeners; *walk; walk = &(*walk)->next) { - sa = (*walk)->bind_addr; - apr_sockaddr_port_get(&oldport, sa); - apr_sockaddr_ip_get(&oldaddr, sa); - if (!strcmp(oldaddr, addr) && port == oldport) { - /* re-use existing record */ - new = *walk; - *walk = new->next; - new->next = ap_listeners; - ap_listeners = new; - return; - } - } - - /* this has to survive restarts */ - new = apr_palloc(process->pool, sizeof(ap_listen_rec)); - new->active = 0; - if ((status = apr_sockaddr_info_get(&new->bind_addr, addr, APR_UNSPEC, port, 0, - process->pool)) != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool, - "alloc_listener: failed to set up sockaddr for %s", addr); - return; - } - if ((status = apr_socket_create(&new->sd, new->bind_addr->sa.sin.sin_family, - SOCK_STREAM, process->pool)) != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool, - "alloc_listener: failed to get a socket for %s", addr); - return; - } - new->next = ap_listeners; - ap_listeners = new; -} - -#if !defined(SPMT_OS2_MPM) -static -#endif -int ap_listen_open(process_rec *process, apr_port_t port) -{ - apr_pool_t *pconf = process->pconf; - ap_listen_rec *lr; - ap_listen_rec *next; - int num_open; - - /* allocate a default listener if necessary */ - if (ap_listeners == NULL) { - alloc_listener(process, NULL, port ? port : DEFAULT_HTTP_PORT); - } - - num_open = 0; - for (lr = ap_listeners; lr; lr = lr->next) { - if (lr->active) { - ++num_open; - } - else { - if (make_sock(pconf, lr) == APR_SUCCESS) { - ++num_open; - lr->active = 1; - } - } - } - - /* close the old listeners */ - for (lr = old_listeners; lr; lr = next) { - apr_socket_close(lr->sd); - lr->active = 0; - next = lr->next; -/* free(lr);*/ - } - old_listeners = NULL; - - apr_pool_cleanup_register(pconf, NULL, apr_pool_cleanup_null, close_listeners_on_exec); - - return num_open ? 0 : -1; -} - -int ap_setup_listeners(server_rec *s) -{ - ap_listen_rec *lr; - int num_listeners = 0; - if (ap_listen_open(s->process, s->port)) { - return 0; - } - for (lr = ap_listeners; lr; lr = lr->next) { - num_listeners++; - } - return num_listeners; -} - -void ap_listen_pre_config(void) -{ - old_listeners = ap_listeners; - ap_listeners = NULL; - ap_listenbacklog = DEFAULT_LISTENBACKLOG; -} - - -const char *ap_set_listener(cmd_parms *cmd, void *dummy, const char *ips) -{ - char *host, *scope_id; - apr_port_t port; - apr_status_t rv; - - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - rv = apr_parse_addr_port(&host, &scope_id, &port, ips, cmd->pool); - if (rv != APR_SUCCESS) { - return "Invalid address or port"; - } - if (host && !strcmp(host, "*")) { - host = NULL; - } - if (scope_id) { - /* XXX scope id support is useful with link-local IPv6 addresses */ - return "Scope id is not supported"; - } - if (!port) { - return "Port must be specified"; - } - - alloc_listener(cmd->server->process, host, port); - - return NULL; -} - -const char *ap_set_listenbacklog(cmd_parms *cmd, void *dummy, const 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; -} - -const char *ap_set_send_buffer_size(cmd_parms *cmd, void *dummy, const 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."; - } - send_buffer_size = s; - return NULL; -} diff --git a/server/log.c b/server/log.c deleted file mode 100644 index 4ba0b4c6f3..0000000000 --- a/server/log.c +++ /dev/null @@ -1,753 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_log.c: Dealing with the logs and errors - * - * Rob McCool - * - */ - -#include "apr.h" -#include "apr_general.h" /* for signal stuff */ -#include "apr_strings.h" -#include "apr_errno.h" -#include "apr_thread_proc.h" -#include "apr_lib.h" -#include "apr_signal.h" - -#define APR_WANT_STDIO -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_STDARG_H -#include <stdarg.h> -#endif -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_log.h" -#include "http_main.h" - -typedef struct { - char *t_name; - int t_val; -} TRANS; - -#ifdef HAVE_SYSLOG - -static const TRANS facilities[] = { - {"auth", LOG_AUTH}, -#ifdef LOG_AUTHPRIV - {"authpriv",LOG_AUTHPRIV}, -#endif -#ifdef LOG_CRON - {"cron", LOG_CRON}, -#endif -#ifdef LOG_DAEMON - {"daemon", LOG_DAEMON}, -#endif -#ifdef LOG_FTP - {"ftp", LOG_FTP}, -#endif -#ifdef LOG_KERN - {"kern", LOG_KERN}, -#endif -#ifdef LOG_LPR - {"lpr", LOG_LPR}, -#endif -#ifdef LOG_MAIL - {"mail", LOG_MAIL}, -#endif -#ifdef LOG_NEWS - {"news", LOG_NEWS}, -#endif -#ifdef LOG_SYSLOG - {"syslog", LOG_SYSLOG}, -#endif -#ifdef LOG_USER - {"user", LOG_USER}, -#endif -#ifdef LOG_UUCP - {"uucp", LOG_UUCP}, -#endif -#ifdef LOG_LOCAL0 - {"local0", LOG_LOCAL0}, -#endif -#ifdef LOG_LOCAL1 - {"local1", LOG_LOCAL1}, -#endif -#ifdef LOG_LOCAL2 - {"local2", LOG_LOCAL2}, -#endif -#ifdef LOG_LOCAL3 - {"local3", LOG_LOCAL3}, -#endif -#ifdef LOG_LOCAL4 - {"local4", LOG_LOCAL4}, -#endif -#ifdef LOG_LOCAL5 - {"local5", LOG_LOCAL5}, -#endif -#ifdef LOG_LOCAL6 - {"local6", LOG_LOCAL6}, -#endif -#ifdef LOG_LOCAL7 - {"local7", LOG_LOCAL7}, -#endif - {NULL, -1}, -}; -#endif - -static const TRANS priorities[] = { - {"emerg", APLOG_EMERG}, - {"alert", APLOG_ALERT}, - {"crit", APLOG_CRIT}, - {"error", APLOG_ERR}, - {"warn", APLOG_WARNING}, - {"notice", APLOG_NOTICE}, - {"info", APLOG_INFO}, - {"debug", APLOG_DEBUG}, - {NULL, -1}, -}; - -static apr_file_t *stderr_log; - -AP_DECLARE(void) ap_open_stderr_log(apr_pool_t *p) -{ - apr_file_open_stderr(&stderr_log, p); -} - -static int log_child(apr_pool_t *p, const char *progname, - apr_file_t **fpin) -{ - /* Child process code for 'ErrorLog "|..."'; - * may want a common framework for this, since I expect it will - * be common for other foo-loggers to want this sort of thing... - */ - apr_status_t rc; - apr_procattr_t *procattr; - apr_proc_t *procnew; - -#ifdef SIGHUP - /* No concept of a child process on Win32 */ - apr_signal(SIGHUP, SIG_IGN); -#endif /* ndef SIGHUP */ - - if (((rc = apr_procattr_create(&procattr, p)) == APR_SUCCESS) && - ((rc = apr_procattr_io_set(procattr, - APR_FULL_BLOCK, - APR_NO_PIPE, - APR_NO_PIPE)) == APR_SUCCESS)) { - char **args; - const char *pname; - - apr_tokenize_to_argv(progname, &args, p); - pname = apr_pstrdup(p, args[0]); - procnew = (apr_proc_t *) apr_pcalloc(p, sizeof(*procnew)); - rc = apr_proc_create(procnew, pname, (const char * const *)args, - NULL, procattr, p); - - if (rc == APR_SUCCESS) { - apr_pool_note_subprocess(p, procnew, kill_after_timeout); - (*fpin) = procnew->in; - } - } - - return(rc); -} - -static void open_error_log(server_rec *s, apr_pool_t *p) -{ - const char *fname; - int rc; - - if (*s->error_fname == '|') { - apr_file_t *dummy = NULL; - - /* This starts a new process... */ - rc = log_child (p, s->error_fname+1, &dummy); - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, - "Couldn't start ErrorLog process"); - exit(1); - } - - s->error_log = dummy; - } - -#ifdef HAVE_SYSLOG - else if (!strncasecmp(s->error_fname, "syslog", 6)) { - if ((fname = strchr(s->error_fname, ':'))) { - const TRANS *fac; - - fname++; - for (fac = facilities; fac->t_name; fac++) { - if (!strcasecmp(fname, fac->t_name)) { - openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID, - fac->t_val); - s->error_log = NULL; - return; - } - } - } - else - openlog(ap_server_argv0, LOG_NDELAY|LOG_CONS|LOG_PID, LOG_LOCAL7); - - s->error_log = NULL; - } -#endif - else { - fname = ap_server_root_relative(p, s->error_fname); - rc = apr_file_open(&s->error_log, fname, - APR_APPEND | APR_READ | APR_WRITE | APR_CREATE, - APR_OS_DEFAULT, p); - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, - "%s: could not open error log file %s.", - ap_server_argv0, fname); - exit(1); - } - } -} - -void ap_open_logs(server_rec *s_main, apr_pool_t *p) -{ - apr_status_t rc = APR_SUCCESS; - server_rec *virt, *q; - int replace_stderr; - apr_file_t *errfile = NULL; - - open_error_log(s_main, p); - - replace_stderr = 1; - if (s_main->error_log) { - /* replace stderr with this new log */ - apr_file_flush(s_main->error_log); - apr_file_open_stderr(&errfile, p); - if ((rc = apr_file_dup(&errfile, s_main->error_log, p)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rc, s_main, - "unable to replace stderr with error_log"); - } else { - replace_stderr = 0; - } - } - /* note that stderr may still need to be replaced with something - * because it points to the old error log, or back to the tty - * of the submitter. - */ - if (replace_stderr && freopen("/dev/null", "w", stderr) == NULL) { - ap_log_error(APLOG_MARK, APLOG_CRIT, errno, s_main, - "unable to replace stderr with /dev/null"); - } - - for (virt = s_main->next; virt; virt = virt->next) { - if (virt->error_fname) { - for (q=s_main; q != virt; q = q->next) - if (q->error_fname != NULL && - strcmp(q->error_fname, virt->error_fname) == 0) - break; - if (q == virt) - open_error_log(virt, p); - else - virt->error_log = q->error_log; - } - else - virt->error_log = s_main->error_log; - } -} - -AP_DECLARE(void) ap_error_log2stderr(server_rec *s) { - apr_file_t *errfile = NULL; - - apr_file_open_stderr(&errfile, s->process->pool); - if (s->error_log != NULL) { - apr_file_dup(&(s->error_log), errfile, s->process->pool); - } -} - -static void log_error_core(const char *file, int line, int level, - apr_status_t status, const server_rec *s, - const request_rec *r, apr_pool_t *pool, - const char *fmt, va_list args) -{ - char errstr[MAX_STRING_LEN]; - size_t len; - apr_file_t *logf = NULL; - const char *referer; - int level_and_mask = level & APLOG_LEVELMASK; - - if (s == NULL) { - /* - * If we are doing stderr logging (startup), don't log messages that are - * above the default server log level unless it is a startup/shutdown - * notice - */ - if ((level_and_mask != APLOG_NOTICE) && - (level_and_mask > DEFAULT_LOGLEVEL)) - return; - logf = stderr_log; - } - else if (s->error_log) { - /* - * If we are doing normal logging, don't log messages that are - * above the server log level unless it is a startup/shutdown notice - */ - if ((level_and_mask != APLOG_NOTICE) && - (level_and_mask > s->loglevel)) - return; - logf = s->error_log; - } -#ifdef TPF - else if (tpf_child) { - /* - * If we are doing normal logging, don't log messages that are - * above the server log level unless it is a startup/shutdown notice - */ - if ((level_and_mask != APLOG_NOTICE) && - (level_and_mask > s->loglevel)) - return; - logf = stderr; - } -#endif /* TPF */ - else { - /* - * If we are doing syslog logging, don't log messages that are - * above the server log level (including a startup/shutdown notice) - */ - if (level_and_mask > s->loglevel) - return; - } - - if (logf && ((level & APLOG_STARTUP) != APLOG_STARTUP)) { - errstr[0] = '['; - apr_ctime(errstr + 1, apr_time_now()); - errstr[1 + APR_CTIME_LEN - 1] = ']'; - errstr[1 + APR_CTIME_LEN ] = ' '; - len = 1 + APR_CTIME_LEN + 1; - } else { - len = 0; - } - - if ((level & APLOG_STARTUP) != APLOG_STARTUP) { - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "[%s] ", priorities[level_and_mask].t_name); - } -#ifndef TPF - if (file && level_and_mask == APLOG_DEBUG) { -#ifdef _OSD_POSIX - char tmp[256]; - char *e = strrchr(file, '/'); - - /* In OSD/POSIX, the compiler returns for __FILE__ - * a string like: __FILE__="*POSIX(/usr/include/stdio.h)" - * (it even returns an absolute path for sources in - * the current directory). Here we try to strip this - * down to the basename. - */ - if (e != NULL && e[1] != '\0') { - apr_snprintf(tmp, sizeof(tmp), "%s", &e[1]); - e = &tmp[strlen(tmp)-1]; - if (*e == ')') - *e = '\0'; - file = tmp; - } -#endif /*_OSD_POSIX*/ - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "%s(%d): ", file, line); - } -#endif /* TPF */ - if (r && r->connection) { - /* XXX: TODO: add a method of selecting whether logged client - * addresses are in dotted quad or resolved form... dotted - * quad is the most secure, which is why I'm implementing it - * first. -djg - */ - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "[client %s] ", r->connection->remote_ip); - } - if (!(level & APLOG_NOERRNO) - && (status != 0)) { - char buf[120]; - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - "(%d)%s: ", status, apr_strerror(status, buf, sizeof(buf))); - } - len += apr_vsnprintf(errstr + len, MAX_STRING_LEN - len, fmt, args); - - if (r && (referer = apr_table_get(r->headers_in, "Referer"))) { - len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - ", referer: %s", referer); - } - - /* NULL if we are logging to syslog */ - if (logf) { - /* Truncate for the terminator (as apr_snprintf does) */ - if (len > MAX_STRING_LEN - sizeof(APR_EOL_STR)) - len = MAX_STRING_LEN - sizeof(APR_EOL_STR); - strcpy(errstr + len, APR_EOL_STR); - apr_file_puts(errstr, logf); - apr_file_flush(logf); - } -#ifdef HAVE_SYSLOG - else { - syslog(level_and_mask, "%s", errstr); - } -#endif -} - -AP_DECLARE(void) ap_log_error(const char *file, int line, int level, - apr_status_t status, const server_rec *s, - const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - log_error_core(file, line, level, status, s, NULL, NULL, fmt, args); - va_end(args); -} - -AP_DECLARE(void) ap_log_perror(const char *file, int line, int level, - apr_status_t status, apr_pool_t *p, - const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - log_error_core(file, line, level, status, NULL, NULL, p, fmt, args); - va_end(args); -} - -AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level, - apr_status_t status, const request_rec *r, - const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - log_error_core(file, line, level, status, r->server, r, NULL, fmt, args); - /* - * IF the error level is 'warning' or more severe, - * AND there isn't already error text associated with this request, - * THEN make the message text available to ErrorDocument and - * other error processors. This can be disabled by stuffing - * something, even an empty string, into the "error-notes" cell - * before calling this routine. - */ - va_end(args); - va_start(args,fmt); - if (((level & APLOG_LEVELMASK) <= APLOG_WARNING) - && (apr_table_get(r->notes, "error-notes") == NULL)) { - apr_table_setn(r->notes, "error-notes", - ap_escape_html(r->pool, apr_pvsprintf(r->pool, fmt, - args))); - } - va_end(args); -} - -void ap_log_pid(apr_pool_t *p, const char *fname) -{ - apr_file_t *pid_file = NULL; - apr_finfo_t finfo; - static pid_t saved_pid = -1; - pid_t mypid; - apr_status_t rv; - - if (!fname) - return; - - fname = ap_server_root_relative(p, fname); - mypid = getpid(); - if (mypid != saved_pid - && apr_stat(&finfo, fname, APR_FINFO_MTIME, p) == APR_SUCCESS) { - /* WINCH and HUP call this on each restart. - * Only warn on first time through for this pid. - * - * XXX: Could just write first time through too, although - * that may screw up scripts written to do something - * based on the last modification time of the pid file. - */ - ap_log_perror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, p, - apr_psprintf(p, - "pid file %s overwritten -- Unclean shutdown of previous Apache run?", - fname) - ); - } - - if ((rv = apr_file_open(&pid_file, fname, APR_WRITE | APR_CREATE | APR_TRUNCATE, - APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD, p)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "could not create %s", fname); - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, NULL, - "%s: could not log pid to file %s", - ap_server_argv0, fname); - exit(1); - } - apr_file_printf(pid_file, "%ld" APR_EOL_STR, (long)mypid); - apr_file_close(pid_file); - saved_pid = mypid; -} - -AP_DECLARE(void) ap_log_assert(const char *szExp, const char *szFile, int nLine) -{ - char time_str[APR_CTIME_LEN]; - - apr_ctime(time_str, apr_time_now()); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "[%s] file %s, line %d, assertion \"%s\" failed", - time_str, szFile, nLine, szExp); -#ifndef WIN32 - /* unix assert does an abort leading to a core dump */ - abort(); -#else - exit(1); -#endif -} - -/* piped log support */ - -#ifdef AP_HAVE_RELIABLE_PIPED_LOGS -/* forward declaration */ -static void piped_log_maintenance(int reason, void *data, apr_wait_t status); - -static int piped_log_spawn(piped_log *pl) -{ - int rc; - apr_procattr_t *procattr; - apr_proc_t *procnew = NULL; - apr_status_t status; - -#ifdef SIGHUP - apr_signal(SIGHUP, SIG_IGN); -#endif - if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) || - ((status = apr_procattr_child_in_set(procattr, ap_piped_log_read_fd(pl), - ap_piped_log_write_fd(pl))) != APR_SUCCESS)) { - char buf[120]; - /* Something bad happened, give up and go away. */ - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "piped_log_spawn: unable to setup child process '%s': %s", - pl->program, apr_strerror(status, buf, sizeof(buf))); - rc = -1; - } - else { - char **args; - const char *pname; - - apr_tokenize_to_argv(pl->program, &args, pl->p); - pname = apr_pstrdup(pl->p, args[0]); - procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t)); - rc = apr_proc_create(procnew, pname, (const char * const *) args, - NULL, procattr, pl->p); - - if (rc == APR_SUCCESS) { - /* pjr - This no longer happens inside the child, */ - /* I am assuming that if apr_proc_create was */ - /* successful that the child is running. */ - RAISE_SIGSTOP(PIPED_LOG_SPAWN); - pl->pid = procnew; - ap_piped_log_write_fd(pl) = procnew->in; - apr_proc_other_child_register(procnew, piped_log_maintenance, pl, - ap_piped_log_write_fd(pl), pl->p); - } - } - - return 0; -} - - -static void piped_log_maintenance(int reason, void *data, apr_wait_t status) -{ - piped_log *pl = data; - apr_status_t stats; - - switch (reason) { - case APR_OC_REASON_DEATH: - pl->pid = NULL; - apr_proc_other_child_unregister(pl); - if (pl->program == NULL) { - /* during a restart */ - break; - } - break; - case APR_OC_REASON_LOST: - pl->pid = NULL; - apr_proc_other_child_unregister(pl); - if (pl->program == NULL) { - /* during a restart */ - break; - } - if ((stats = piped_log_spawn(pl)) != APR_SUCCESS) { - /* what can we do? This could be the error log we're having - * problems opening up... */ - char buf[120]; - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "piped_log_maintenance: unable to respawn '%s': %s", - pl->program, apr_strerror(stats, buf, sizeof(buf))); - } - break; - - case APR_OC_REASON_UNWRITABLE: - /* We should not kill off the pipe here, since it may only be full. - * If it really is locked, we should kill it off manually. */ - break; - - case APR_OC_REASON_RESTART: - pl->program = NULL; - if (pl->pid != NULL) { - apr_proc_kill(pl->pid, SIGTERM); - } - break; - - case APR_OC_REASON_UNREGISTER: - break; - } -} - - -static apr_status_t piped_log_cleanup(void *data) -{ - piped_log *pl = data; - - if (pl->pid != NULL) { - apr_proc_kill(pl->pid, SIGTERM); - } - apr_proc_other_child_unregister(pl); - apr_file_close(ap_piped_log_read_fd(pl)); - apr_file_close(ap_piped_log_write_fd(pl)); - return APR_SUCCESS; -} - - -static apr_status_t piped_log_cleanup_for_exec(void *data) -{ - piped_log *pl = data; - - apr_file_close(ap_piped_log_read_fd(pl)); - apr_file_close(ap_piped_log_write_fd(pl)); - return APR_SUCCESS; -} - -AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program) -{ - piped_log *pl; - - pl = apr_palloc(p, sizeof (*pl)); - pl->p = p; - pl->program = apr_pstrdup(p, program); - pl->pid = NULL; - if (apr_file_pipe_create(&ap_piped_log_read_fd(pl), &ap_piped_log_write_fd(pl), p) != APR_SUCCESS) { - return NULL; - } - apr_pool_cleanup_register(p, pl, piped_log_cleanup, piped_log_cleanup_for_exec); - if (piped_log_spawn(pl) == -1) { - int save_errno = errno; - apr_pool_cleanup_kill(p, pl, piped_log_cleanup); - apr_file_close(ap_piped_log_read_fd(pl)); - apr_file_close(ap_piped_log_write_fd(pl)); - errno = save_errno; - return NULL; - } - return pl; -} - -#else /* !AP_HAVE_RELIABLE_PIPED_LOGS */ - -static apr_status_t piped_log_cleanup(void *data) -{ - piped_log *pl = data; - - apr_file_close(ap_piped_log_write_fd(pl)); - return APR_SUCCESS; -} - -AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program) -{ - piped_log *pl; - apr_file_t *dummy = NULL; - int rc; - - rc = log_child(p, program, &dummy); - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, - "Couldn't start piped log process"); - exit (1); - } - - pl = apr_palloc(p, sizeof (*pl)); - pl->p = p; - ap_piped_log_read_fd(pl) = NULL; - ap_piped_log_write_fd(pl) = dummy; - apr_pool_cleanup_register(p, pl, piped_log_cleanup, piped_log_cleanup); - - return pl; -} - -#endif - -AP_DECLARE(void) ap_close_piped_log(piped_log *pl) -{ - apr_pool_cleanup_run(pl->p, pl, piped_log_cleanup); -} - diff --git a/server/main.c b/server/main.c deleted file mode 100644 index ad71b60d2b..0000000000 --- a/server/main.c +++ /dev/null @@ -1,464 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_getopt.h" -#include "apr_general.h" -#include "apr_lib.h" - -#define APR_WANT_STDIO -#include "apr_want.h" - -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" -#include "http_vhost.h" -#include "util_uri.h" -#include "util_ebcdic.h" -#include "ap_mpm.h" - -/* WARNING: Win32 binds http_main.c dynamically to the server. Please place - * extern functions and global data in another appropriate module. - * - * Most significant main() global data can be found in http_config.c - */ - -/* XXX - We should be able to grab the per-MPM settings here too */ -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 APACHE_MPM_DIR - printf(" -D APACHE_MPM_DIR=\"%s\"\n", APACHE_MPM_DIR); -#endif -#ifdef HAVE_SHMGET - printf(" -D HAVE_SHMGET\n"); -#endif -#if APR_FILE_BASED_SHM - printf(" -D APR_FILE_BASED_SHM\n"); -#endif -#if APR_HAS_MMAP - printf(" -D APR_HAS_MMAP\n"); -#endif -#ifdef NO_WRITEV - printf(" -D NO_WRITEV\n"); -#endif -#ifdef NO_LINGCLOSE - printf(" -D NO_LINGCLOSE\n"); -#endif -#if APR_HAVE_IPV6 - printf(" -D APR_HAVE_IPV6\n"); -#endif -#if APR_USE_FLOCK_SERIALIZE - printf(" -D APR_USE_FLOCK_SERIALIZE\n"); -#endif -#if APR_USE_SYSVSEM_SERIALIZE - printf(" -D APR_USE_SYSVSEM_SERIALIZE\n"); -#endif -#if APR_USE_FCNTL_SERIALIZE - printf(" -D APR_USE_FCNTL_SERIALIZE\n"); -#endif -#if APR_USE_PROC_PTHREAD_SERIALIZE - printf(" -D APR_USE_PROC_PTHREAD_SERIALIZE\n"); -#endif -#if APR_USE_PTHREAD_SERIALIZE - printf(" -D APR_USE_PTHREAD_SERIALIZE\n"); -#endif -#if APR_PROCESS_LOCK_IS_GLOBAL - printf(" -D APR_PROCESS_LOCK_IS_GLOBAL\n"); -#endif -#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT - printf(" -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT\n"); -#endif -#if APR_HAS_OTHER_CHILD - printf(" -D APR_HAS_OTHER_CHILD\n"); -#endif -#ifdef AP_HAVE_RELIABLE_PIPED_LOGS - printf(" -D AP_HAVE_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 -#if APR_CHARSET_EBCDIC - printf(" -D APR_CHARSET_EBCDIC\n"); -#endif -#ifdef APACHE_XLATE - printf(" -D APACHE_XLATE\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_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 -} - -static void destroy_and_exit_process(process_rec *process, int process_exit_value) -{ - apr_pool_destroy(process->pool); /* and destroy all descendent pools */ - apr_terminate(); - exit(process_exit_value); -} - -static process_rec *create_process(int argc, const char * const *argv) -{ - process_rec *process; - apr_pool_t *cntx; - apr_status_t stat; - - stat = apr_pool_create(&cntx, NULL); - if (stat != APR_SUCCESS) { - /* XXX From the time that we took away the NULL pool->malloc mapping - * we have been unable to log here without segfaulting. - */ - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, NULL, - "apr_pool_create() failed to create " - "initial context"); - apr_terminate(); - exit(1); - } - - ap_open_stderr_log(cntx); - - process = apr_palloc(cntx, sizeof(process_rec)); - process->pool = cntx; - - apr_pool_create(&process->pconf, process->pool); - process->argc = argc; - process->argv = argv; - process->short_name = apr_filename_of_pathname(argv[0]); - return process; -} - -static void usage(process_rec *process) -{ - const char *bin = process->argv[0]; - char pad[MAX_STRING_LEN]; - unsigned i; - - for (i = 0; i < strlen(bin); i++) - pad[i] = ' '; - pad[i] = '\0'; -#ifdef SHARED_CORE - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0,NULL , "Usage: %s [-R directory] [-D name] [-d directory] [-f file]", bin); -#else - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Usage: %s [-D name] [-d directory] [-f file]", bin); -#endif - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " %s [-C \"directive\"] [-c \"directive\"]", pad); -#ifdef WIN32 - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " %s [-k restart|shutdown|start]", pad); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " %s [-n service_name]", pad); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " %s [-i] [-u]", pad); -#endif - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " %s [-v] [-V] [-h] [-l] [-L] [-t] [-T]", pad); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Options:"); -#ifdef SHARED_CORE - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -R directory : specify an alternate location for shared object files"); -#endif - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -D name : define a name for use in <IfDefine name> directives"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -d directory : specify an alternate initial ServerRoot"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -f file : specify an alternate ServerConfigFile"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -C \"directive\" : process directive before reading config files"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -c \"directive\" : process directive after reading config files"); -#ifdef WIN32 - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -n name : set service name and use its ServerConfigFile"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -k shutdown : tell running Apache to shutdown"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -k restart : tell running Apache to do a graceful restart"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -k start : tell Apache to start"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -i : install an Apache service"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -u : uninstall an Apache service"); -#endif - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -v : show version number"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -V : show compile settings"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -h : list available command line options (this page)"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -l : list compiled in modules"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -L : list available configuration directives"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -t -D DUMP_VHOSTS : show parsed settings (currently only vhost settings)"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -t : run syntax check for config files (with docroot check)"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, " -T : run syntax check for config files (without docroot check)"); - /* TODOC: -X goes away, expect MPMs to use -D options */ - destroy_and_exit_process(process, 1); -} - -int main(int argc, const char * const argv[]) -{ - char c; - int configtestonly = 0; - const char *confname = SERVER_CONFIG_FILE; - const char *def_server_root = HTTPD_ROOT; - process_rec *process; - server_rec *server_conf; - apr_pool_t *pglobal; - apr_pool_t *pconf; - apr_pool_t *plog; /* Pool of log streams, reset _after_ each read of conf */ - apr_pool_t *ptemp; /* Pool for temporary config stuff, reset often */ - apr_pool_t *pcommands; /* Pool for -D, -C and -c switches */ - apr_getopt_t *opt; - module **mod; - const char *optarg; - - apr_initialize(); - - process = create_process(argc, argv); - pglobal = process->pool; - pconf = process->pconf; - ap_server_argv0 = process->short_name; - -#if APR_CHARSET_EBCDIC - if (ap_init_ebcdic(pglobal) != APR_SUCCESS) { - destroy_and_exit_process(process, 1); - } -#endif - - ap_setup_prelinked_modules(process); - - apr_pool_create(&pcommands, pglobal); - ap_server_pre_read_config = apr_array_make(pcommands, 1, sizeof(char *)); - ap_server_post_read_config = apr_array_make(pcommands, 1, sizeof(char *)); - ap_server_config_defines = apr_array_make(pcommands, 1, sizeof(char *)); - - ap_run_rewrite_args(process); - - /* Maintain AP_SERVER_BASEARGS list in http_main.h to allow the MPM - * to safely pass on our args from its rewrite_args() handler. - */ - apr_getopt_init(&opt, pcommands, process->argc, process->argv); - - while (apr_getopt(opt, AP_SERVER_BASEARGS, &c, &optarg) - == APR_SUCCESS) { - char **new; - switch (c) { - case 'c': - new = (char **)apr_array_push(ap_server_post_read_config); - *new = apr_pstrdup(pcommands, optarg); - break; - case 'C': - new = (char **)apr_array_push(ap_server_pre_read_config); - *new = apr_pstrdup(pcommands, optarg); - break; - case 'd': - def_server_root = optarg; - break; - case 'D': - new = (char **)apr_array_push(ap_server_config_defines); - *new = apr_pstrdup(pcommands, optarg); - break; - case 'f': - confname = optarg; - break; - case 'v': - printf("Server version: %s\n", ap_get_server_version()); - printf("Server built: %s\n", ap_get_server_built()); - destroy_and_exit_process(process, 0); - case 'V': - show_compile_settings(); - destroy_and_exit_process(process, 0); - case 'l': - ap_show_modules(); - destroy_and_exit_process(process, 0); - case 'L': - ap_show_directives(); - destroy_and_exit_process(process, 0); - case 't': - configtestonly = 1; - break; - case '?': - case 'h': - usage(process); - } - } - - apr_pool_create(&plog, pglobal); - apr_pool_create(&ptemp, pconf); - - /* Note that we preflight the config file once - before reading it _again_ in the main loop. - This allows things, log files configuration - for example, to settle down. */ - - ap_server_root = def_server_root; - server_conf = ap_read_config(process, ptemp, confname, &ap_conftree); - ap_run_pre_config(pconf, plog, ptemp); - ap_process_config_tree(server_conf, ap_conftree, process->pconf, ptemp); - ap_fixup_virtual_hosts(pconf, server_conf); - ap_fini_vhost_config(pconf, server_conf); - apr_sort_hooks(); - if (configtestonly) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Syntax OK\n"); - destroy_and_exit_process(process, 0); - } - apr_pool_clear(plog); - ap_run_open_logs(pconf, plog, ptemp, server_conf); - ap_run_post_config(pconf, plog, ptemp, server_conf); - apr_pool_destroy(ptemp); - - for (;;) { - apr_hook_deregister_all(); - apr_pool_clear(pconf); - for (mod = ap_prelinked_modules; *mod != NULL; mod++) { - ap_register_hooks(*mod, pconf); - } - - - /* This is a hack until we finish the code so that it only reads - * the config file once and just operates on the tree already in - * memory. rbb - */ - ap_conftree = NULL; - apr_pool_create(&ptemp, pconf); - ap_server_root = def_server_root; - server_conf = ap_read_config(process, ptemp, confname, &ap_conftree); - ap_run_pre_config(pconf, plog, ptemp); - ap_process_config_tree(server_conf, ap_conftree, process->pconf, ptemp); - ap_fixup_virtual_hosts(pconf, server_conf); - ap_fini_vhost_config(pconf, server_conf); - apr_sort_hooks(); - apr_pool_clear(plog); - ap_run_open_logs(pconf, plog, ptemp, server_conf); - ap_run_post_config(pconf, plog, ptemp, server_conf); - apr_pool_destroy(ptemp); - - ap_run_optional_fn_retrieve(); - - if (ap_mpm_run(pconf, plog, server_conf)) break; - } - destroy_and_exit_process(process, 0); - return 0; /* Supress compiler warning. */ -} - -/* 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 */ - -#ifndef SHARED_CORE_BOOTSTRAP -/* - * Force apr_password_validate() into the image so that modules like - * mod_auth can use it even if they're dynamically loaded. - */ -void suck_in_apr_password_validate(void); -void suck_in_apr_password_validate(void) -{ - apr_password_validate("a", "b"); -} -#endif - -#ifdef AP_USING_AUTOCONF -/* This ugly little hack pulls any function referenced in exports.c into - * the web server. exports.c is generated during the build, and it - * has all of the APR functions specified by the apr/apr.exports and - * apr-util/aprutil.exports files. - */ -const void *suck_in_APR(void); -const void *suck_in_APR(void) -{ - extern const void *ap_ugly_hack; - - return ap_ugly_hack; -} -#endif diff --git a/server/mpm/.cvsignore b/server/mpm/.cvsignore deleted file mode 100644 index bd5fe06963..0000000000 --- a/server/mpm/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -Makefile -.deps diff --git a/server/mpm/MPM.NAMING b/server/mpm/MPM.NAMING deleted file mode 100644 index 62b60a0328..0000000000 --- a/server/mpm/MPM.NAMING +++ /dev/null @@ -1,13 +0,0 @@ - -The following MPMs currently exist: - - prefork ....... Multi Process Model with Preforking (Apache 1.3) - perchild ...... Multi Process Model with Threading. - Constant number of processes, variable number of threads - each child process can have a different uid/gid. - threaded ...... Multi Process Model with Threading. - Variable number of processes, constant number of - threads/child (= Apache/thread) - spmt_os2 ...... Single Process Model with Threading on OS/2 - winnt ......... Single Process Model with Threading on Windows NT - diff --git a/server/mpm/Makefile.in b/server/mpm/Makefile.in deleted file mode 100644 index b68fee5cd7..0000000000 --- a/server/mpm/Makefile.in +++ /dev/null @@ -1,4 +0,0 @@ - -SUBDIRS = $(MPM_NAME) - -include $(top_srcdir)/build/rules.mk diff --git a/server/mpm/beos/.cvsignore b/server/mpm/beos/.cvsignore deleted file mode 100644 index 84df257214..0000000000 --- a/server/mpm/beos/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -.deps -.libs -*.lo -*.la -Makefile diff --git a/server/mpm/beos/Makefile.in b/server/mpm/beos/Makefile.in deleted file mode 100644 index 3f88b0415f..0000000000 --- a/server/mpm/beos/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libbeos.la -LTLIBRARY_SOURCES = beos.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/server/mpm/beos/beos.c b/server/mpm/beos/beos.c deleted file mode 100644 index c0128df9b5..0000000000 --- a/server/mpm/beos/beos.c +++ /dev/null @@ -1,1122 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* The new BeOS MPM! - * - * This one basically is a single process multi threaded model, but - * I couldn't be bothered adding the spmt_ to the front of the name! - * Anyway, this is still under development so it isn't yet the default - * choice. - */ - -#define CORE_PRIVATE - -#include "apr_strings.h" -#include "apr_portable.h" -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" /* for read_config */ -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "ap_mpm.h" -#include "beosd.h" -#include "ap_listen.h" -#include "scoreboard.h" -#include <kernel/OS.h> -#include "mpm_common.h" -#include "mpm.h" -#include <unistd.h> -#include <sys/socket.h> -#include <signal.h> - -/* - * Actual definitions of config globals - */ - -int ap_threads_per_child=HARD_THREAD_LIMIT; /* Worker threads per child */ -int ap_max_requests_per_child=0; -static const char *ap_pid_fname=NULL; -static int ap_threads_to_start=0; -static int min_spare_threads=0; -static int max_spare_threads=0; -static int ap_thread_limit=0; -static int num_listening_sockets = 0; /* set by open_listeners in ap_mpm_run */ -static apr_socket_t ** listening_sockets; -apr_lock_t *accept_mutex = NULL; - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ - -static int server_pid; - -/* Keep track of the number of worker threads currently active */ -static int worker_thread_count; -apr_lock_t *worker_thread_count_mutex; - -/* The structure used to pass unique initialization info to each thread */ -typedef struct { - int slot; - apr_pool_t *tpool; -} proc_info; - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with MaxClients changes across SIGWINCH restarts. We use this - * value to optimize routines that have to scan the entire scoreboard. - */ -int ap_max_child_assigned = -1; -int ap_max_threads_limit = -1; -char ap_coredump_dir[MAX_STRING_LEN]; - -static apr_socket_t *udp_sock; -static apr_sockaddr_t *udp_sa; - -/* shared http_main globals... */ - -server_rec *ap_server_conf; - -/* one_process */ -static int one_process = 0; - -#ifdef DEBUG_SIGSTOP -int raise_sigstop_flags; -#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) - apr_pool_destroy(pchild); - exit(code); -} - -/* handle all varieties of core dumping signals */ -static void sig_coredump(int sig) -{ - chdir(ap_coredump_dir); - signal(sig, SIG_DFL); - kill(server_pid, sig); - /* 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... - */ - -/* 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; - -/* - * 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. - * - * These should only be called from the parent process itself, since the - * parent process will use the shutdown_pending and restart_pending variables - * to determine whether to shutdown or restart. The child process should - * call signal_parent() directly to tell the parent to die -- this will - * cause neither of those variable to be set, which the parent will - * assume means something serious is wrong (which it will be, for the - * child to force an exit) and so do an exit anyway. - */ - -static void ap_start_shutdown(void) -{ - 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; -} - -/* do a graceful restart if graceful == 1 */ -static void ap_start_restart(int graceful) -{ - - if (restart_pending == 1) { - /* Probably not an error - don't bother reporting it */ - return; - } - restart_pending = 1; - is_graceful = graceful; - if (is_graceful){ - apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard); - } -} - -static void sig_term(int sig) -{ - ap_start_shutdown(); -} - -static void restart(int sig) -{ - ap_start_restart(sig == SIGWINCH); -} - -static void tell_workers_to_exit(void) -{ - apr_size_t len; - int i = 0; - for (i = 0 ; i < ap_max_child_assigned; i++){ - len = 4; - if (apr_sendto(udp_sock, udp_sa, 0, "die!", &len) != APR_SUCCESS) - break; - } -} - -static void set_signals(void) -{ - struct sigaction sa; - - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - - if (!one_process) { - sa.sa_handler = sig_coredump; - - if (sigaction(SIGSEGV, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)"); - if (sigaction(SIGBUS, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)"); - if (sigaction(SIGABRT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)"); - if (sigaction(SIGILL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGILL)"); - sa.sa_flags = 0; - } - sa.sa_handler = sig_term; - if (sigaction(SIGTERM, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)"); - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)"); - - sa.sa_handler = SIG_IGN; - if (sigaction(SIGPIPE, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)"); - - /* we want to ignore HUPs and WINCH while we're busy processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, SIGWINCH); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); - if (sigaction(SIGWINCH, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGWINCH)"); -} - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -int ap_graceful_stop_signalled(void) -{ - /* XXX - Does this really work? - Manoj */ - return is_graceful; -} - -/***************************************************************** - * Child process main loop. - */ - -static void process_socket(apr_pool_t *p, apr_socket_t *sock, int my_child_num) -{ - conn_rec *current_conn; - long conn_id = my_child_num; - int csd; - - (void)apr_os_sock_get(&csd, sock); - - if (csd >= FD_SETSIZE) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, NULL, - "filedescriptor (%u) larger than FD_SETSIZE (%u) " - "found, you probably need to rebuild Apache with a " - "larger FD_SETSIZE", csd, FD_SETSIZE); - apr_socket_close(sock); - return; - } - - current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id); - - if (current_conn) { - ap_process_connection(current_conn); - ap_lingering_close(current_conn); - } -} - -static int32 worker_thread(void * dummy) -{ - proc_info * ti = dummy; - int child_slot = ti->slot; - apr_pool_t *tpool = ti->tpool; - apr_socket_t *csd = NULL; - apr_pool_t *ptrans; /* Pool for per-transaction stuff */ - apr_socket_t *sd = NULL; - apr_status_t rv = APR_EINIT; - int srv , n; - int curr_pollfd = 0, last_pollfd = 0; - sigset_t sig_mask; - int requests_this_child = ap_max_requests_per_child; - apr_pollfd_t *pollset; - /* each worker thread is in control of it's own destiny...*/ - int this_worker_should_exit = 0; - free(ti); - - /* block the signals for this thread */ - sigfillset(&sig_mask); - sigprocmask(SIG_BLOCK, &sig_mask, NULL); - - apr_pool_create(&ptrans, tpool); - - apr_lock_acquire(worker_thread_count_mutex); - worker_thread_count++; - apr_lock_release(worker_thread_count_mutex); - - (void) ap_update_child_status(0, child_slot, SERVER_STARTING, - (request_rec*)NULL); - - apr_poll_setup(&pollset, num_listening_sockets, tpool); - for(n=0 ; n <= num_listening_sockets ; n++) - apr_poll_socket_add(pollset, listening_sockets[n], APR_POLLIN); - - while (1) { - /* If we're here, then chances are (unless we're the first thread created) we're going - to be held up on the accept_muetx, so doing this here shouldn't be a peformance hit. - If it is, you probably need more threads... - */ - - this_worker_should_exit |= (ap_max_requests_per_child != 0) && (requests_this_child <= 0); - - if (this_worker_should_exit) break; - - (void) ap_update_child_status(0, child_slot, SERVER_READY, - (request_rec*)NULL); - - apr_lock_acquire(accept_mutex); - - while (!this_worker_should_exit) { - apr_int16_t event; - apr_status_t ret; - - ret = apr_poll(pollset, &srv, -1); - - if (ret != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(ret)) { - continue; - } - /* poll() will only return errors in catastrophic - * circumstances. Let's try exiting gracefully, for now. */ - ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *) - ap_server_conf, "apr_poll: (listen)"); - this_worker_should_exit = 1; - } else { - /* if we've bailed in apr_poll what's the point of trying to use the data? */ - apr_poll_revents_get(&event, listening_sockets[0], pollset); - - if (event & APR_POLLIN){ - apr_sockaddr_t *rec_sa; - char *tmpbuf = apr_pcalloc(ptrans, sizeof(char) * 5); - apr_size_t len = 5; - apr_sockaddr_info_get(&rec_sa, "127.0.0.1", APR_UNSPEC, 7772, 0, ptrans); - - if ((ret = apr_recvfrom(rec_sa, listening_sockets[0], 0, tmpbuf, &len)) - != APR_SUCCESS){ - ap_log_error(APLOG_MARK, APLOG_ERR, ret, NULL, - "error getting data from UDP!!"); - }else { - /* add checking??? */ - } - this_worker_should_exit = 1; - } - } - - if (this_worker_should_exit) break; - - if (num_listening_sockets == 1) { - sd = ap_listeners->sd; - goto got_fd; - } - else { - /* find a listener */ - curr_pollfd = last_pollfd; - do { - curr_pollfd++; - - if (curr_pollfd > num_listening_sockets) - curr_pollfd = 1; - - /* Get the revent... */ - apr_poll_revents_get(&event, listening_sockets[curr_pollfd], pollset); - - if (event & APR_POLLIN) { - last_pollfd = curr_pollfd; - sd = listening_sockets[curr_pollfd]; - goto got_fd; - } - } while (curr_pollfd != last_pollfd); - } - } - got_fd: - - if (!this_worker_should_exit) { - rv = apr_accept(&csd, sd, ptrans); - apr_lock_release(accept_mutex); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "apr_accept"); - } else { - process_socket(ptrans, csd, child_slot); - requests_this_child--; - } - } - else { - apr_lock_release(accept_mutex); - break; - } - apr_pool_clear(ptrans); - - } - - ap_update_child_status(0, child_slot, SERVER_DEAD, (request_rec*)NULL); - - apr_lock_acquire(worker_thread_count_mutex); - worker_thread_count--; - apr_lock_release(worker_thread_count_mutex); - - return (0); -} - -static int make_worker(server_rec *s, int slot) -{ - thread_id tid; - proc_info *my_info = (proc_info *)malloc(sizeof(proc_info)); /* freed by thread... */ - - if (my_info == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf, - "malloc: out of memory"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - my_info->slot = slot; - apr_pool_create(&my_info->tpool, pchild); - - if (slot + 1 > ap_max_child_assigned) - ap_max_child_assigned = slot + 1; - - if (one_process) { - set_signals(); - ap_scoreboard_image->parent[0].pid = getpid(); - return 0; - } - - (void) ap_update_child_status(0, slot, SERVER_STARTING, (request_rec*)NULL); - tid = spawn_thread(worker_thread, "apache_worker", B_NORMAL_PRIORITY, - my_info); - if (tid < B_NO_ERROR) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, - "spawn_thread: Unable to start a new thread"); - /* 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. */ - (void) ap_update_child_status(0, slot, SERVER_DEAD, - (request_rec*)NULL); - - sleep(10); - free(my_info); - - return -1; - } - resume_thread(tid); - - ap_scoreboard_image->servers[0][slot].tid = tid; - return 0; -} - -/* start up a bunch of children */ -static void startup_threads(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < ap_thread_limit; ++i) { - if (ap_scoreboard_image->servers[0][i].tid) { - continue; - } - if (make_worker(ap_server_conf, i) < 0) { - break; - } - --number_to_start; - } -} - - -/* - * 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 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 free_length; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead; - - /* initialize the free_list */ - free_length = 0; - - for (i = 0; i < ap_thread_limit; ++i) { - if (ap_scoreboard_image->servers[0][i].tid == 0) { - if (free_length < spawn_rate) { - free_slots[free_length] = i; - ++free_length; - } - } - else { - last_non_dead = i; - } - - if (i >= ap_max_child_assigned && free_length >= spawn_rate) { - break; - } - } - ap_max_child_assigned = last_non_dead + 1; - - if (free_length > 0) { - for (i = 0; i < free_length; ++i) { - make_worker(ap_server_conf, free_slots[i]); - } - /* 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 (spawn_rate < MAX_SPAWN_RATE) { - spawn_rate *= 2; - } - } else { - spawn_rate = 1; - } -} - -static void server_main_loop(int remaining_threads_to_start) -{ - int child_slot; - apr_wait_t status; - apr_proc_t pid; - int i; - - while (!restart_pending && !shutdown_pending) { - ap_wait_or_timeout(&status, &pid, pconf); - - if (pid.pid >= 0) { - ap_process_child_status(&pid, status); - /* non-fatal death... note that it's gone in the scoreboard. */ - child_slot = -1; - for (i = 0; i < ap_max_child_assigned; ++i) { - if (ap_scoreboard_image->servers[0][i].tid == pid.pid) { - child_slot = i; - break; - } - } - if (child_slot >= 0) { - ap_scoreboard_image->servers[0][child_slot].tid = 0; - (void) ap_update_child_status(0, child_slot, SERVER_DEAD, (request_rec*)NULL); - - if (remaining_threads_to_start - && child_slot < ap_thread_limit) { - /* we're still doing a 1-for-1 replacement of dead - * children with new children - */ - make_worker(ap_server_conf, child_slot); - --remaining_threads_to_start; - } -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&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, 0, ap_server_conf, - "long lost child came home! (pid %ld)", pid.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_threads_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_threads(remaining_threads_to_start); - remaining_threads_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(); - } -} - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMONS: - *result = ap_max_child_assigned; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_NOT_SUPPORTED; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = ap_threads_per_child; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int remaining_threads_to_start, i,j; - apr_status_t rv; - ap_listen_rec *lr; - pconf = _pconf; - ap_server_conf = s; - - ap_scoreboard_fname = DEFAULT_SCOREBOARD; - - /* BeOS R5 doesn't support pipes on select() calls, so we use a - UDP socket as these are supported in both R5 and BONE. If we only cared - about BONE we'd use a pipe, but there it is. - As we have UDP support in APR, now use the APR functions and check all the - return values... - */ - if (apr_sockaddr_info_get(&udp_sa, "127.0.0.1", APR_UNSPEC, 7772, 0, _pconf) - != APR_SUCCESS){ - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, s, - "couldn't create control socket information, shutting down"); - return 1; - } - if (apr_socket_create(&udp_sock, udp_sa->sa.sin.sin_family, SOCK_DGRAM, - _pconf) != APR_SUCCESS){ - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, s, - "couldn't create control socket, shutting down"); - return 1; - } - if (apr_bind(udp_sock, udp_sa) != APR_SUCCESS){ - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, s, - "couldn't bind UDP socket!"); - return 1; - } - - if ((num_listening_sockets = ap_setup_listeners(ap_server_conf)) < 1) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s, - "no listening sockets available, shutting down"); - return 1; - } - - ap_log_pid(pconf, ap_pid_fname); - - /* - * Create our locks... - */ - - /* accept_mutex - * used to lock around select so we only have one thread - * in select at a time - */ - if ((rv = apr_lock_create(&accept_mutex, APR_MUTEX, APR_CROSS_PROCESS, - NULL, pconf)) != APR_SUCCESS) { - /* tsch tsch, can't have more than one thread in the accept loop - at a time so we need to fall on our sword... */ - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't create accept lock"); - return 1; - } - - /* worker_thread_count_mutex - * locks the worker_thread_count so we have ana ccurate count... - */ - if ((rv = apr_lock_create(&worker_thread_count_mutex, APR_MUTEX, APR_CROSS_PROCESS, - NULL, pconf)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't create worker thread count lock"); - return 1; - } - - /* - * Startup/shutdown... - */ - - if (!is_graceful) - ap_create_scoreboard(pconf, SB_SHARED); - - if (!is_graceful) { - for (i = 0; i < HARD_SERVER_LIMIT; i++) { - ap_scoreboard_image->parent[i].pid = 0; - for (j = 0;j < HARD_THREAD_LIMIT; j++) - ap_scoreboard_image->servers[i][j].tid = 0; - } - } - if (HARD_SERVER_LIMIT == 1) - ap_scoreboard_image->parent[0].pid = getpid(); - - set_signals(); - - /* Sanity checks to avoid thrashing... */ - if (max_spare_threads < min_spare_threads ) - max_spare_threads = min_spare_threads; - - /* If we're doing a graceful_restart then we're going to see a lot - * of threads exiting immediately when we get into the main loop - * below (because we just sent them SIGWINCH). This happens pretty - * rapidly... and for each one that exits we'll start a new one until - * we reach at least threads_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_threads_to_start = ap_threads_to_start; - /* sanity check on the number to start... */ - if (remaining_threads_to_start > ap_thread_limit) { - remaining_threads_to_start = ap_thread_limit; - } - - /* setup the child pool to use for the workers. Each worker creates - * a seperate pool of it's own to use. - */ - apr_pool_create(&pchild, pconf); - ap_run_child_init(pchild, ap_server_conf); - - /* Now that we have the child pool (pchild) we can allocate - * the listenfds and creat the pollset... - */ - listening_sockets = apr_palloc(pchild, - sizeof(*listening_sockets) * (num_listening_sockets + 1)); - - listening_sockets[0] = udp_sock; - for (lr = ap_listeners, i = 1; i <= num_listening_sockets; lr = lr->next, ++i) - listening_sockets[i]=lr->sd; - - /* we assume all goes OK...hmm might want to check that! */ - if (!is_graceful) { - startup_threads(remaining_threads_to_start); - remaining_threads_to_start = 0; - } - else { - /* give the system some time to recover before kicking into - * exponential mode */ - hold_off_on_exponential_spawning = 10; - } - - /* - * record that we've entered the world ! - */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); - - restart_pending = shutdown_pending = 0; - - /* - * main_loop until it's all over - */ - server_main_loop(remaining_threads_to_start); - - tell_workers_to_exit(); /* if we get here we're exiting... */ - sleep(1); /* give them a brief chance to exit */ - - /* close the UDP socket we've been using... */ - apr_socket_close(listening_sockets[0]); - - /* - * If we get here we're shutting down... - */ - if (shutdown_pending) { - /* Time to gracefully shut down: - * Kill child processes, tell them to call child_exit, etc... - */ - if (beosd_killpg(getpgrp(), SIGTERM) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "killpg 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, - 0, ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - } - - /* use ap_reclaim_child_processes starting with SIGTERM */ - ap_reclaim_child_processes(1); - - /* record the shutdown in the log */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "caught SIGTERM, shutting down"); - - return 1; - } - - /* we've been told to restart */ - signal(SIGHUP, SIG_IGN); - - if (one_process) { - return 1; - } - - if (is_graceful) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "SIGWINCH received. Doing graceful restart"); - } - else { - /* Kill 'em all. Since the child acts the same on the parents SIGTERM - * and a SIGHUP, we may as well use the same signal, because some user - * pthreads are stealing signals from us left and right. - */ - - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "SIGHUP received. Attempting to restart"); - } - - /* just before we go, tidy up the locks we've created to prevent a - * potential leak of semaphores... */ - apr_lock_destroy(worker_thread_count_mutex); - apr_lock_destroy(accept_mutex); - - return 0; -} - -static void beos_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach = 0; - - one_process = !!ap_exists_config_define("ONE_PROCESS"); - no_detach = !!ap_exists_config_define("NO_DETACH"); - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !no_detach) - apr_proc_detach(); - - server_pid = getpid(); - } - - beosd_pre_config(); - ap_listen_pre_config(); - ap_threads_to_start = DEFAULT_START_THREADS; - min_spare_threads = DEFAULT_MIN_FREE_THREADS; - max_spare_threads = DEFAULT_MAX_FREE_THREADS; - ap_thread_limit = HARD_THREAD_LIMIT; - ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; - ap_pid_fname = DEFAULT_PIDLOG; - ap_scoreboard_fname = DEFAULT_SCOREBOARD; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); -} - -static void beos_hooks(apr_pool_t *p) -{ - one_process = 0; - - ap_hook_pre_config(beos_pre_config, NULL, NULL, APR_HOOK_MIDDLE); -} - - -static const char *set_pidfile(cmd_parms *cmd, void *dummy, const 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 <VirtualHost>"; - } - ap_pid_fname = arg; - return NULL; -} - -static const char *set_scoreboard(cmd_parms *cmd, void *dummy, const 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_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_threads_to_start = atoi(arg); - return NULL; -} - -static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - min_spare_threads = atoi(arg); - if (min_spare_threads <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - - return NULL; -} - -static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - max_spare_threads = atoi(arg); - return NULL; -} - -static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_thread_limit = atoi(arg); - if (ap_thread_limit > HARD_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: MaxClients of %d exceeds compile time limit " - "of %d servers,", ap_thread_limit, HARD_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering MaxClients to %d. To increase, please " - "see the", HARD_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " HARD_SERVER_LIMIT define in src/include/httpd.h."); - ap_thread_limit = HARD_SERVER_LIMIT; - } - else if (ap_thread_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: Require MaxClients > 0, setting to 1"); - ap_thread_limit = 1; - } - return NULL; -} - -static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, const 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_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds compile time" - "limit of %d threads,", ap_threads_per_child, - HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering ThreadsPerChild to %d. To increase, please" - "see the", HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " HARD_THREAD_LIMIT define in %s", AP_MPM_HARD_LIMITS_FILE); - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 1; - } - return NULL; -} - -static const char *set_max_requests(cmd_parms *cmd, void *dummy, const 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_coredumpdir (cmd_parms *cmd, void *dummy, const char *arg) -{ - apr_finfo_t finfo; - const char *fname; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - fname = ap_server_root_relative(cmd->pool, arg); - if ((apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) - || (finfo.filetype != APR_DIR)) { - return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, - " does not exist or is not a directory", NULL); - } - apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir)); - return NULL; -} - -static const command_rec beos_cmds[] = { -LISTEN_COMMANDS -AP_INIT_TAKE1( "PidFile", set_pidfile, NULL, RSRC_CONF, - "A file for logging the server process ID"), -AP_INIT_TAKE1( "ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, - "A file for Apache to maintain runtime process management information"), -AP_INIT_TAKE1( "StartServers", set_daemons_to_start, NULL, RSRC_CONF, - "Number of child processes launched at server startup"), -AP_INIT_TAKE1( "MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, - "Minimum number of idle children, to handle request spikes"), -AP_INIT_TAKE1( "MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, - "Maximum number of idle children" ), -AP_INIT_TAKE1( "MaxClients", set_server_limit, NULL, RSRC_CONF, - "Maximum number of children alive at the same time" ), -AP_INIT_TAKE1( "ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, - "Number of threads each child creates" ), -AP_INIT_TAKE1( "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, - "Maximum number of requests a particular child serves before dying." ), -AP_INIT_TAKE1( "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, - "The location of the directory Apache changes to before dumping core" ), -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA mpm_beos_module = { - MPM20_MODULE_STUFF, - NULL, /* hook to run before apache parses args */ - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - beos_cmds, /* command apr_table_t */ - beos_hooks /* register_hooks */ -}; - diff --git a/server/mpm/beos/beos.h b/server/mpm/beos/beos.h deleted file mode 100644 index 4b37a65ec9..0000000000 --- a/server/mpm/beos/beos.h +++ /dev/null @@ -1,69 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_BEOS_H -#define APACHE_MPM_BEOS_H - -extern int ap_threads_per_child; -extern int ap_max_requests_per_child; -extern int ap_pipe_of_death[2]; -extern int ap_extended_status; -extern void clean_child_exit(int); -extern int max_daemons_limit; - -#endif /* APACHE_MPM_BEOS_H */ diff --git a/server/mpm/beos/config5.m4 b/server/mpm/beos/config5.m4 deleted file mode 100644 index 4f201408d6..0000000000 --- a/server/mpm/beos/config5.m4 +++ /dev/null @@ -1,7 +0,0 @@ -dnl ## XXX - Need a more thorough check of the proper flags to use - -if test "$MPM_NAME" = "beos" ; then - apache_apr_flags="--enable-threads" - - APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile) -fi diff --git a/server/mpm/beos/mpm.h b/server/mpm/beos/mpm.h deleted file mode 100644 index 3a652f0502..0000000000 --- a/server/mpm/beos/mpm.h +++ /dev/null @@ -1,77 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_BEOS_H -#define APACHE_MPM_BEOS_H - -#define BEOS_MPM -#include "scoreboard.h" - -#define MPM_NAME "Beos" -#define AP_MPM_NEEDS_RECLAIM_CHILD_PROCESSES 1 -#define MPM_SYNC_CHILD_TABLE() -#define MPM_CHILD_PID(i) (ap_scoreboard_image->servers[0][i].tid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) - -extern int ap_max_child_assigned; - -extern server_rec *ap_server_conf; -extern char ap_coredump_dir[MAX_STRING_LEN]; -extern int ap_threads_per_child; - -#endif /* APACHE_MPM_BEOS_H */ diff --git a/server/mpm/beos/mpm_default.h b/server/mpm/beos/mpm_default.h deleted file mode 100644 index 2517bb8c95..0000000000 --- a/server/mpm/beos/mpm_default.h +++ /dev/null @@ -1,149 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -/* we use the child (c) as zero in our code... */ -#define AP_ID_FROM_CHILD_THREAD(c, t) t -/* as the child is always zero, just return the id... */ -#define AP_CHILD_THREAD_FROM_ID(i) 0 , i - -/* Number of threads to spawn off by default --- also, if fewer than - * this free when the caretaker checks, it will spawn more. - */ -#ifndef DEFAULT_START_THREADS -#define DEFAULT_START_THREADS 25 -#endif - -/* Maximum number of *free* threads --- more than this, and - * they will die off. - */ - -#ifndef DEFAULT_MAX_FREE_THREADS -#define DEFAULT_MAX_FREE_THREADS 50 -#endif - -/* Minimum --- fewer than this, and more will be created */ - -#ifndef DEFAULT_MIN_FREE_THREADS -#define DEFAULT_MIN_FREE_THREADS 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. - */ - -/* we only ever have 1 main process running... */ -#define HARD_SERVER_LIMIT 1 - -/* Limit on the threads per process. Clients will be locked out if more than - * this * HARD_SERVER_LIMIT are needed. - * - * We keep this for one reason it keeps the size of the scoreboard file small - * enough that we can read the whole thing without worrying too much about - * the overhead. - */ -#ifdef NO_THREADS -#define HARD_THREAD_LIMIT 1 -#endif -#ifndef HARD_THREAD_LIMIT -#define HARD_THREAD_LIMIT 50 -#endif - -#ifdef NO_THREADS -#define DEFAULT_THREADS_PER_CHILD 1 -#endif - -#ifndef DEFAULT_THREADS_PER_CHILD -#define DEFAULT_THREADS_PER_CHILD 10 -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG "logs/httpd.pid" -#endif - -/* Scoreboard file, if there is one */ -#ifndef DEFAULT_SCOREBOARD -#define DEFAULT_SCOREBOARD "logs/apache_runtime_status" -#endif - -/* - * Interval, in microseconds, between scoreboard maintenance. - */ -#ifndef SCOREBOARD_MAINTENANCE_INTERVAL -#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 -#endif - -/* Number of requests to try to handle in a single process. If <= 0, - * the children don't die off. - */ -#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD -#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 -#endif - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/server/mpm/config.m4 b/server/mpm/config.m4 deleted file mode 100644 index 9d2c3fba6a..0000000000 --- a/server/mpm/config.m4 +++ /dev/null @@ -1,34 +0,0 @@ -AC_MSG_CHECKING(which MPM to use) -AC_ARG_WITH(mpm, -[ --with-mpm=MPM Choose the process model for Apache to use. - MPM={beos,threaded,prefork,spmt_os2,perchild}],[ - APACHE_MPM=$withval -],[ - if test "x$APACHE_MPM" = "x"; then - APACHE_MPM=threaded - fi -]) -AC_MSG_RESULT($APACHE_MPM) - -apache_cv_mpm=$APACHE_MPM - -if test "$apache_cv_mpm" = "threaded" -o "$apache_cv_mpm" = "perchild"; then - APR_CHECK_APR_DEFINE(APR_HAS_THREADS, srclib/apr) - - if test "x$ac_cv_define_APR_HAS_THREADS" = "xno"; then - AC_MSG_RESULT(The currently selected MPM requires threads which your system seems to lack) - AC_MSG_CHECKING(checking for replacement) - AC_MSG_RESULT(prefork selected) - apache_cv_mpm=prefork - fi -fi - -APACHE_FAST_OUTPUT(server/mpm/Makefile) - -MPM_NAME=$apache_cv_mpm -MPM_DIR=server/mpm/$MPM_NAME -MPM_LIB=$MPM_DIR/lib${MPM_NAME}.la - -APACHE_SUBST(MPM_NAME) -MODLIST="$MODLIST mpm_${MPM_NAME}" - diff --git a/server/mpm/experimental/perchild/.cvsignore b/server/mpm/experimental/perchild/.cvsignore deleted file mode 100644 index 84df257214..0000000000 --- a/server/mpm/experimental/perchild/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -.deps -.libs -*.lo -*.la -Makefile diff --git a/server/mpm/experimental/perchild/Makefile.in b/server/mpm/experimental/perchild/Makefile.in deleted file mode 100644 index 374f130646..0000000000 --- a/server/mpm/experimental/perchild/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libperchild.la -LTLIBRARY_SOURCES = perchild.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/server/mpm/experimental/perchild/config5.m4 b/server/mpm/experimental/perchild/config5.m4 deleted file mode 100644 index bd179baed9..0000000000 --- a/server/mpm/experimental/perchild/config5.m4 +++ /dev/null @@ -1,6 +0,0 @@ -dnl ## XXX - Need a more thorough check of the proper flags to use - -if test "$MPM_NAME" = "perchild" ; then - - APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile) -fi diff --git a/server/mpm/experimental/perchild/mpm.h b/server/mpm/experimental/perchild/mpm.h deleted file mode 100644 index d24f8b4aba..0000000000 --- a/server/mpm/experimental/perchild/mpm.h +++ /dev/null @@ -1,91 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "httpd.h" -#include "mpm_default.h" -#include "unixd.h" - -#ifndef APACHE_MPM_PERCHILD_H -#define APACHE_MPM_PERCHILD_H - -#define PERCHILD_MPM - -#define MPM_NAME "Perchild" - -#define AP_MPM_NEEDS_RECLAIM_CHILD_PROCESSES 1 -#define MPM_SYNC_CHILD_TABLE() -#define MPM_CHILD_PID(i) (ap_child_table[i].pid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) - -/* Table of child status */ -#define SERVER_DEAD 0 -#define SERVER_DYING 1 -#define SERVER_ALIVE 2 - -typedef struct ap_ctable{ - pid_t pid; - unsigned char status; -} ap_ctable; - -extern int ap_threads_per_child; -extern int ap_max_daemons_limit; -extern ap_ctable ap_child_table[HARD_SERVER_LIMIT]; -extern server_rec *ap_server_conf; -extern char ap_coredump_dir[MAX_STRING_LEN]; - -#endif /* APACHE_MPM_PERCHILD_H */ diff --git a/server/mpm/experimental/perchild/mpm_default.h b/server/mpm/experimental/perchild/mpm_default.h deleted file mode 100644 index f462ea8f90..0000000000 --- a/server/mpm/experimental/perchild/mpm_default.h +++ /dev/null @@ -1,147 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -#define AP_ID_FROM_CHILD_THREAD(c, t) ((c * HARD_THREAD_LIMIT) + t) -#define AP_CHILD_THREAD_FROM_ID(i) (i / HARD_THREAD_LIMIT), (i % HARD_THREAD_LIMIT) - -/* Number of threads to spawn off by default --- also, if fewer than - * this free when the caretaker checks, it will spawn more. - */ -#ifndef DEFAULT_START_THREAD -#define DEFAULT_START_THREAD 5 -#endif - -/* Maximum number of *free* server threads --- more than this, and - * they will die off. - */ - -#ifndef DEFAULT_MAX_SPARE_THREAD -#define DEFAULT_MAX_SPARE_THREAD 10 -#endif - -/* Minimum --- fewer than this, and more will be created */ - -#ifndef DEFAULT_MIN_SPARE_THREAD -#define DEFAULT_MIN_SPARE_THREAD 5 -#endif - -/* Limit on the threads per process. Clients will be locked out if more than - * this * HARD_SERVER_LIMIT are needed. - * - * We keep this for one reason 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_THREAD_LIMIT -#define HARD_THREAD_LIMIT 64 -#endif - -/* Number of servers to spawn off by default - */ -#ifndef DEFAULT_NUM_DAEMON -#define DEFAULT_NUM_DAEMON 2 -#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 -#define HARD_SERVER_LIMIT 8 -#endif - -/* File used for accept locking, when we use a file */ -#ifndef DEFAULT_LOCKFILE -#define DEFAULT_LOCKFILE "logs/accept.lock" -#endif - -/* Scoreboard file, if there is one */ -#ifndef DEFAULT_SCOREBOARD -#define DEFAULT_SCOREBOARD "logs/apache_runtime_status" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG "logs/httpd.pid" -#endif - -/* - * Interval, in microseconds, between scoreboard maintenance. - */ -#ifndef SCOREBOARD_MAINTENANCE_INTERVAL -#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 -#endif - -/* Number of requests to try to handle in a single process. If <= 0, - * the children don't die off. - */ -#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD -#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 -#endif - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/server/mpm/experimental/perchild/perchild.c b/server/mpm/experimental/perchild/perchild.c deleted file mode 100644 index 0fa14997b1..0000000000 --- a/server/mpm/experimental/perchild/perchild.c +++ /dev/null @@ -1,1829 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr_hash.h" -#include "apr_strings.h" -#include "apr_pools.h" -#include "apr_portable.h" -#include "apr_file_io.h" -#include "apr_signal.h" - -#define APR_WANT_IOVEC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif - -#if !APR_HAS_THREADS -#error The perchild MPM requires APR threads, but they are unavailable. -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" /* for read_config */ -#include "http_core.h" /* for get_remote_host */ -#include "http_protocol.h" -#include "http_connection.h" -#include "ap_mpm.h" -#include "unixd.h" -#include "mpm_common.h" -#include "ap_listen.h" -#include "mpm_default.h" -#include "mpm.h" -#include "scoreboard.h" -#include "util_filter.h" - -/* ### should be APR-ized */ -#include <poll.h> -#include <grp.h> -#include <pwd.h> -#include <sys/stat.h> -#include <sys/un.h> -#include <setjmp.h> - -/* - * Actual definitions of config globals - */ - -static int threads_to_start = 0; /* Worker threads per child */ -static int min_spare_threads = 0; -static int max_spare_threads = 0; -static int max_threads = 0; -static int max_requests_per_child = 0; -static const char *ap_pid_fname=NULL; -static int num_daemons=0; -static int curr_child_num=0; -static int workers_may_exit = 0; -static int requests_this_child; -static int num_listenfds = 0; -static apr_socket_t **listenfds; -static jmp_buf jmpbuffer; - -struct child_info_t { - uid_t uid; - gid_t gid; - int sd; -}; - -typedef struct { - const char *sockname; /* The base name for the socket */ - const char *fullsockname; /* socket base name + extension */ - int sd; /* The socket descriptor */ - int sd2; /* The socket descriptor */ -} perchild_server_conf; - -typedef struct child_info_t child_info_t; - -/* Tables used to determine the user and group each child process should - * run as. The hash table is used to correlate a server name with a child - * process. - */ -static child_info_t child_info_table[HARD_SERVER_LIMIT]; -static int thread_socket_table[HARD_THREAD_LIMIT]; - - -struct ap_ctable ap_child_table[HARD_SERVER_LIMIT]; - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with NumServers changes across SIGWINCH restarts. We use this - * value to optimize routines that have to scan the entire child table. - * - * XXX - It might not be worth keeping this code in. There aren't very - * many child processes in this MPM. - */ -int ap_max_daemons_limit = -1; -int ap_threads_per_child = HARD_THREAD_LIMIT; - -char ap_coredump_dir[MAX_STRING_LEN]; - -module AP_MODULE_DECLARE_DATA mpm_perchild_module; - -static apr_file_t *pipe_of_death_in = NULL; -static apr_file_t *pipe_of_death_out = NULL; -static apr_lock_t *pipe_of_death_mutex; - -/* *Non*-shared http_main globals... */ - -server_rec *ap_server_conf; - -/* 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; - -#ifdef DEBUG_SIGSTOP -int raise_sigstop_flags; -#endif - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ -static apr_pool_t *thread_pool_parent; /* Parent of per-thread pools */ -static apr_lock_t *thread_pool_parent_mutex; - -static int child_num; -static unsigned int my_pid; /* Linux getpid() doesn't work except in - main thread. Use this instead */ -/* Keep track of the number of worker threads currently active */ -static int worker_thread_count; -static apr_lock_t *worker_thread_count_mutex; -static int worker_thread_free_ids[HARD_THREAD_LIMIT]; -static apr_threadattr_t *worker_thread_attr; - -/* Keep track of the number of idle worker threads */ -static int idle_thread_count; -static apr_lock_t *idle_thread_count_mutex; - -/* Locks for accept serialization */ -#ifdef NO_SERIALIZED_ACCEPT -#define SAFE_ACCEPT(stmt) APR_SUCCESS -#else -#define SAFE_ACCEPT(stmt) (stmt) -static apr_lock_t *process_accept_mutex; -#endif /* NO_SERIALIZED_ACCEPT */ -static const char *lock_fname; -static apr_lock_t *thread_accept_mutex; - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMONS: - *result = ap_max_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_STATIC; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = max_threads; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -/* a clean exit from a child with proper cleanup */ -static void clean_child_exit(int code) -{ - if (pchild) { - apr_pool_destroy(pchild); - } - exit(code); -} - -/* handle all varieties of core dumping signals */ -static void sig_coredump(int sig) -{ - chdir(ap_coredump_dir); - apr_signal(sig, SIG_DFL); - kill(getpid(), sig); - /* 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. - */ -} - -static void just_die(int sig) -{ - clean_child_exit(0); -} - -/***************************************************************** - * Connection structures and accounting... - */ - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful; -/* we don't currently track ap_my_generation, but mod_status - * references it so it must be defined */ -ap_generation_t volatile ap_my_generation=0; - -/* - * 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. - * - * These should only be called from the parent process itself, since the - * parent process will use the shutdown_pending and restart_pending variables - * to determine whether to shutdown or restart. The child process should - * call signal_parent() directly to tell the parent to die -- this will - * cause neither of those variable to be set, which the parent will - * assume means something serious is wrong (which it will be, for the - * child to force an exit) and so do an exit anyway. - */ - -static void ap_start_shutdown(void) -{ - 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; -} - -/* do a graceful restart if graceful == 1 */ -static void ap_start_restart(int graceful) -{ - - if (restart_pending == 1) { - /* Probably not an error - don't bother reporting it */ - return; - } - restart_pending = 1; - is_graceful = graceful; - if (is_graceful) { - apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard); - } -} - -static void sig_term(int sig) -{ - ap_start_shutdown(); -} - -static void restart(int sig) -{ -#ifndef WIN32 - ap_start_restart(sig == SIGWINCH); -#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, errno, ap_server_conf, "sigaction(SIGSEGV)"); -#ifdef SIGBUS - if (sigaction(SIGBUS, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)"); -#endif -#ifdef SIGABORT - if (sigaction(SIGABORT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)"); -#endif -#ifdef SIGABRT - if (sigaction(SIGABRT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)"); -#endif -#ifdef SIGILL - if (sigaction(SIGILL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_server_conf, "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_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, errno, ap_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, errno, ap_server_conf, "sigaction(SIGPIPE)"); -#endif - - /* we want to ignore HUPs and WINCH while we're busy processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, SIGWINCH); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); - if (sigaction(SIGWINCH, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGWINCH)"); -#else - if (!one_process) { - apr_signal(SIGSEGV, sig_coredump); -#ifdef SIGBUS - apr_signal(SIGBUS, sig_coredump); -#endif /* SIGBUS */ -#ifdef SIGABORT - apr_signal(SIGABORT, sig_coredump); -#endif /* SIGABORT */ -#ifdef SIGABRT - apr_signal(SIGABRT, sig_coredump); -#endif /* SIGABRT */ -#ifdef SIGILL - apr_signal(SIGILL, sig_coredump); -#endif /* SIGILL */ -#ifdef SIGXCPU - apr_signal(SIGXCPU, SIG_DFL); -#endif /* SIGXCPU */ -#ifdef SIGXFSZ - apr_signal(SIGXFSZ, SIG_DFL); -#endif /* SIGXFSZ */ - } - - apr_signal(SIGTERM, sig_term); -#ifdef SIGHUP - apr_signal(SIGHUP, restart); -#endif /* SIGHUP */ -#ifdef SIGWINCH - apr_signal(SIGWINCH, restart); -#endif /* SIGWINCH */ -#ifdef SIGPIPE - apr_signal(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#endif -} - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -int ap_graceful_stop_signalled(void) -{ - /* XXX - Does this really work? - Manoj */ - return is_graceful; -} - -/***************************************************************** - * Child process main loop. - */ - -static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id) -{ - conn_rec *current_conn; - int csd; - apr_status_t rv; - int thread_num = conn_id % HARD_THREAD_LIMIT; - - if ((rv = apr_os_sock_get(&csd, sock)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get"); - } - - if (csd >= FD_SETSIZE) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, NULL, - "new file descriptor %d is too large; you probably need " - "to rebuild Apache with a larger FD_SETSIZE " - "(currently %d)", - csd, FD_SETSIZE); - apr_socket_close(sock); - return; - } - - if (thread_socket_table[thread_num] < 0) { - ap_sock_disable_nagle(sock); - } - - current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id); - if (current_conn) { - ap_process_connection(current_conn); - ap_lingering_close(current_conn); - } -} - -static void *worker_thread(void *); - -/* Starts a thread as long as we're below max_threads */ -static int start_thread(void) -{ - apr_thread_t *thread; - int rc; - - apr_lock_acquire(worker_thread_count_mutex); - if (worker_thread_count < max_threads - 1) { - if ((rc = apr_thread_create(&thread, worker_thread_attr, worker_thread, - &worker_thread_free_ids[worker_thread_count], pchild))) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rc, ap_server_conf, - "apr_thread_create: unable to create worker thread"); - /* 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 if we exit. */ - sleep(10); - workers_may_exit = 1; - apr_lock_release(worker_thread_count_mutex); - return 0; - } - else { - worker_thread_count++; - } - } - else { - static int reported = 0; - - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ap_server_conf, - "server reached MaxThreadsPerChild setting, consider raising the" - " MaxThreadsPerChild or NumServers settings"); - reported = 1; - } - apr_lock_release(worker_thread_count_mutex); - return 0; - } - apr_lock_release(worker_thread_count_mutex); - return 1; - -} -/* Sets workers_may_exit if we received a character on the pipe_of_death */ -static void check_pipe_of_death(void) -{ - apr_lock_acquire(pipe_of_death_mutex); - if (!workers_may_exit) { - int ret; - char pipe_read_char; - apr_size_t n = 1; - - ret = apr_recv(listenfds[0], &pipe_read_char, &n); - if (APR_STATUS_IS_EAGAIN(ret)) { - /* It lost the lottery. It must continue to suffer - * through a life of servitude. */ - } - else { - /* It won the lottery (or something else is very - * wrong). Embrace death with open arms. */ - workers_may_exit = 1; - } - } - apr_lock_release(pipe_of_death_mutex); -} - -/* idle_thread_count should be incremented before starting a worker_thread */ - -static void *worker_thread(void *arg) -{ - apr_socket_t *csd = NULL; - apr_pool_t *tpool; /* Pool for this thread */ - apr_pool_t *ptrans; /* Pool for per-transaction stuff */ - apr_socket_t *sd = NULL; - int srv; - int curr_pollfd, last_pollfd = 0; - int thread_just_started = 1; - int thread_num = *((int *) arg); - long conn_id = child_num * HARD_THREAD_LIMIT + thread_num; - apr_pollfd_t *pollset; - int n; - apr_status_t rv; - - apr_lock_acquire(thread_pool_parent_mutex); - apr_pool_create(&tpool, thread_pool_parent); - apr_lock_release(thread_pool_parent_mutex); - apr_pool_create(&ptrans, tpool); - - (void) ap_update_child_status(child_num, thread_num, SERVER_STARTING, - (request_rec *) NULL); - - apr_poll_setup(&pollset, num_listenfds+1, tpool); - for(n=0 ; n <= num_listenfds ; ++n) { - apr_poll_socket_add(pollset, listenfds[n], APR_POLLIN); - } - - while (!workers_may_exit) { - workers_may_exit |= (max_requests_per_child != 0) && (requests_this_child <= 0); - if (workers_may_exit) break; - if (!thread_just_started) { - apr_lock_acquire(idle_thread_count_mutex); - if (idle_thread_count < max_spare_threads) { - idle_thread_count++; - apr_lock_release(idle_thread_count_mutex); - } - else { - apr_lock_release(idle_thread_count_mutex); - break; - } - } - else { - thread_just_started = 0; - } - - (void) ap_update_child_status(child_num, thread_num, SERVER_READY, - (request_rec *) NULL); - - apr_lock_acquire(thread_accept_mutex); - if (workers_may_exit) { - apr_lock_release(thread_accept_mutex); - break; - } - if ((rv = SAFE_ACCEPT(apr_lock_acquire(process_accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_lock_acquire failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - - while (!workers_may_exit) { - apr_int16_t event; - srv = apr_poll(pollset, &n, -1); - - if (srv != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(srv)) { - continue; - } - - /* apr_poll() will only return errors in catastrophic - * circumstances. Let's try exiting gracefully, for now. */ - ap_log_error(APLOG_MARK, APLOG_ERR, srv, (const server_rec *) - ap_server_conf, "apr_poll: (listen)"); - workers_may_exit = 1; - } - if (workers_may_exit) break; - - apr_poll_revents_get(&event, listenfds[0], pollset); - if (event & APR_POLLIN) { - /* A process got a signal on the shutdown pipe. Check if we're - * the lucky process to die. */ - check_pipe_of_death(); - continue; - } - - apr_poll_revents_get(&event, listenfds[1], pollset); - if (event & APR_POLLIN || event & APR_POLLOUT) { - /* This request is from another child in our current process. - * We should set a flag here, and then below we will read - * two bytes (the socket number and the NULL byte. - */ - thread_socket_table[thread_num] = -2; - goto got_from_other_child; - } - - if (num_listenfds == 1) { - sd = ap_listeners->sd; - goto got_fd; - } - else { - /* find a listener */ - curr_pollfd = last_pollfd; - do { - curr_pollfd++; - if (curr_pollfd > num_listenfds) { - curr_pollfd = 1; - } - /* XXX: Should we check for POLLERR? */ - apr_poll_revents_get(&event, listenfds[curr_pollfd], pollset); - if (event & APR_POLLIN) { - last_pollfd = curr_pollfd; - sd = listenfds[curr_pollfd]; - goto got_fd; - } - } while (curr_pollfd != last_pollfd); - } - } - got_fd: - if (!workers_may_exit) { - if ((rv = apr_accept(&csd, sd, ptrans)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, "apr_accept"); - } - if ((rv = SAFE_ACCEPT(apr_lock_release(process_accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_lock_release failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - apr_lock_release(thread_accept_mutex); - apr_lock_acquire(idle_thread_count_mutex); - if (idle_thread_count > min_spare_threads) { - idle_thread_count--; - } - else { - if (!start_thread()) { - idle_thread_count--; - } - } - apr_lock_release(idle_thread_count_mutex); - got_from_other_child: - if (thread_socket_table[thread_num] == -2) { - struct msghdr msg; - struct cmsghdr *cmsg; - char sockname[80]; - struct iovec iov; - int ret, sd, dp; - - iov.iov_base = sockname; - iov.iov_len = 80; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(sd)); - cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sd); - msg.msg_control = (caddr_t)cmsg; - msg.msg_controllen = cmsg->cmsg_len; - msg.msg_flags = 0; - - ret = recvmsg(child_info_table[child_num].sd, &msg, 0); - - memcpy(&dp, CMSG_DATA(cmsg), sizeof(dp)); - - thread_socket_table[thread_num] = dp; - apr_os_sock_put(&csd, &child_info_table[child_num].sd, ptrans); - } - if (setjmp(jmpbuffer) != 1) { - process_socket(ptrans, csd, conn_id); - } - else { - thread_socket_table[thread_num] = -1; - } - requests_this_child--; - } else { - if ((rv = SAFE_ACCEPT(apr_lock_release(process_accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_lock_release failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - apr_lock_release(thread_accept_mutex); - apr_lock_acquire(idle_thread_count_mutex); - idle_thread_count--; - apr_lock_release(idle_thread_count_mutex); - break; - } - apr_pool_clear(ptrans); - } - - apr_lock_acquire(thread_pool_parent_mutex); - ap_update_child_status(child_num, thread_num, SERVER_DEAD, - (request_rec *) NULL); - apr_pool_destroy(tpool); - apr_lock_release(thread_pool_parent_mutex); - apr_lock_acquire(worker_thread_count_mutex); - worker_thread_count--; - worker_thread_free_ids[worker_thread_count] = thread_num; - if (worker_thread_count == 0) { - /* All the threads have exited, now finish the shutdown process - * by signalling the sigwait thread */ - kill(my_pid, SIGTERM); - } - apr_lock_release(worker_thread_count_mutex); - - return NULL; -} - -/* 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 int set_group_privs(uid_t uid, gid_t gid) -{ - if (!geteuid()) { - const char *name; - - /* Get username if passed as a uid */ - - struct passwd *ent; - - if ((ent = getpwuid(uid)) == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "getpwuid: couldn't determine user name from uid %u, " - "you probably need to modify the User directive", - (unsigned)uid); - return -1; - } - - name = ent->pw_name; - - /* - * Set the GID before initgroups(), since on some platforms - * setgid() is known to zap the group list. - */ - if (setgid(gid) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "setgid: unable to set group id to Group %u", - (unsigned)gid); - return -1; - } - - /* Reset `groups' attributes. */ - - if (initgroups(name, gid) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "initgroups: unable to set groups for User %s " - "and Group %u", name, (unsigned)gid); - return -1; - } - } - return 0; -} - - -static int perchild_setup_child(int childnum) -{ - child_info_t *ug = &child_info_table[childnum]; - - if (ug->uid == -1 && ug->gid == -1) { - return unixd_setup_child(); - } - if (set_group_privs(ug->uid, ug->gid)) { - return -1; - } - /* Only try to switch if we're running as root */ - if (!geteuid() && ( -#ifdef _OSD_POSIX - os_init_job_environment(server_conf, unixd_config.user_name, one_process) != 0 || -#endif - setuid(ug->uid) == -1)) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "setuid: unable to change to uid: %ld", - (long) ug->uid); - return -1; - } - return 0; -} - -static int check_signal(int signum) -{ - switch (signum) { - case SIGTERM: - case SIGINT: - just_die(signum); - return 1; - } - return 0; -} - -static void child_main(int child_num_arg) -{ - int i; - ap_listen_rec *lr; - apr_status_t rv; - apr_thread_t *thread; - - my_pid = getpid(); - child_num = child_num_arg; - apr_pool_create(&pchild, pconf); - - /*stuff to do before we switch id's, so we have permissions.*/ - - rv = SAFE_ACCEPT(apr_lock_child_init(&process_accept_mutex, lock_fname, - pchild)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize cross-process lock in child"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (perchild_setup_child(child_num)) { - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_run_child_init(pchild, ap_server_conf); - - /*done with init critical section */ - - apr_setup_signal_thread(); - - requests_this_child = max_requests_per_child; - - /* Set up the pollfd array, num_listenfds + 1 for the pipe and 1 for - * the child socket. - */ - listenfds = apr_pcalloc(pchild, sizeof(*listenfds) * (num_listenfds + 2)); -#if APR_FILES_AS_SOCKETS - apr_socket_from_file(&listenfds[0], pipe_of_death_in); -#endif - - /* The child socket */ - apr_os_sock_put(&listenfds[1], &child_info_table[child_num].sd, pchild); - - num_listenfds++; - for (lr = ap_listeners, i = 2; i <= num_listenfds; lr = lr->next, ++i) - listenfds[i]=lr->sd; - - /* Setup worker threads */ - - if (threads_to_start > max_threads) { - threads_to_start = max_threads; - } - idle_thread_count = threads_to_start; - worker_thread_count = 0; - for (i = 0; i < max_threads; i++) { - worker_thread_free_ids[i] = i; - } - apr_pool_create(&thread_pool_parent, pchild); - apr_lock_create(&thread_pool_parent_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - apr_lock_create(&idle_thread_count_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - apr_lock_create(&worker_thread_count_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - apr_lock_create(&pipe_of_death_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - apr_lock_create(&thread_accept_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - - apr_threadattr_create(&worker_thread_attr, pchild); - apr_threadattr_detach_set(worker_thread_attr, 1); - - /* We are creating worker threads right now */ - for (i=0; i < threads_to_start; i++) { - /* start_thread shouldn't fail here */ - if (!start_thread()) { - break; - } - } - - apr_signal_thread(check_signal); -} - -static int make_child(server_rec *s, int slot) -{ - int pid; - - if (slot + 1 > ap_max_daemons_limit) { - ap_max_daemons_limit = slot + 1; - } - - if (one_process) { - set_signals(); - ap_child_table[slot].pid = getpid(); - ap_child_table[slot].status = SERVER_ALIVE; - child_main(slot); - } - (void) ap_update_child_status(slot, 0, SERVER_STARTING, (request_rec *) NULL); - - if ((pid = fork()) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, - "fork: Unable to fork new process"); - /* 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 <sys/processor.h> - int status = bindprocessor(BINDPROCESS, (int)getpid(), - PROCESSOR_CLASS_ANY); - if (status != OK) - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, errno, - ap_server_conf, "processor unbind failed %d", status); -#endif - - RAISE_SIGSTOP(MAKE_CHILD); - - /* XXX - For an unthreaded server, a signal handler will be necessary - apr_signal(SIGTERM, just_die); - */ - child_main(slot); - clean_child_exit(0); - } - /* else */ - ap_child_table[slot].pid = pid; - ap_child_table[slot].status = SERVER_ALIVE; - - return 0; -} - -/* start up a bunch of children */ -static int startup_children(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < num_daemons; ++i) { - if (ap_child_table[i].pid) { - continue; - } - if (make_child(ap_server_conf, i) < 0) { - break; - } - --number_to_start; - } - return number_to_start; -} - - -/* - * spawn_rate is the number of children that will be spawned on the - * next maintenance cycle if there aren't enough servers. It is - * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by - * without the need to spawn. - */ -static int spawn_rate = 1; -#ifndef MAX_SPAWN_RATE -#define MAX_SPAWN_RATE (32) -#endif -static int hold_off_on_exponential_spawning; - -static void perform_child_maintenance(void) -{ - int i; - int free_length; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead = -1; - - /* initialize the free_list */ - free_length = 0; - - for (i = 0; i < num_daemons; ++i) { - if (ap_child_table[i].pid == 0) { - if (free_length < spawn_rate) { - free_slots[free_length] = i; - ++free_length; - } - } - else { - last_non_dead = i; - } - - if (i >= ap_max_daemons_limit && free_length >= spawn_rate) { - break; - } - } - ap_max_daemons_limit = last_non_dead + 1; - - if (free_length > 0) { - for (i = 0; i < free_length; ++i) { - make_child(ap_server_conf, free_slots[i]); - } - /* 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 (spawn_rate < MAX_SPAWN_RATE) { - spawn_rate *= 2; - } - } - else { - spawn_rate = 1; - } -} - -static void server_main_loop(int remaining_children_to_start) -{ - int child_slot; - apr_wait_t status; - apr_proc_t pid; - int i; - - while (!restart_pending && !shutdown_pending) { - ap_wait_or_timeout(&status, &pid, pconf); - - if (pid.pid != -1) { - ap_process_child_status(&pid, status); - /* non-fatal death... note that it's gone in the child table and - * clean out the status table. */ - child_slot = -1; - for (i = 0; i < ap_max_daemons_limit; ++i) { - if (ap_child_table[i].pid == pid.pid) { - child_slot = i; - break; - } - } - if (child_slot >= 0) { - ap_child_table[child_slot].pid = 0; - ap_update_child_status(child_slot, i, SERVER_DEAD, (request_rec *) NULL); - - - if (remaining_children_to_start - && child_slot < num_daemons) { - /* we're still doing a 1-for-1 replacement of dead - * children with new children - */ - make_child(ap_server_conf, child_slot); - --remaining_children_to_start; - } -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&pid, status) == 0) { - /* handled */ -#endif - } - else if (is_graceful) { - /* Great, we've probably just lost a slot in the - * child table. Somehow we don't know about this - * child. - */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, - ap_server_conf, - "long lost child came home! (pid %ld)", - (long)pid.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. - */ - remaining_children_to_start = \ - startup_children(remaining_children_to_start); - /* 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_child_maintenance(); - } -} - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int remaining_children_to_start; - int i; - apr_status_t rv; - apr_size_t one = 1; - - pconf = _pconf; - ap_server_conf = s; - if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out, pconf)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, - (const server_rec*) ap_server_conf, - "apr_file_pipe_create (pipe_of_death)"); - exit(1); - } - if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, - (const server_rec*) ap_server_conf, - "apr_file_pipe_timeout_set (pipe_of_death)"); - exit(1); - } - ap_server_conf = s; - if ((num_listenfds = ap_setup_listeners(ap_server_conf)) < 1) { - /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s, - "no listening sockets available, shutting down"); - return 1; - } - ap_log_pid(pconf, ap_pid_fname); - - /* Initialize cross-process accept lock */ - lock_fname = apr_psprintf(_pconf, "%s.%u", - ap_server_root_relative(_pconf, lock_fname), - my_pid); - rv = SAFE_ACCEPT(apr_lock_create(&process_accept_mutex, APR_MUTEX, - APR_CROSS_PROCESS, lock_fname, _pconf)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't create cross-process lock"); - return 1; - } - - if (!is_graceful) { - ap_create_scoreboard(pconf, SB_SHARED); - } - /* Initialize the child table */ - if (!is_graceful) { - for (i = 0; i < HARD_SERVER_LIMIT; i++) { - ap_child_table[i].pid = 0; - } - } - - set_signals(); - - /* 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 SIGWINCH). 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 = num_daemons; - if (!is_graceful) { - remaining_children_to_start = \ - startup_children(remaining_children_to_start); - } - 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, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); - restart_pending = shutdown_pending = 0; - - server_main_loop(remaining_children_to_start); - - if (shutdown_pending) { - /* Time to gracefully shut down: - * Kill child processes, tell them to call child_exit, etc... - */ - if (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "killpg SIGTERM"); - } - ap_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, 0, - ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - } - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, - ap_server_conf, "caught SIGTERM, shutting down"); - - return 1; - } - - /* we've been told to restart */ - apr_signal(SIGHUP, SIG_IGN); - - if (one_process) { - /* not worth thinking about */ - return 1; - } - - if (is_graceful) { - char char_of_death = '!'; - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "SIGWINCH received. Doing graceful restart"); - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. - */ - - for (i = 0; i < num_daemons; ++i) { - if (ap_child_table[i].pid) { - ap_child_table[i].status = SERVER_DYING; - } - } - /* give the children the signal to die */ - for (i = 0; i < num_daemons;) { - if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(rv)) continue; - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, - "write pipe_of_death"); - } - i++; - } - } - else { - /* Kill 'em all. Since the child acts the same on the parents SIGTERM - * and a SIGHUP, we may as well use the same signal, because some user - * pthreads are stealing signals from us left and right. - */ - if (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "killpg SIGTERM"); - } - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, - ap_server_conf, "SIGHUP received. Attempting to restart"); - } - return 0; -} - -static void perchild_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach = 0; - int i; - - one_process = !!ap_exists_config_define("ONE_PROCESS"); - no_detach = !!ap_exists_config_define("NO_DETACH"); - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !no_detach) { - apr_proc_detach(); - } - - my_pid = getpid(); - } - - unixd_pre_config(ptemp); - ap_listen_pre_config(); - num_daemons = DEFAULT_NUM_DAEMON; - threads_to_start = DEFAULT_START_THREAD; - min_spare_threads = DEFAULT_MIN_SPARE_THREAD; - max_spare_threads = DEFAULT_MAX_SPARE_THREAD; - max_threads = HARD_THREAD_LIMIT; - ap_pid_fname = DEFAULT_PIDLOG; - ap_scoreboard_fname = DEFAULT_SCOREBOARD; - lock_fname = DEFAULT_LOCKFILE; - max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - curr_child_num = 0; - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - for (i = 0; i < HARD_SERVER_LIMIT; i++) { - child_info_table[i].uid = -1; - child_info_table[i].gid = -1; - child_info_table[i].sd = -1; - } - for (i = 0; i < HARD_THREAD_LIMIT; i++) { - thread_socket_table[i] = -1; - } -} - -static int pass_request(request_rec *r) -{ - apr_socket_t *thesock = r->connection->client_socket; - struct msghdr msg; - struct cmsghdr *cmsg; - int sfd; - struct iovec iov; - apr_bucket_brigade *bb = apr_brigade_create(r->pool); - perchild_server_conf *sconf = (perchild_server_conf *) - ap_get_module_config(r->server->module_config, - &mpm_perchild_module); - char *foo; - apr_size_t len; - apr_size_t readbytes = 0; - - apr_pool_userdata_get((void **)&foo, "PERCHILD_BUFFER", r->connection->pool); - len = strlen(foo); - - apr_pool_userdata_set(NULL, "PERCHILD_BUFFER", apr_pool_cleanup_null, - r->connection->pool); - - apr_os_sock_get(&sfd, thesock); - - iov.iov_base = NULL; - iov.iov_len = 0; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sfd)); - cmsg->cmsg_len = sizeof(*cmsg) + sizeof(int); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - - memcpy(CMSG_DATA(cmsg), &sfd, sizeof(sfd)); - - msg.msg_control = (caddr_t)cmsg; - msg.msg_controllen = cmsg->cmsg_len; - msg.msg_flags=0; - - if (sendmsg(sconf->sd2, &msg, 0) == -1) { - apr_pool_destroy(r->pool); - return -1; - } - - write(sconf->sd2, foo, len); - - while (ap_get_brigade(r->input_filters, bb, AP_MODE_NONBLOCKING, &readbytes) == APR_SUCCESS) { - apr_bucket *e; - APR_BRIGADE_FOREACH(e, bb) { - const char *str; - - apr_bucket_read(e, &str, &len, APR_NONBLOCK_READ); - write(sconf->sd2, str, len); - } - } - - apr_pool_destroy(r->pool); - return 1; -} - -static char *make_perchild_socket(const char *fullsockname, int sd[2]) -{ - socketpair(PF_UNIX, SOCK_STREAM, 0, sd); - return NULL; -} - - -static void perchild_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - int i; - server_rec *sr; - perchild_server_conf *sconf; - int def_sd[2]; - - def_sd[0] = -1; - def_sd[1] = -1; - - for (sr = s; sr; sr = sr->next) { - sconf = (perchild_server_conf *)ap_get_module_config(sr->module_config, - &mpm_perchild_module); - - if (sconf->sd == -1) { - sconf->fullsockname = apr_pstrcat(sr->process->pool, - sconf->sockname, ".DEFAULT", NULL); - if (def_sd[0] == -1) { - if (!make_perchild_socket(sconf->fullsockname, def_sd)) { - /* log error */ - } - } - sconf->sd = def_sd[0]; - sconf->sd2 = def_sd[1]; - } - } - - for (i = 0; i < num_daemons; i++) { - if (child_info_table[i].uid == -1) { - child_info_table[i].sd = def_sd[0]; - } - } -} - -static int perchild_post_read(request_rec *r) -{ - ap_filter_t *f = r->connection->input_filters; - int thread_num = r->connection->id % HARD_THREAD_LIMIT; - perchild_server_conf *sconf = (perchild_server_conf *) - ap_get_module_config(r->server->module_config, - &mpm_perchild_module); - - while (f) { - if (!strcmp("PERCHILD_BUFFER", f->frec->name)) { - ap_remove_output_filter(f); - break; - } - f = f->next; - } - - if (thread_socket_table[thread_num] != -1) { - apr_socket_t *csd = NULL; - - apr_os_sock_put(&csd, &thread_socket_table[thread_num], - r->connection->pool); - ap_sock_disable_nagle(csd); - r->connection->client_socket = csd; - return OK; - } - else { - if (sconf->sd != child_info_table[child_num].sd) { - if (pass_request(r) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, - ap_server_conf, "Could not pass request to proper " - "child, request will not be honored."); - } - longjmp(jmpbuffer, 1); - } - return OK; - } - return OK; -} - -static apr_status_t perchild_buffer(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_size_t *readbytes) -{ - apr_bucket *e; - apr_status_t rv; - char *buffer = NULL; - const char *str; - apr_size_t len; - - if ((rv = ap_get_brigade(f->next, b, mode, readbytes)) != APR_SUCCESS) { - return rv; - } - - apr_pool_userdata_get((void **)&buffer, "PERCHILD_BUFFER", f->c->pool); - - APR_BRIGADE_FOREACH(e, b) { - if (e->length != 0) { - apr_bucket_read(e, &str, &len, APR_NONBLOCK_READ); - - if (buffer == NULL) { - buffer = apr_pstrndup(f->c->pool, str, len); - } - else { - buffer = apr_pstrcat(f->c->pool, buffer, - apr_pstrndup(f->c->pool, str, len), NULL); - } - } - } - apr_pool_userdata_set(buffer, "PERCHILD_BUFFER", apr_pool_cleanup_null, f->c->pool); - - return APR_SUCCESS; -} - -static int perchild_pre_connection(conn_rec *c) -{ - ap_add_input_filter("PERCHILD_BUFFER", NULL, NULL, c); - return OK; -} - -static void perchild_hooks(apr_pool_t *p) -{ - one_process = 0; - - ap_hook_pre_config(perchild_pre_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(perchild_post_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_pre_connection(perchild_pre_connection,NULL,NULL, APR_HOOK_MIDDLE); - - /* This must be run absolutely first. If this request isn't for this - * server then we need to forward it to the proper child. No sense - * tying up this server running more post_read request hooks if it is - * just going to be forwarded along. - */ - ap_hook_post_read_request(perchild_post_read, NULL, NULL, APR_HOOK_REALLY_FIRST); - ap_register_input_filter("PERCHILD_BUFFER", perchild_buffer, AP_FTYPE_CONTENT); -} - -static const char *set_pidfile(cmd_parms *cmd, void *dummy, const 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 <VirtualHost>"; - } - ap_pid_fname = arg; - return NULL; -} - -static const char *set_scoreboard(cmd_parms *cmd, void *dummy, const 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, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - lock_fname = arg; - return NULL; -} -static const char *set_num_daemons (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - num_daemons = atoi(arg); - if (num_daemons > HARD_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: NumServers of %d exceeds compile time limit " - "of %d servers,", num_daemons, HARD_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering NumServers to %d. To increase, please " - "see the", HARD_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " HARD_SERVER_LIMIT define in %s.", - AP_MPM_HARD_LIMITS_FILE); - num_daemons = HARD_SERVER_LIMIT; - } - else if (num_daemons < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: Require NumServers > 0, setting to 1"); - num_daemons = 1; - } - return NULL; -} - -static const char *set_threads_to_start (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - threads_to_start = atoi(arg); - if (threads_to_start > HARD_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: StartThreads of %d exceeds compile time" - " limit of %d threads,", threads_to_start, - HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering StartThreads to %d. To increase, please" - " see the", HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " HARD_THREAD_LIMIT define in %s.", - AP_MPM_HARD_LIMITS_FILE); - } - else if (threads_to_start < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: Require StartThreads > 0, setting to 1"); - threads_to_start = 1; - } - return NULL; -} - -static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - min_spare_threads = atoi(arg); - if (min_spare_threads <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - - return NULL; -} - -static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - max_spare_threads = atoi(arg); - if (max_spare_threads >= HARD_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: detected MinSpareThreads set higher than"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "HARD_THREAD_LIMIT. Resetting to %d", HARD_THREAD_LIMIT); - max_spare_threads = HARD_THREAD_LIMIT; - } - return NULL; -} - -static const char *set_max_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - max_threads = atoi(arg); - if (max_threads > HARD_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: detected MaxThreadsPerChild set higher than"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "HARD_THREAD_LIMIT. Resetting to %d", HARD_THREAD_LIMIT); - max_threads = HARD_THREAD_LIMIT; - } - return NULL; -} - -static const char *set_max_requests(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - max_requests_per_child = atoi(arg); - - return NULL; -} - -static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, - const char *arg) -{ - apr_finfo_t finfo; - const char *fname; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - fname = ap_server_root_relative(cmd->pool, arg); - if ((apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) - || (finfo.filetype != APR_DIR)) { - return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, - " does not exist or is not a directory", NULL); - } - apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir)); - return NULL; -} - -static const char *set_child_per_uid(cmd_parms *cmd, void *dummy, const char *u, - const char *g, const char *num) -{ - int i; - int max_this_time = atoi(num) + curr_child_num; - for (i = curr_child_num; i < max_this_time; i++, curr_child_num++); { - child_info_t *ug = &child_info_table[i - 1]; - - if (i > num_daemons) { - return "Trying to use more child ID's than NumServers. Increase " - "NumServers in your config file."; - } - - ug->uid = atoi(u); - ug->gid = atoi(g); - } - return NULL; -} - -static const char *assign_childuid(cmd_parms *cmd, void *dummy, const char *uid, - const char *gid) -{ - int i; - int u = atoi(uid); - int g = atoi(gid); - const char *errstr; - int socks[2]; - perchild_server_conf *sconf = (perchild_server_conf *) - ap_get_module_config(cmd->server->module_config, - &mpm_perchild_module); - - sconf->fullsockname = apr_pstrcat(cmd->pool, sconf->sockname, ".", uid, ":", gid, NULL); - - if ((errstr = make_perchild_socket(sconf->fullsockname, socks))) { - return errstr; - } - - sconf->sd = socks[0]; - sconf->sd2 = socks[1]; - - for (i = 0; i < num_daemons; i++) { - if (u == child_info_table[i].uid && g == child_info_table[i].gid) { - child_info_table[i].sd = sconf->sd; - } - } - - return NULL; -} - - -static const command_rec perchild_cmds[] = { -UNIX_DAEMON_COMMANDS -LISTEN_COMMANDS -AP_INIT_TAKE1("PidFile", set_pidfile, NULL, RSRC_CONF, - "A file for logging the server process ID"), -AP_INIT_TAKE1("ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, - "A file for Apache to maintain runtime process management information"), -AP_INIT_TAKE1("LockFile", set_lockfile, NULL, RSRC_CONF, - "The lockfile used when Apache needs to lock the accept() call"), -AP_INIT_TAKE1("NumServers", set_num_daemons, NULL, RSRC_CONF, - "Number of children alive at the same time"), -AP_INIT_TAKE1("StartThreads", set_threads_to_start, NULL, RSRC_CONF, - "Number of threads each child creates"), -AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, - "Minimum number of idle threads per child, to handle request spikes"), -AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, - "Maximum number of idle threads per child"), -AP_INIT_TAKE1("MaxThreadsPerChild", set_max_threads, NULL, RSRC_CONF, - "Maximum number of threads per child"), -AP_INIT_TAKE1("MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, - "Maximum number of requests a particular child serves before dying."), -AP_INIT_TAKE1("CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, - "The location of the directory Apache changes to before dumping core"), -AP_INIT_TAKE3("ChildperUserID", set_child_per_uid, NULL, RSRC_CONF, - "Specify a User and Group for a specific child process."), -AP_INIT_TAKE2("AssignUserID", assign_childuid, NULL, RSRC_CONF, - "Tie a virtual host to a specific child process."), -{ NULL } -}; - -static void *perchild_create_config(apr_pool_t *p, server_rec *s) -{ - perchild_server_conf *c = - (perchild_server_conf *) apr_pcalloc(p, sizeof(perchild_server_conf)); - - c->sd = -1; - return c; -} - -module AP_MODULE_DECLARE_DATA mpm_perchild_module = { - MPM20_MODULE_STUFF, - NULL, /* hook to run before apache parses args */ - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - perchild_create_config, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - perchild_cmds, /* command apr_table_t */ - perchild_hooks /* register_hooks */ -}; - diff --git a/server/mpm/monitoring-services.txt b/server/mpm/monitoring-services.txt deleted file mode 100644 index 2466589025..0000000000 --- a/server/mpm/monitoring-services.txt +++ /dev/null @@ -1,94 +0,0 @@ -From: William A. Rowe, Jr. -Date: June 7th '00 -Subject: service monitoring in Apache 1.3.13 - -The concept for a taskbar monitor has been thrown around -for a very long while. 1.3.13 introduced Win9x services, -and that added fuel to the mix. Here are some sideband -observations I've made for other developers... - -About Apache as a console, don't start Apache hidden without -any command line arguments if you want to launch it yourself -in a hidden window (it will do the classic test for -AllocConsole/FreeConsole)... drop in some arguments such as -the -f or -r option and it will fly without thinking it is a -service under 9x and NT. - -Rule two, don't use --ntservice as an argument, ever. Only -the Windows NT Service Control Manager is allowed to pass that -flag, and only that flag, when it runs Apache.exe. Do use ---ntservice as the sole argument to the executable name if -you are installing an Apache NT service yourself. - -Rule three, use -k start and -n name when maintaining the -HKLM/Software/Microsoft/Windows/CurrentVersion/RunServices -list, since there is no other way for Apache to know what -the service is named :) And look at any 9x installed service's -RunServices entry in the registry for the start service semantic. - -Rule four, use the WinNT Service Control Manager exclusively -for starting, stopping and restarting Apache as an NT service. -The restart signal is the value 128, as documented in service.h -and service.c - this will continue to work in Apache 2.0. If -it fails, you are handling an older version (pre 1.3.13) of -Apache, and need to stop and then start the service instead. - -Rule five, use the legacy pid-named events to signal Win9x -service Apache to restart and stop the service. But don't -bother looking for httpd.pid files... you can get the pid -right from the hidden service control window. Apache 1.3.13 -and 2.x create a hidden window named for the name of the -service (without the spaces), with a window class of -"ApacheWin95ServiceMonitor", so can use FindWindow to track -down running Win9x services. See the service.c code for how -I accomplished this pretty simply in the -k stop/-k restart -handler. - -Taskbar Monitor App -------------------- - -Basic requirements: a C code application using strictly the -Win32 API, and not MFC or other Win32 frameworks. Could use -the service.c module to share some basic functions. That -module could be extended in Apache 2.0 to make this all easier. - -I think we are looking for an external app that simply acts -as a monitor or allows a stopped service to be started. If -the user logs off, we loose the monitor app, but installed as -a shortcut in the Start group or in the registry key -HKLM/Software/Microsoft/Windows/CurrentVersion/Run -we will be just fine. I'd like to see the monitor run only -one instance to monitor all running services, for memory -and resource conservation. - -I was thinking that the hover/iconbar title would tell them -"Test service is running", or "Test service is stopped". -If they left click, they could stop or restart, or simply -start if it is stopped. There could be a preference that -each service doesn't get it's own individual task icon unless -it is running, if it is a manual start service (or missing -from the RunServices list, which is the equivilant under 9x). - -If a specific service is set to Auto start or is in the -RunServices Win9x registry key, we must show them the stopped -icon, of course. We might also keep the icon for any running -service that stops abruptly. But there could be a 'single -icon' option for the taskbar icon monitor that says show only -a single status icon, for simplicity if the administrator runs -many Apache services. - -But I was hoping that any right click would provide a menu -of all Apache services with their status. e.g. - Test service is stopped - Apache_2 service is running - MyWeb service is running -and each would do the logical submenu, same as if that -specific taskbar icon were left clicked, offering to start or -offering to stop or restart the server, as appropriate. - -Finally, to identify all installed Apache services, just query -the registry key HKLM\SYSTEM\CurrentControlSet\Services for any -key that has the ImagePath value of "...\Apache.exe"... (quotes -are significant here, if the leading quote is ommitted the -entire string ends with the text \Apache.exe - based on Apache's -own service installer in every released version.) diff --git a/server/mpm/perchild/.cvsignore b/server/mpm/perchild/.cvsignore deleted file mode 100644 index 84df257214..0000000000 --- a/server/mpm/perchild/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -.deps -.libs -*.lo -*.la -Makefile diff --git a/server/mpm/perchild/Makefile.in b/server/mpm/perchild/Makefile.in deleted file mode 100644 index 374f130646..0000000000 --- a/server/mpm/perchild/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libperchild.la -LTLIBRARY_SOURCES = perchild.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/server/mpm/perchild/config5.m4 b/server/mpm/perchild/config5.m4 deleted file mode 100644 index bd179baed9..0000000000 --- a/server/mpm/perchild/config5.m4 +++ /dev/null @@ -1,6 +0,0 @@ -dnl ## XXX - Need a more thorough check of the proper flags to use - -if test "$MPM_NAME" = "perchild" ; then - - APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile) -fi diff --git a/server/mpm/perchild/mpm.h b/server/mpm/perchild/mpm.h deleted file mode 100644 index d24f8b4aba..0000000000 --- a/server/mpm/perchild/mpm.h +++ /dev/null @@ -1,91 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "httpd.h" -#include "mpm_default.h" -#include "unixd.h" - -#ifndef APACHE_MPM_PERCHILD_H -#define APACHE_MPM_PERCHILD_H - -#define PERCHILD_MPM - -#define MPM_NAME "Perchild" - -#define AP_MPM_NEEDS_RECLAIM_CHILD_PROCESSES 1 -#define MPM_SYNC_CHILD_TABLE() -#define MPM_CHILD_PID(i) (ap_child_table[i].pid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) - -/* Table of child status */ -#define SERVER_DEAD 0 -#define SERVER_DYING 1 -#define SERVER_ALIVE 2 - -typedef struct ap_ctable{ - pid_t pid; - unsigned char status; -} ap_ctable; - -extern int ap_threads_per_child; -extern int ap_max_daemons_limit; -extern ap_ctable ap_child_table[HARD_SERVER_LIMIT]; -extern server_rec *ap_server_conf; -extern char ap_coredump_dir[MAX_STRING_LEN]; - -#endif /* APACHE_MPM_PERCHILD_H */ diff --git a/server/mpm/perchild/mpm_default.h b/server/mpm/perchild/mpm_default.h deleted file mode 100644 index f462ea8f90..0000000000 --- a/server/mpm/perchild/mpm_default.h +++ /dev/null @@ -1,147 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -#define AP_ID_FROM_CHILD_THREAD(c, t) ((c * HARD_THREAD_LIMIT) + t) -#define AP_CHILD_THREAD_FROM_ID(i) (i / HARD_THREAD_LIMIT), (i % HARD_THREAD_LIMIT) - -/* Number of threads to spawn off by default --- also, if fewer than - * this free when the caretaker checks, it will spawn more. - */ -#ifndef DEFAULT_START_THREAD -#define DEFAULT_START_THREAD 5 -#endif - -/* Maximum number of *free* server threads --- more than this, and - * they will die off. - */ - -#ifndef DEFAULT_MAX_SPARE_THREAD -#define DEFAULT_MAX_SPARE_THREAD 10 -#endif - -/* Minimum --- fewer than this, and more will be created */ - -#ifndef DEFAULT_MIN_SPARE_THREAD -#define DEFAULT_MIN_SPARE_THREAD 5 -#endif - -/* Limit on the threads per process. Clients will be locked out if more than - * this * HARD_SERVER_LIMIT are needed. - * - * We keep this for one reason 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_THREAD_LIMIT -#define HARD_THREAD_LIMIT 64 -#endif - -/* Number of servers to spawn off by default - */ -#ifndef DEFAULT_NUM_DAEMON -#define DEFAULT_NUM_DAEMON 2 -#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 -#define HARD_SERVER_LIMIT 8 -#endif - -/* File used for accept locking, when we use a file */ -#ifndef DEFAULT_LOCKFILE -#define DEFAULT_LOCKFILE "logs/accept.lock" -#endif - -/* Scoreboard file, if there is one */ -#ifndef DEFAULT_SCOREBOARD -#define DEFAULT_SCOREBOARD "logs/apache_runtime_status" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG "logs/httpd.pid" -#endif - -/* - * Interval, in microseconds, between scoreboard maintenance. - */ -#ifndef SCOREBOARD_MAINTENANCE_INTERVAL -#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 -#endif - -/* Number of requests to try to handle in a single process. If <= 0, - * the children don't die off. - */ -#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD -#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 -#endif - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/server/mpm/perchild/perchild.c b/server/mpm/perchild/perchild.c deleted file mode 100644 index 0fa14997b1..0000000000 --- a/server/mpm/perchild/perchild.c +++ /dev/null @@ -1,1829 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr_hash.h" -#include "apr_strings.h" -#include "apr_pools.h" -#include "apr_portable.h" -#include "apr_file_io.h" -#include "apr_signal.h" - -#define APR_WANT_IOVEC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif - -#if !APR_HAS_THREADS -#error The perchild MPM requires APR threads, but they are unavailable. -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" /* for read_config */ -#include "http_core.h" /* for get_remote_host */ -#include "http_protocol.h" -#include "http_connection.h" -#include "ap_mpm.h" -#include "unixd.h" -#include "mpm_common.h" -#include "ap_listen.h" -#include "mpm_default.h" -#include "mpm.h" -#include "scoreboard.h" -#include "util_filter.h" - -/* ### should be APR-ized */ -#include <poll.h> -#include <grp.h> -#include <pwd.h> -#include <sys/stat.h> -#include <sys/un.h> -#include <setjmp.h> - -/* - * Actual definitions of config globals - */ - -static int threads_to_start = 0; /* Worker threads per child */ -static int min_spare_threads = 0; -static int max_spare_threads = 0; -static int max_threads = 0; -static int max_requests_per_child = 0; -static const char *ap_pid_fname=NULL; -static int num_daemons=0; -static int curr_child_num=0; -static int workers_may_exit = 0; -static int requests_this_child; -static int num_listenfds = 0; -static apr_socket_t **listenfds; -static jmp_buf jmpbuffer; - -struct child_info_t { - uid_t uid; - gid_t gid; - int sd; -}; - -typedef struct { - const char *sockname; /* The base name for the socket */ - const char *fullsockname; /* socket base name + extension */ - int sd; /* The socket descriptor */ - int sd2; /* The socket descriptor */ -} perchild_server_conf; - -typedef struct child_info_t child_info_t; - -/* Tables used to determine the user and group each child process should - * run as. The hash table is used to correlate a server name with a child - * process. - */ -static child_info_t child_info_table[HARD_SERVER_LIMIT]; -static int thread_socket_table[HARD_THREAD_LIMIT]; - - -struct ap_ctable ap_child_table[HARD_SERVER_LIMIT]; - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with NumServers changes across SIGWINCH restarts. We use this - * value to optimize routines that have to scan the entire child table. - * - * XXX - It might not be worth keeping this code in. There aren't very - * many child processes in this MPM. - */ -int ap_max_daemons_limit = -1; -int ap_threads_per_child = HARD_THREAD_LIMIT; - -char ap_coredump_dir[MAX_STRING_LEN]; - -module AP_MODULE_DECLARE_DATA mpm_perchild_module; - -static apr_file_t *pipe_of_death_in = NULL; -static apr_file_t *pipe_of_death_out = NULL; -static apr_lock_t *pipe_of_death_mutex; - -/* *Non*-shared http_main globals... */ - -server_rec *ap_server_conf; - -/* 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; - -#ifdef DEBUG_SIGSTOP -int raise_sigstop_flags; -#endif - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ -static apr_pool_t *thread_pool_parent; /* Parent of per-thread pools */ -static apr_lock_t *thread_pool_parent_mutex; - -static int child_num; -static unsigned int my_pid; /* Linux getpid() doesn't work except in - main thread. Use this instead */ -/* Keep track of the number of worker threads currently active */ -static int worker_thread_count; -static apr_lock_t *worker_thread_count_mutex; -static int worker_thread_free_ids[HARD_THREAD_LIMIT]; -static apr_threadattr_t *worker_thread_attr; - -/* Keep track of the number of idle worker threads */ -static int idle_thread_count; -static apr_lock_t *idle_thread_count_mutex; - -/* Locks for accept serialization */ -#ifdef NO_SERIALIZED_ACCEPT -#define SAFE_ACCEPT(stmt) APR_SUCCESS -#else -#define SAFE_ACCEPT(stmt) (stmt) -static apr_lock_t *process_accept_mutex; -#endif /* NO_SERIALIZED_ACCEPT */ -static const char *lock_fname; -static apr_lock_t *thread_accept_mutex; - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMONS: - *result = ap_max_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_STATIC; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = max_threads; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -/* a clean exit from a child with proper cleanup */ -static void clean_child_exit(int code) -{ - if (pchild) { - apr_pool_destroy(pchild); - } - exit(code); -} - -/* handle all varieties of core dumping signals */ -static void sig_coredump(int sig) -{ - chdir(ap_coredump_dir); - apr_signal(sig, SIG_DFL); - kill(getpid(), sig); - /* 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. - */ -} - -static void just_die(int sig) -{ - clean_child_exit(0); -} - -/***************************************************************** - * Connection structures and accounting... - */ - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful; -/* we don't currently track ap_my_generation, but mod_status - * references it so it must be defined */ -ap_generation_t volatile ap_my_generation=0; - -/* - * 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. - * - * These should only be called from the parent process itself, since the - * parent process will use the shutdown_pending and restart_pending variables - * to determine whether to shutdown or restart. The child process should - * call signal_parent() directly to tell the parent to die -- this will - * cause neither of those variable to be set, which the parent will - * assume means something serious is wrong (which it will be, for the - * child to force an exit) and so do an exit anyway. - */ - -static void ap_start_shutdown(void) -{ - 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; -} - -/* do a graceful restart if graceful == 1 */ -static void ap_start_restart(int graceful) -{ - - if (restart_pending == 1) { - /* Probably not an error - don't bother reporting it */ - return; - } - restart_pending = 1; - is_graceful = graceful; - if (is_graceful) { - apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard); - } -} - -static void sig_term(int sig) -{ - ap_start_shutdown(); -} - -static void restart(int sig) -{ -#ifndef WIN32 - ap_start_restart(sig == SIGWINCH); -#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, errno, ap_server_conf, "sigaction(SIGSEGV)"); -#ifdef SIGBUS - if (sigaction(SIGBUS, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)"); -#endif -#ifdef SIGABORT - if (sigaction(SIGABORT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)"); -#endif -#ifdef SIGABRT - if (sigaction(SIGABRT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)"); -#endif -#ifdef SIGILL - if (sigaction(SIGILL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_server_conf, "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_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, errno, ap_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, errno, ap_server_conf, "sigaction(SIGPIPE)"); -#endif - - /* we want to ignore HUPs and WINCH while we're busy processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, SIGWINCH); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); - if (sigaction(SIGWINCH, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGWINCH)"); -#else - if (!one_process) { - apr_signal(SIGSEGV, sig_coredump); -#ifdef SIGBUS - apr_signal(SIGBUS, sig_coredump); -#endif /* SIGBUS */ -#ifdef SIGABORT - apr_signal(SIGABORT, sig_coredump); -#endif /* SIGABORT */ -#ifdef SIGABRT - apr_signal(SIGABRT, sig_coredump); -#endif /* SIGABRT */ -#ifdef SIGILL - apr_signal(SIGILL, sig_coredump); -#endif /* SIGILL */ -#ifdef SIGXCPU - apr_signal(SIGXCPU, SIG_DFL); -#endif /* SIGXCPU */ -#ifdef SIGXFSZ - apr_signal(SIGXFSZ, SIG_DFL); -#endif /* SIGXFSZ */ - } - - apr_signal(SIGTERM, sig_term); -#ifdef SIGHUP - apr_signal(SIGHUP, restart); -#endif /* SIGHUP */ -#ifdef SIGWINCH - apr_signal(SIGWINCH, restart); -#endif /* SIGWINCH */ -#ifdef SIGPIPE - apr_signal(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#endif -} - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -int ap_graceful_stop_signalled(void) -{ - /* XXX - Does this really work? - Manoj */ - return is_graceful; -} - -/***************************************************************** - * Child process main loop. - */ - -static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id) -{ - conn_rec *current_conn; - int csd; - apr_status_t rv; - int thread_num = conn_id % HARD_THREAD_LIMIT; - - if ((rv = apr_os_sock_get(&csd, sock)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get"); - } - - if (csd >= FD_SETSIZE) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, NULL, - "new file descriptor %d is too large; you probably need " - "to rebuild Apache with a larger FD_SETSIZE " - "(currently %d)", - csd, FD_SETSIZE); - apr_socket_close(sock); - return; - } - - if (thread_socket_table[thread_num] < 0) { - ap_sock_disable_nagle(sock); - } - - current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id); - if (current_conn) { - ap_process_connection(current_conn); - ap_lingering_close(current_conn); - } -} - -static void *worker_thread(void *); - -/* Starts a thread as long as we're below max_threads */ -static int start_thread(void) -{ - apr_thread_t *thread; - int rc; - - apr_lock_acquire(worker_thread_count_mutex); - if (worker_thread_count < max_threads - 1) { - if ((rc = apr_thread_create(&thread, worker_thread_attr, worker_thread, - &worker_thread_free_ids[worker_thread_count], pchild))) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rc, ap_server_conf, - "apr_thread_create: unable to create worker thread"); - /* 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 if we exit. */ - sleep(10); - workers_may_exit = 1; - apr_lock_release(worker_thread_count_mutex); - return 0; - } - else { - worker_thread_count++; - } - } - else { - static int reported = 0; - - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ap_server_conf, - "server reached MaxThreadsPerChild setting, consider raising the" - " MaxThreadsPerChild or NumServers settings"); - reported = 1; - } - apr_lock_release(worker_thread_count_mutex); - return 0; - } - apr_lock_release(worker_thread_count_mutex); - return 1; - -} -/* Sets workers_may_exit if we received a character on the pipe_of_death */ -static void check_pipe_of_death(void) -{ - apr_lock_acquire(pipe_of_death_mutex); - if (!workers_may_exit) { - int ret; - char pipe_read_char; - apr_size_t n = 1; - - ret = apr_recv(listenfds[0], &pipe_read_char, &n); - if (APR_STATUS_IS_EAGAIN(ret)) { - /* It lost the lottery. It must continue to suffer - * through a life of servitude. */ - } - else { - /* It won the lottery (or something else is very - * wrong). Embrace death with open arms. */ - workers_may_exit = 1; - } - } - apr_lock_release(pipe_of_death_mutex); -} - -/* idle_thread_count should be incremented before starting a worker_thread */ - -static void *worker_thread(void *arg) -{ - apr_socket_t *csd = NULL; - apr_pool_t *tpool; /* Pool for this thread */ - apr_pool_t *ptrans; /* Pool for per-transaction stuff */ - apr_socket_t *sd = NULL; - int srv; - int curr_pollfd, last_pollfd = 0; - int thread_just_started = 1; - int thread_num = *((int *) arg); - long conn_id = child_num * HARD_THREAD_LIMIT + thread_num; - apr_pollfd_t *pollset; - int n; - apr_status_t rv; - - apr_lock_acquire(thread_pool_parent_mutex); - apr_pool_create(&tpool, thread_pool_parent); - apr_lock_release(thread_pool_parent_mutex); - apr_pool_create(&ptrans, tpool); - - (void) ap_update_child_status(child_num, thread_num, SERVER_STARTING, - (request_rec *) NULL); - - apr_poll_setup(&pollset, num_listenfds+1, tpool); - for(n=0 ; n <= num_listenfds ; ++n) { - apr_poll_socket_add(pollset, listenfds[n], APR_POLLIN); - } - - while (!workers_may_exit) { - workers_may_exit |= (max_requests_per_child != 0) && (requests_this_child <= 0); - if (workers_may_exit) break; - if (!thread_just_started) { - apr_lock_acquire(idle_thread_count_mutex); - if (idle_thread_count < max_spare_threads) { - idle_thread_count++; - apr_lock_release(idle_thread_count_mutex); - } - else { - apr_lock_release(idle_thread_count_mutex); - break; - } - } - else { - thread_just_started = 0; - } - - (void) ap_update_child_status(child_num, thread_num, SERVER_READY, - (request_rec *) NULL); - - apr_lock_acquire(thread_accept_mutex); - if (workers_may_exit) { - apr_lock_release(thread_accept_mutex); - break; - } - if ((rv = SAFE_ACCEPT(apr_lock_acquire(process_accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_lock_acquire failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - - while (!workers_may_exit) { - apr_int16_t event; - srv = apr_poll(pollset, &n, -1); - - if (srv != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(srv)) { - continue; - } - - /* apr_poll() will only return errors in catastrophic - * circumstances. Let's try exiting gracefully, for now. */ - ap_log_error(APLOG_MARK, APLOG_ERR, srv, (const server_rec *) - ap_server_conf, "apr_poll: (listen)"); - workers_may_exit = 1; - } - if (workers_may_exit) break; - - apr_poll_revents_get(&event, listenfds[0], pollset); - if (event & APR_POLLIN) { - /* A process got a signal on the shutdown pipe. Check if we're - * the lucky process to die. */ - check_pipe_of_death(); - continue; - } - - apr_poll_revents_get(&event, listenfds[1], pollset); - if (event & APR_POLLIN || event & APR_POLLOUT) { - /* This request is from another child in our current process. - * We should set a flag here, and then below we will read - * two bytes (the socket number and the NULL byte. - */ - thread_socket_table[thread_num] = -2; - goto got_from_other_child; - } - - if (num_listenfds == 1) { - sd = ap_listeners->sd; - goto got_fd; - } - else { - /* find a listener */ - curr_pollfd = last_pollfd; - do { - curr_pollfd++; - if (curr_pollfd > num_listenfds) { - curr_pollfd = 1; - } - /* XXX: Should we check for POLLERR? */ - apr_poll_revents_get(&event, listenfds[curr_pollfd], pollset); - if (event & APR_POLLIN) { - last_pollfd = curr_pollfd; - sd = listenfds[curr_pollfd]; - goto got_fd; - } - } while (curr_pollfd != last_pollfd); - } - } - got_fd: - if (!workers_may_exit) { - if ((rv = apr_accept(&csd, sd, ptrans)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, "apr_accept"); - } - if ((rv = SAFE_ACCEPT(apr_lock_release(process_accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_lock_release failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - apr_lock_release(thread_accept_mutex); - apr_lock_acquire(idle_thread_count_mutex); - if (idle_thread_count > min_spare_threads) { - idle_thread_count--; - } - else { - if (!start_thread()) { - idle_thread_count--; - } - } - apr_lock_release(idle_thread_count_mutex); - got_from_other_child: - if (thread_socket_table[thread_num] == -2) { - struct msghdr msg; - struct cmsghdr *cmsg; - char sockname[80]; - struct iovec iov; - int ret, sd, dp; - - iov.iov_base = sockname; - iov.iov_len = 80; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(sd)); - cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sd); - msg.msg_control = (caddr_t)cmsg; - msg.msg_controllen = cmsg->cmsg_len; - msg.msg_flags = 0; - - ret = recvmsg(child_info_table[child_num].sd, &msg, 0); - - memcpy(&dp, CMSG_DATA(cmsg), sizeof(dp)); - - thread_socket_table[thread_num] = dp; - apr_os_sock_put(&csd, &child_info_table[child_num].sd, ptrans); - } - if (setjmp(jmpbuffer) != 1) { - process_socket(ptrans, csd, conn_id); - } - else { - thread_socket_table[thread_num] = -1; - } - requests_this_child--; - } else { - if ((rv = SAFE_ACCEPT(apr_lock_release(process_accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_lock_release failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - apr_lock_release(thread_accept_mutex); - apr_lock_acquire(idle_thread_count_mutex); - idle_thread_count--; - apr_lock_release(idle_thread_count_mutex); - break; - } - apr_pool_clear(ptrans); - } - - apr_lock_acquire(thread_pool_parent_mutex); - ap_update_child_status(child_num, thread_num, SERVER_DEAD, - (request_rec *) NULL); - apr_pool_destroy(tpool); - apr_lock_release(thread_pool_parent_mutex); - apr_lock_acquire(worker_thread_count_mutex); - worker_thread_count--; - worker_thread_free_ids[worker_thread_count] = thread_num; - if (worker_thread_count == 0) { - /* All the threads have exited, now finish the shutdown process - * by signalling the sigwait thread */ - kill(my_pid, SIGTERM); - } - apr_lock_release(worker_thread_count_mutex); - - return NULL; -} - -/* 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 int set_group_privs(uid_t uid, gid_t gid) -{ - if (!geteuid()) { - const char *name; - - /* Get username if passed as a uid */ - - struct passwd *ent; - - if ((ent = getpwuid(uid)) == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "getpwuid: couldn't determine user name from uid %u, " - "you probably need to modify the User directive", - (unsigned)uid); - return -1; - } - - name = ent->pw_name; - - /* - * Set the GID before initgroups(), since on some platforms - * setgid() is known to zap the group list. - */ - if (setgid(gid) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "setgid: unable to set group id to Group %u", - (unsigned)gid); - return -1; - } - - /* Reset `groups' attributes. */ - - if (initgroups(name, gid) == -1) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "initgroups: unable to set groups for User %s " - "and Group %u", name, (unsigned)gid); - return -1; - } - } - return 0; -} - - -static int perchild_setup_child(int childnum) -{ - child_info_t *ug = &child_info_table[childnum]; - - if (ug->uid == -1 && ug->gid == -1) { - return unixd_setup_child(); - } - if (set_group_privs(ug->uid, ug->gid)) { - return -1; - } - /* Only try to switch if we're running as root */ - if (!geteuid() && ( -#ifdef _OSD_POSIX - os_init_job_environment(server_conf, unixd_config.user_name, one_process) != 0 || -#endif - setuid(ug->uid) == -1)) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, - "setuid: unable to change to uid: %ld", - (long) ug->uid); - return -1; - } - return 0; -} - -static int check_signal(int signum) -{ - switch (signum) { - case SIGTERM: - case SIGINT: - just_die(signum); - return 1; - } - return 0; -} - -static void child_main(int child_num_arg) -{ - int i; - ap_listen_rec *lr; - apr_status_t rv; - apr_thread_t *thread; - - my_pid = getpid(); - child_num = child_num_arg; - apr_pool_create(&pchild, pconf); - - /*stuff to do before we switch id's, so we have permissions.*/ - - rv = SAFE_ACCEPT(apr_lock_child_init(&process_accept_mutex, lock_fname, - pchild)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize cross-process lock in child"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (perchild_setup_child(child_num)) { - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_run_child_init(pchild, ap_server_conf); - - /*done with init critical section */ - - apr_setup_signal_thread(); - - requests_this_child = max_requests_per_child; - - /* Set up the pollfd array, num_listenfds + 1 for the pipe and 1 for - * the child socket. - */ - listenfds = apr_pcalloc(pchild, sizeof(*listenfds) * (num_listenfds + 2)); -#if APR_FILES_AS_SOCKETS - apr_socket_from_file(&listenfds[0], pipe_of_death_in); -#endif - - /* The child socket */ - apr_os_sock_put(&listenfds[1], &child_info_table[child_num].sd, pchild); - - num_listenfds++; - for (lr = ap_listeners, i = 2; i <= num_listenfds; lr = lr->next, ++i) - listenfds[i]=lr->sd; - - /* Setup worker threads */ - - if (threads_to_start > max_threads) { - threads_to_start = max_threads; - } - idle_thread_count = threads_to_start; - worker_thread_count = 0; - for (i = 0; i < max_threads; i++) { - worker_thread_free_ids[i] = i; - } - apr_pool_create(&thread_pool_parent, pchild); - apr_lock_create(&thread_pool_parent_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - apr_lock_create(&idle_thread_count_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - apr_lock_create(&worker_thread_count_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - apr_lock_create(&pipe_of_death_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - apr_lock_create(&thread_accept_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - - apr_threadattr_create(&worker_thread_attr, pchild); - apr_threadattr_detach_set(worker_thread_attr, 1); - - /* We are creating worker threads right now */ - for (i=0; i < threads_to_start; i++) { - /* start_thread shouldn't fail here */ - if (!start_thread()) { - break; - } - } - - apr_signal_thread(check_signal); -} - -static int make_child(server_rec *s, int slot) -{ - int pid; - - if (slot + 1 > ap_max_daemons_limit) { - ap_max_daemons_limit = slot + 1; - } - - if (one_process) { - set_signals(); - ap_child_table[slot].pid = getpid(); - ap_child_table[slot].status = SERVER_ALIVE; - child_main(slot); - } - (void) ap_update_child_status(slot, 0, SERVER_STARTING, (request_rec *) NULL); - - if ((pid = fork()) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, - "fork: Unable to fork new process"); - /* 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 <sys/processor.h> - int status = bindprocessor(BINDPROCESS, (int)getpid(), - PROCESSOR_CLASS_ANY); - if (status != OK) - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, errno, - ap_server_conf, "processor unbind failed %d", status); -#endif - - RAISE_SIGSTOP(MAKE_CHILD); - - /* XXX - For an unthreaded server, a signal handler will be necessary - apr_signal(SIGTERM, just_die); - */ - child_main(slot); - clean_child_exit(0); - } - /* else */ - ap_child_table[slot].pid = pid; - ap_child_table[slot].status = SERVER_ALIVE; - - return 0; -} - -/* start up a bunch of children */ -static int startup_children(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < num_daemons; ++i) { - if (ap_child_table[i].pid) { - continue; - } - if (make_child(ap_server_conf, i) < 0) { - break; - } - --number_to_start; - } - return number_to_start; -} - - -/* - * spawn_rate is the number of children that will be spawned on the - * next maintenance cycle if there aren't enough servers. It is - * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by - * without the need to spawn. - */ -static int spawn_rate = 1; -#ifndef MAX_SPAWN_RATE -#define MAX_SPAWN_RATE (32) -#endif -static int hold_off_on_exponential_spawning; - -static void perform_child_maintenance(void) -{ - int i; - int free_length; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead = -1; - - /* initialize the free_list */ - free_length = 0; - - for (i = 0; i < num_daemons; ++i) { - if (ap_child_table[i].pid == 0) { - if (free_length < spawn_rate) { - free_slots[free_length] = i; - ++free_length; - } - } - else { - last_non_dead = i; - } - - if (i >= ap_max_daemons_limit && free_length >= spawn_rate) { - break; - } - } - ap_max_daemons_limit = last_non_dead + 1; - - if (free_length > 0) { - for (i = 0; i < free_length; ++i) { - make_child(ap_server_conf, free_slots[i]); - } - /* 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 (spawn_rate < MAX_SPAWN_RATE) { - spawn_rate *= 2; - } - } - else { - spawn_rate = 1; - } -} - -static void server_main_loop(int remaining_children_to_start) -{ - int child_slot; - apr_wait_t status; - apr_proc_t pid; - int i; - - while (!restart_pending && !shutdown_pending) { - ap_wait_or_timeout(&status, &pid, pconf); - - if (pid.pid != -1) { - ap_process_child_status(&pid, status); - /* non-fatal death... note that it's gone in the child table and - * clean out the status table. */ - child_slot = -1; - for (i = 0; i < ap_max_daemons_limit; ++i) { - if (ap_child_table[i].pid == pid.pid) { - child_slot = i; - break; - } - } - if (child_slot >= 0) { - ap_child_table[child_slot].pid = 0; - ap_update_child_status(child_slot, i, SERVER_DEAD, (request_rec *) NULL); - - - if (remaining_children_to_start - && child_slot < num_daemons) { - /* we're still doing a 1-for-1 replacement of dead - * children with new children - */ - make_child(ap_server_conf, child_slot); - --remaining_children_to_start; - } -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&pid, status) == 0) { - /* handled */ -#endif - } - else if (is_graceful) { - /* Great, we've probably just lost a slot in the - * child table. Somehow we don't know about this - * child. - */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, - ap_server_conf, - "long lost child came home! (pid %ld)", - (long)pid.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. - */ - remaining_children_to_start = \ - startup_children(remaining_children_to_start); - /* 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_child_maintenance(); - } -} - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int remaining_children_to_start; - int i; - apr_status_t rv; - apr_size_t one = 1; - - pconf = _pconf; - ap_server_conf = s; - if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out, pconf)) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, - (const server_rec*) ap_server_conf, - "apr_file_pipe_create (pipe_of_death)"); - exit(1); - } - if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, - (const server_rec*) ap_server_conf, - "apr_file_pipe_timeout_set (pipe_of_death)"); - exit(1); - } - ap_server_conf = s; - if ((num_listenfds = ap_setup_listeners(ap_server_conf)) < 1) { - /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s, - "no listening sockets available, shutting down"); - return 1; - } - ap_log_pid(pconf, ap_pid_fname); - - /* Initialize cross-process accept lock */ - lock_fname = apr_psprintf(_pconf, "%s.%u", - ap_server_root_relative(_pconf, lock_fname), - my_pid); - rv = SAFE_ACCEPT(apr_lock_create(&process_accept_mutex, APR_MUTEX, - APR_CROSS_PROCESS, lock_fname, _pconf)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't create cross-process lock"); - return 1; - } - - if (!is_graceful) { - ap_create_scoreboard(pconf, SB_SHARED); - } - /* Initialize the child table */ - if (!is_graceful) { - for (i = 0; i < HARD_SERVER_LIMIT; i++) { - ap_child_table[i].pid = 0; - } - } - - set_signals(); - - /* 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 SIGWINCH). 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 = num_daemons; - if (!is_graceful) { - remaining_children_to_start = \ - startup_children(remaining_children_to_start); - } - 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, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); - restart_pending = shutdown_pending = 0; - - server_main_loop(remaining_children_to_start); - - if (shutdown_pending) { - /* Time to gracefully shut down: - * Kill child processes, tell them to call child_exit, etc... - */ - if (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "killpg SIGTERM"); - } - ap_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, 0, - ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - } - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, - ap_server_conf, "caught SIGTERM, shutting down"); - - return 1; - } - - /* we've been told to restart */ - apr_signal(SIGHUP, SIG_IGN); - - if (one_process) { - /* not worth thinking about */ - return 1; - } - - if (is_graceful) { - char char_of_death = '!'; - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "SIGWINCH received. Doing graceful restart"); - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. - */ - - for (i = 0; i < num_daemons; ++i) { - if (ap_child_table[i].pid) { - ap_child_table[i].status = SERVER_DYING; - } - } - /* give the children the signal to die */ - for (i = 0; i < num_daemons;) { - if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(rv)) continue; - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, - "write pipe_of_death"); - } - i++; - } - } - else { - /* Kill 'em all. Since the child acts the same on the parents SIGTERM - * and a SIGHUP, we may as well use the same signal, because some user - * pthreads are stealing signals from us left and right. - */ - if (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, - "killpg SIGTERM"); - } - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, - ap_server_conf, "SIGHUP received. Attempting to restart"); - } - return 0; -} - -static void perchild_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach = 0; - int i; - - one_process = !!ap_exists_config_define("ONE_PROCESS"); - no_detach = !!ap_exists_config_define("NO_DETACH"); - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !no_detach) { - apr_proc_detach(); - } - - my_pid = getpid(); - } - - unixd_pre_config(ptemp); - ap_listen_pre_config(); - num_daemons = DEFAULT_NUM_DAEMON; - threads_to_start = DEFAULT_START_THREAD; - min_spare_threads = DEFAULT_MIN_SPARE_THREAD; - max_spare_threads = DEFAULT_MAX_SPARE_THREAD; - max_threads = HARD_THREAD_LIMIT; - ap_pid_fname = DEFAULT_PIDLOG; - ap_scoreboard_fname = DEFAULT_SCOREBOARD; - lock_fname = DEFAULT_LOCKFILE; - max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - curr_child_num = 0; - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); - - for (i = 0; i < HARD_SERVER_LIMIT; i++) { - child_info_table[i].uid = -1; - child_info_table[i].gid = -1; - child_info_table[i].sd = -1; - } - for (i = 0; i < HARD_THREAD_LIMIT; i++) { - thread_socket_table[i] = -1; - } -} - -static int pass_request(request_rec *r) -{ - apr_socket_t *thesock = r->connection->client_socket; - struct msghdr msg; - struct cmsghdr *cmsg; - int sfd; - struct iovec iov; - apr_bucket_brigade *bb = apr_brigade_create(r->pool); - perchild_server_conf *sconf = (perchild_server_conf *) - ap_get_module_config(r->server->module_config, - &mpm_perchild_module); - char *foo; - apr_size_t len; - apr_size_t readbytes = 0; - - apr_pool_userdata_get((void **)&foo, "PERCHILD_BUFFER", r->connection->pool); - len = strlen(foo); - - apr_pool_userdata_set(NULL, "PERCHILD_BUFFER", apr_pool_cleanup_null, - r->connection->pool); - - apr_os_sock_get(&sfd, thesock); - - iov.iov_base = NULL; - iov.iov_len = 0; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sfd)); - cmsg->cmsg_len = sizeof(*cmsg) + sizeof(int); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - - memcpy(CMSG_DATA(cmsg), &sfd, sizeof(sfd)); - - msg.msg_control = (caddr_t)cmsg; - msg.msg_controllen = cmsg->cmsg_len; - msg.msg_flags=0; - - if (sendmsg(sconf->sd2, &msg, 0) == -1) { - apr_pool_destroy(r->pool); - return -1; - } - - write(sconf->sd2, foo, len); - - while (ap_get_brigade(r->input_filters, bb, AP_MODE_NONBLOCKING, &readbytes) == APR_SUCCESS) { - apr_bucket *e; - APR_BRIGADE_FOREACH(e, bb) { - const char *str; - - apr_bucket_read(e, &str, &len, APR_NONBLOCK_READ); - write(sconf->sd2, str, len); - } - } - - apr_pool_destroy(r->pool); - return 1; -} - -static char *make_perchild_socket(const char *fullsockname, int sd[2]) -{ - socketpair(PF_UNIX, SOCK_STREAM, 0, sd); - return NULL; -} - - -static void perchild_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - int i; - server_rec *sr; - perchild_server_conf *sconf; - int def_sd[2]; - - def_sd[0] = -1; - def_sd[1] = -1; - - for (sr = s; sr; sr = sr->next) { - sconf = (perchild_server_conf *)ap_get_module_config(sr->module_config, - &mpm_perchild_module); - - if (sconf->sd == -1) { - sconf->fullsockname = apr_pstrcat(sr->process->pool, - sconf->sockname, ".DEFAULT", NULL); - if (def_sd[0] == -1) { - if (!make_perchild_socket(sconf->fullsockname, def_sd)) { - /* log error */ - } - } - sconf->sd = def_sd[0]; - sconf->sd2 = def_sd[1]; - } - } - - for (i = 0; i < num_daemons; i++) { - if (child_info_table[i].uid == -1) { - child_info_table[i].sd = def_sd[0]; - } - } -} - -static int perchild_post_read(request_rec *r) -{ - ap_filter_t *f = r->connection->input_filters; - int thread_num = r->connection->id % HARD_THREAD_LIMIT; - perchild_server_conf *sconf = (perchild_server_conf *) - ap_get_module_config(r->server->module_config, - &mpm_perchild_module); - - while (f) { - if (!strcmp("PERCHILD_BUFFER", f->frec->name)) { - ap_remove_output_filter(f); - break; - } - f = f->next; - } - - if (thread_socket_table[thread_num] != -1) { - apr_socket_t *csd = NULL; - - apr_os_sock_put(&csd, &thread_socket_table[thread_num], - r->connection->pool); - ap_sock_disable_nagle(csd); - r->connection->client_socket = csd; - return OK; - } - else { - if (sconf->sd != child_info_table[child_num].sd) { - if (pass_request(r) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, - ap_server_conf, "Could not pass request to proper " - "child, request will not be honored."); - } - longjmp(jmpbuffer, 1); - } - return OK; - } - return OK; -} - -static apr_status_t perchild_buffer(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_size_t *readbytes) -{ - apr_bucket *e; - apr_status_t rv; - char *buffer = NULL; - const char *str; - apr_size_t len; - - if ((rv = ap_get_brigade(f->next, b, mode, readbytes)) != APR_SUCCESS) { - return rv; - } - - apr_pool_userdata_get((void **)&buffer, "PERCHILD_BUFFER", f->c->pool); - - APR_BRIGADE_FOREACH(e, b) { - if (e->length != 0) { - apr_bucket_read(e, &str, &len, APR_NONBLOCK_READ); - - if (buffer == NULL) { - buffer = apr_pstrndup(f->c->pool, str, len); - } - else { - buffer = apr_pstrcat(f->c->pool, buffer, - apr_pstrndup(f->c->pool, str, len), NULL); - } - } - } - apr_pool_userdata_set(buffer, "PERCHILD_BUFFER", apr_pool_cleanup_null, f->c->pool); - - return APR_SUCCESS; -} - -static int perchild_pre_connection(conn_rec *c) -{ - ap_add_input_filter("PERCHILD_BUFFER", NULL, NULL, c); - return OK; -} - -static void perchild_hooks(apr_pool_t *p) -{ - one_process = 0; - - ap_hook_pre_config(perchild_pre_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(perchild_post_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_pre_connection(perchild_pre_connection,NULL,NULL, APR_HOOK_MIDDLE); - - /* This must be run absolutely first. If this request isn't for this - * server then we need to forward it to the proper child. No sense - * tying up this server running more post_read request hooks if it is - * just going to be forwarded along. - */ - ap_hook_post_read_request(perchild_post_read, NULL, NULL, APR_HOOK_REALLY_FIRST); - ap_register_input_filter("PERCHILD_BUFFER", perchild_buffer, AP_FTYPE_CONTENT); -} - -static const char *set_pidfile(cmd_parms *cmd, void *dummy, const 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 <VirtualHost>"; - } - ap_pid_fname = arg; - return NULL; -} - -static const char *set_scoreboard(cmd_parms *cmd, void *dummy, const 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, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - lock_fname = arg; - return NULL; -} -static const char *set_num_daemons (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - num_daemons = atoi(arg); - if (num_daemons > HARD_SERVER_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: NumServers of %d exceeds compile time limit " - "of %d servers,", num_daemons, HARD_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering NumServers to %d. To increase, please " - "see the", HARD_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " HARD_SERVER_LIMIT define in %s.", - AP_MPM_HARD_LIMITS_FILE); - num_daemons = HARD_SERVER_LIMIT; - } - else if (num_daemons < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: Require NumServers > 0, setting to 1"); - num_daemons = 1; - } - return NULL; -} - -static const char *set_threads_to_start (cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - threads_to_start = atoi(arg); - if (threads_to_start > HARD_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: StartThreads of %d exceeds compile time" - " limit of %d threads,", threads_to_start, - HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering StartThreads to %d. To increase, please" - " see the", HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " HARD_THREAD_LIMIT define in %s.", - AP_MPM_HARD_LIMITS_FILE); - } - else if (threads_to_start < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: Require StartThreads > 0, setting to 1"); - threads_to_start = 1; - } - return NULL; -} - -static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - min_spare_threads = atoi(arg); - if (min_spare_threads <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - - return NULL; -} - -static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - max_spare_threads = atoi(arg); - if (max_spare_threads >= HARD_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: detected MinSpareThreads set higher than"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "HARD_THREAD_LIMIT. Resetting to %d", HARD_THREAD_LIMIT); - max_spare_threads = HARD_THREAD_LIMIT; - } - return NULL; -} - -static const char *set_max_threads(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - max_threads = atoi(arg); - if (max_threads > HARD_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: detected MaxThreadsPerChild set higher than"); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "HARD_THREAD_LIMIT. Resetting to %d", HARD_THREAD_LIMIT); - max_threads = HARD_THREAD_LIMIT; - } - return NULL; -} - -static const char *set_max_requests(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - max_requests_per_child = atoi(arg); - - return NULL; -} - -static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, - const char *arg) -{ - apr_finfo_t finfo; - const char *fname; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - fname = ap_server_root_relative(cmd->pool, arg); - if ((apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) - || (finfo.filetype != APR_DIR)) { - return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, - " does not exist or is not a directory", NULL); - } - apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir)); - return NULL; -} - -static const char *set_child_per_uid(cmd_parms *cmd, void *dummy, const char *u, - const char *g, const char *num) -{ - int i; - int max_this_time = atoi(num) + curr_child_num; - for (i = curr_child_num; i < max_this_time; i++, curr_child_num++); { - child_info_t *ug = &child_info_table[i - 1]; - - if (i > num_daemons) { - return "Trying to use more child ID's than NumServers. Increase " - "NumServers in your config file."; - } - - ug->uid = atoi(u); - ug->gid = atoi(g); - } - return NULL; -} - -static const char *assign_childuid(cmd_parms *cmd, void *dummy, const char *uid, - const char *gid) -{ - int i; - int u = atoi(uid); - int g = atoi(gid); - const char *errstr; - int socks[2]; - perchild_server_conf *sconf = (perchild_server_conf *) - ap_get_module_config(cmd->server->module_config, - &mpm_perchild_module); - - sconf->fullsockname = apr_pstrcat(cmd->pool, sconf->sockname, ".", uid, ":", gid, NULL); - - if ((errstr = make_perchild_socket(sconf->fullsockname, socks))) { - return errstr; - } - - sconf->sd = socks[0]; - sconf->sd2 = socks[1]; - - for (i = 0; i < num_daemons; i++) { - if (u == child_info_table[i].uid && g == child_info_table[i].gid) { - child_info_table[i].sd = sconf->sd; - } - } - - return NULL; -} - - -static const command_rec perchild_cmds[] = { -UNIX_DAEMON_COMMANDS -LISTEN_COMMANDS -AP_INIT_TAKE1("PidFile", set_pidfile, NULL, RSRC_CONF, - "A file for logging the server process ID"), -AP_INIT_TAKE1("ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, - "A file for Apache to maintain runtime process management information"), -AP_INIT_TAKE1("LockFile", set_lockfile, NULL, RSRC_CONF, - "The lockfile used when Apache needs to lock the accept() call"), -AP_INIT_TAKE1("NumServers", set_num_daemons, NULL, RSRC_CONF, - "Number of children alive at the same time"), -AP_INIT_TAKE1("StartThreads", set_threads_to_start, NULL, RSRC_CONF, - "Number of threads each child creates"), -AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, - "Minimum number of idle threads per child, to handle request spikes"), -AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, - "Maximum number of idle threads per child"), -AP_INIT_TAKE1("MaxThreadsPerChild", set_max_threads, NULL, RSRC_CONF, - "Maximum number of threads per child"), -AP_INIT_TAKE1("MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, - "Maximum number of requests a particular child serves before dying."), -AP_INIT_TAKE1("CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, - "The location of the directory Apache changes to before dumping core"), -AP_INIT_TAKE3("ChildperUserID", set_child_per_uid, NULL, RSRC_CONF, - "Specify a User and Group for a specific child process."), -AP_INIT_TAKE2("AssignUserID", assign_childuid, NULL, RSRC_CONF, - "Tie a virtual host to a specific child process."), -{ NULL } -}; - -static void *perchild_create_config(apr_pool_t *p, server_rec *s) -{ - perchild_server_conf *c = - (perchild_server_conf *) apr_pcalloc(p, sizeof(perchild_server_conf)); - - c->sd = -1; - return c; -} - -module AP_MODULE_DECLARE_DATA mpm_perchild_module = { - MPM20_MODULE_STUFF, - NULL, /* hook to run before apache parses args */ - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - perchild_create_config, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - perchild_cmds, /* command apr_table_t */ - perchild_hooks /* register_hooks */ -}; - diff --git a/server/mpm/prefork/.cvsignore b/server/mpm/prefork/.cvsignore deleted file mode 100644 index dc53ac865d..0000000000 --- a/server/mpm/prefork/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -*.lo -*.la -Makefile -.deps -.libs diff --git a/server/mpm/prefork/Makefile.in b/server/mpm/prefork/Makefile.in deleted file mode 100644 index 034bf5ce84..0000000000 --- a/server/mpm/prefork/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libprefork.la -LTLIBRARY_SOURCES = prefork.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/server/mpm/prefork/config.m4 b/server/mpm/prefork/config.m4 deleted file mode 100644 index 9c189a8642..0000000000 --- a/server/mpm/prefork/config.m4 +++ /dev/null @@ -1,3 +0,0 @@ -if test "$MPM_NAME" = "prefork" ; then - APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile) -fi diff --git a/server/mpm/prefork/mpm.h b/server/mpm/prefork/mpm.h deleted file mode 100644 index 6a923b0636..0000000000 --- a/server/mpm/prefork/mpm.h +++ /dev/null @@ -1,80 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "httpd.h" -#include "mpm_default.h" -#include "scoreboard.h" -#include "unixd.h" - -#ifndef APACHE_MPM_PREFORK_H -#define APACHE_MPM_PREFORK_H - -#define PREFORK_MPM - -#define MPM_NAME "Prefork" - -#define AP_MPM_NEEDS_RECLAIM_CHILD_PROCESSES 1 -#define MPM_SYNC_CHILD_TABLE() (ap_sync_scoreboard_image()) -#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) - -extern int ap_threads_per_child; -extern int ap_max_daemons_limit; -extern server_rec *ap_server_conf; -extern char ap_coredump_dir[MAX_STRING_LEN]; -#endif /* APACHE_MPM_PREFORK_H */ diff --git a/server/mpm/prefork/mpm_default.h b/server/mpm/prefork/mpm_default.h deleted file mode 100644 index 3763037ae6..0000000000 --- a/server/mpm/prefork/mpm_default.h +++ /dev/null @@ -1,135 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -#define AP_ID_FROM_CHILD_THREAD(c, t) c -#define AP_CHILD_THREAD_FROM_ID(i) i, 0 - - -/* 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 -#define HARD_SERVER_LIMIT 256 -#endif - -#ifndef HARD_THREAD_LIMIT -#define HARD_THREAD_LIMIT 1 -#endif - -/* File used for accept locking, when we use a file */ -#ifndef DEFAULT_LOCKFILE -#define DEFAULT_LOCKFILE "logs/accept.lock" -#endif - -/* Scoreboard file, if there is one */ -#ifndef DEFAULT_SCOREBOARD -#define DEFAULT_SCOREBOARD "logs/apache_runtime_status" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG "logs/httpd.pid" -#endif - -/* - * Interval, in microseconds, between scoreboard maintenance. - */ -#ifndef SCOREBOARD_MAINTENANCE_INTERVAL -#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 -#endif - -/* Number of requests to try to handle in a single process. If <= 0, - * the children don't die off. - */ -#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD -#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 -#endif - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c deleted file mode 100644 index 52ed0b51e0..0000000000 --- a/server/mpm/prefork/prefork.c +++ /dev/null @@ -1,1515 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * httpd.c: simple http daemon for answering WWW file requests - * - * - * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3) - * - * 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. - */ - -/* TODO: this is a cobbled together prefork MPM example... it should mostly - * TODO: behave like apache-1.3... here's a short list of things I think - * TODO: need cleaning up still: - */ - -#include "apr.h" -#include "apr_portable.h" -#include "apr_strings.h" -#include "apr_thread_proc.h" -#include "apr_signal.h" - -#define APR_WANT_STDIO -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "httpd.h" -#include "mpm_default.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "scoreboard.h" -#include "ap_mpm.h" -#include "unixd.h" -#include "mpm_common.h" -#include "ap_listen.h" -#include "ap_mmn.h" - -#ifdef HAVE_BSTRING_H -#include <bstring.h> /* for IRIX, FD_SET calls bzero() */ -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif - -#include <signal.h> -#include <sys/times.h> - -/* config globals */ - -int ap_threads_per_child=0; /* Worker threads per child */ -static int ap_max_requests_per_child=0; -static const char *ap_pid_fname=NULL; -static apr_lock_t *accept_lock; -static const char *ap_lock_fname; -static int ap_daemons_to_start=0; -static int ap_daemons_min_free=0; -static int ap_daemons_max_free=0; -static int ap_daemons_limit=0; - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with MaxClients changes across SIGWINCH restarts. We use this - * value to optimize routines that have to scan the entire scoreboard. - */ -int ap_max_daemons_limit = -1; -server_rec *ap_server_conf; - -char ap_coredump_dir[MAX_STRING_LEN]; - -/* *Non*-shared http_main globals... */ - -static apr_socket_t *sd; -static fd_set listenfds; -static int listenmaxfd; - -/* 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; - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ - -static pid_t ap_my_pid; /* it seems silly to call getpid all the time */ -#ifndef MULTITHREAD -static int my_child_num; -#endif - -#ifdef TPF -int tpf_child = 0; -char tpf_server_name[INETD_SERVNAME_LENGTH+1]; -#endif /* TPF */ - -#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(ap_server_conf->module_config, &core_module); - char *dir = sconf->gprof_dir; - const char *use_dir; - - if(dir) { - apr_status_t res; - char buf[512]; - int len = strlen(sconf->gprof_dir) - 1; - if(*(dir + len) == '%') { - dir[len] = '\0'; - apr_snprintf(buf, sizeof(buf), "%sgprof.%d", dir, (int)getpid()); - } - use_dir = ap_server_root_relative(pconf, buf[0] ? buf : dir); - res = apr_dir_make(use_dir, 0755, pconf); - if(res != APR_SUCCESS && !APR_STATUS_IS_EEXIST(res)) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf, - "gprof: error creating directory %s", dir); - } - } - else { - use_dir = ap_server_root_relative(pconf, "logs"); - } - - chdir(dir); -} -#else -#define chdir_for_gprof() -#endif - -/* XXX - I don't know if TPF will ever use this module or not, so leave - * the ap_check_signals calls in but disable them - manoj */ -#define ap_check_signals() - -/* 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) { - apr_pool_destroy(pchild); - } - ap_scoreboard_image->servers[my_child_num][0].life_status = SB_WORKING; - chdir_for_gprof(); - exit(code); -} - -static void expand_lock_fname(apr_pool_t *p) -{ - /* XXXX possibly bogus cast */ - ap_lock_fname = apr_psprintf(p, "%s.%lu", - ap_server_root_relative(p, ap_lock_fname), (unsigned long)getpid()); -} - -/* Initialize mutex lock. - * Done by each child at its birth - */ -static void accept_mutex_child_init(apr_pool_t *p) -{ - apr_status_t rv; - - rv = apr_lock_child_init(&accept_lock, ap_lock_fname, p); - if (rv) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, - "couldn't do child init for accept mutex"); - clean_child_exit(APEXIT_CHILDINIT); - } -} - -/* Initialize mutex lock. - * Must be safe to call this on a restart. - */ -static void accept_mutex_init(apr_pool_t *p) -{ - apr_status_t rv; - - expand_lock_fname(p); - rv = apr_lock_create(&accept_lock, APR_MUTEX, APR_CROSS_PROCESS, ap_lock_fname, p); - if (rv) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "couldn't create accept mutex"); - exit(APEXIT_INIT); - } -} - -static void accept_mutex_on(void) -{ - apr_status_t rv = apr_lock_acquire(accept_lock); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "couldn't grab the accept mutex"); - exit(APEXIT_CHILDFATAL); - } -} - -static void accept_mutex_off(void) -{ - apr_status_t rv = apr_lock_release(accept_lock); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, "couldn't release the accept mutex"); - exit(APEXIT_CHILDFATAL); - } -} - -/* 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) {stmt;}} while(0) -#else -#define SAFE_ACCEPT(stmt) do {stmt;} while(0) -#endif - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMONS: - *result = ap_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_NOT_SUPPORTED; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = 0; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -#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(apr_wait_t *status) -{ - int n, pid; - - for (n = 0; n < ap_max_daemons_limit; ++n) { - ap_sync_scoreboard_image(); - if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD && - kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) { - ap_update_child_status(AP_CHILD_THREAD_FROM_ID(n), SERVER_DEAD, NULL); - /* just mark it as having a successful exit status */ - memset(status, 0, sizeof(apr_wait_t)); - return(pid); - } - } - return 0; -} -#endif - -/* handle all varieties of core dumping signals */ -static void sig_coredump(int sig) -{ - chdir(ap_coredump_dir); - apr_signal(sig, SIG_DFL); - kill(getpid(), sig); - /* 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) -{ - clean_child_exit(0); -} - -static void please_die_gracefully(int sig) -{ - /* clean_child_exit(0); */ - ap_scoreboard_image->servers[my_child_num][0].life_status = SB_IDLE_DIE; - if (sig == SIGHUP) { - (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), - SERVER_GRACEFUL, (request_rec *) NULL); - } - else { - (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), - SERVER_IDLE_KILL, (request_rec *) NULL); - } -} - -/* 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; - -static void sig_term(int sig) -{ - 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; -} - -static void restart(int sig) -{ - if (restart_pending == 1) { - /* Probably not an error - don't bother reporting it */ - return; - } - restart_pending = 1; - if ((is_graceful = (sig == SIGWINCH))) { - apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard); - } -} - -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, errno, ap_server_conf, "sigaction(SIGSEGV)"); -#ifdef SIGBUS - if (sigaction(SIGBUS, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)"); -#endif -#ifdef SIGABORT - if (sigaction(SIGABORT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)"); -#endif -#ifdef SIGABRT - if (sigaction(SIGABRT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)"); -#endif -#ifdef SIGILL - if (sigaction(SIGILL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_server_conf, "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_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, errno, ap_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, errno, ap_server_conf, "sigaction(SIGPIPE)"); -#endif - - /* we want to ignore HUPs and WINCH while we're busy processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, SIGWINCH); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); - if (sigaction(SIGWINCH, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGWINCH)"); -#else - if (!one_process) { - apr_signal(SIGSEGV, sig_coredump); -#ifdef SIGBUS - apr_signal(SIGBUS, sig_coredump); -#endif /* SIGBUS */ -#ifdef SIGABORT - apr_signal(SIGABORT, sig_coredump); -#endif /* SIGABORT */ -#ifdef SIGABRT - apr_signal(SIGABRT, sig_coredump); -#endif /* SIGABRT */ -#ifdef SIGILL - apr_signal(SIGILL, sig_coredump); -#endif /* SIGILL */ -#ifdef SIGXCPU - apr_signal(SIGXCPU, SIG_DFL); -#endif /* SIGXCPU */ -#ifdef SIGXFSZ - apr_signal(SIGXFSZ, SIG_DFL); -#endif /* SIGXFSZ */ - } - - apr_signal(SIGTERM, sig_term); -#ifdef SIGHUP - apr_signal(SIGHUP, restart); -#endif /* SIGHUP */ -#ifdef SIGWINCH - apr_signal(SIGWINCH, restart); -#endif /* SIGWINCH */ -#ifdef SIGPIPE - apr_signal(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#endif -} - -/***************************************************************** - * 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 apr_socket_t *csd; -static int requests_this_child; -static fd_set main_fds; - -#define I_AM_TO_SHUTDOWN() \ -(ap_scoreboard_image->servers[my_child_num][0].life_status != SB_WORKING) - -int ap_graceful_stop_signalled(void) -{ - /* not ever called anymore... */ - return 0; -} - - -static void child_main(int child_num_arg) -{ - ap_listen_rec *lr; - ap_listen_rec *last_lr; - ap_listen_rec *first_lr; - apr_pool_t *ptrans; - conn_rec *current_conn; - apr_status_t stat = APR_EINIT; - int sockdes; - - my_child_num = child_num_arg; - ap_my_pid = getpid(); - csd = NULL; - requests_this_child = 0; - last_lr = NULL; - - /* Get a sub context for global allocations in this child, so that - * we can have cleanups occur when the child exits. - */ - apr_pool_create(&pchild, pconf); - - apr_pool_create(&ptrans, pchild); - - /* needs to be done before we switch UIDs so we have permissions */ - reopen_scoreboard(pchild); - SAFE_ACCEPT(accept_mutex_child_init(pchild)); - - if (unixd_setup_child()) { - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_run_child_init(pchild, ap_server_conf); - - (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(my_child_num), SERVER_READY, (request_rec *) NULL); - - apr_signal(SIGHUP, please_die_gracefully); - - ap_sync_scoreboard_image(); - while (!I_AM_TO_SHUTDOWN()) { - - /* Prepare to receive a SIGWINCH due to graceful restart so that - * we can exit cleanly. - */ - apr_signal(SIGWINCH, please_die_gracefully); - apr_signal(SIGTERM, just_die); - - /* - * (Re)initialize this child to a pre-connection state. - */ - - current_conn = NULL; - - apr_pool_clear(ptrans); - - if ((ap_max_requests_per_child > 0 - && requests_this_child++ >= ap_max_requests_per_child)) { - clean_child_exit(0); - } - - (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(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) { - /* more than one socket */ - memcpy(&main_fds, &listenfds, sizeof(fd_set)); - srv = 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, errno, ap_server_conf, "select: (listen)"); - clean_child_exit(1); - } - - if (srv <= 0) - continue; - - /* we remember the last_lr we searched last time around so that - we don't end up starving any particular listening socket */ - if (last_lr == NULL) { - lr = ap_listeners; - } - else { - lr = last_lr->next; - if (!lr) - lr = ap_listeners; - } - first_lr=lr; - do { - apr_os_sock_get(&sockdes, lr->sd); - if (FD_ISSET(sockdes, &main_fds)) - goto got_listener; - lr = lr->next; - if (!lr) - lr = ap_listeners; - } - while (lr != first_lr); - /* FIXME: if we get here, something bad has happened, and we're - probably gonna spin forever. - */ - continue; - got_listener: - last_lr = lr; - sd = lr->sd; - } - else { - /* only one socket, just pretend we did the other stuff */ - sd = ap_listeners->sd; - } - - /* if we accept() something we don't want to die, so we have to - * defer the exit - */ - apr_signal(SIGTERM, please_die_gracefully); - for (;;) { - ap_sync_scoreboard_image(); - if (I_AM_TO_SHUTDOWN()) { - /* we didn't get a socket, and we were told to die */ - clean_child_exit(0); - } - stat = apr_accept(&csd, sd, ptrans); - if (stat == APR_SUCCESS || !APR_STATUS_IS_EINTR(stat)) - break; - } - - if (stat == APR_SUCCESS) - break; /* We have a socket ready for reading */ - else { - -/* TODO: this accept result handling stuff should be abstracted... - * it's already out of date between the various unix mpms - */ - /* 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 (stat) { -#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, stat, ap_server_conf, - "apr_accept: giving up."); - clean_child_exit(APEXIT_CHILDFATAL); -#endif /*ENETDOWN*/ - -#ifdef TPF - case EINACT: - ap_log_error(APLOG_MARK, APLOG_EMERG, stat, ap_server_conf, - "offload device inactive"); - clean_child_exit(APEXIT_CHILDFATAL); - break; - default: - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ap_server_conf, - "select/accept error (%u)", stat); - clean_child_exit(APEXIT_CHILDFATAL); -#else - default: - ap_log_error(APLOG_MARK, APLOG_ERR, stat, ap_server_conf, - "apr_accept: (client socket)"); - clean_child_exit(1); -#endif - } - } - - ap_sync_scoreboard_image(); - if (I_AM_TO_SHUTDOWN()) { - clean_child_exit(0); - } - } - - SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ - - /* We've got a socket, let's at least process one request off the - * socket before we accept a graceful restart request. We set - * the signal to ignore because we don't want to disturb any - * third party code. - */ - apr_signal(SIGWINCH, SIG_IGN); - /* - * We now have a connection, so set it up with the appropriate - * socket options, file descriptors, and read/write buffers. - */ - - apr_os_sock_get(&sockdes, csd); - - if (sockdes >= FD_SETSIZE) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, NULL, - "new file descriptor %d is too large; you probably need " - "to rebuild Apache with a larger FD_SETSIZE " - "(currently %d)", - sockdes, FD_SETSIZE); - apr_socket_close(csd); - ap_sync_scoreboard_image(); - continue; - } - -#ifdef TPF - if (sockdes == 0) { /* 0 is invalid socket for TPF */ - ap_sync_scoreboard_image(); - continue; - } -#endif - - ap_sock_disable_nagle(csd); - - current_conn = ap_new_connection(ptrans, ap_server_conf, csd, - my_child_num); - if (current_conn) { - ap_process_connection(current_conn); - ap_lingering_close(current_conn); - } - - ap_sync_scoreboard_image(); - } - clean_child_exit(0); -} - - -static int make_child(server_rec *s, int slot) -{ - int pid; - - if (slot + 1 > ap_max_daemons_limit) { - ap_max_daemons_limit = slot + 1; - } - - if (one_process) { - apr_signal(SIGHUP, please_die_gracefully); - apr_signal(SIGINT, please_die_gracefully); -#ifdef SIGQUIT - apr_signal(SIGQUIT, SIG_DFL); -#endif - apr_signal(SIGTERM, just_die); - ap_scoreboard_image->servers[slot][0].life_status = SB_WORKING; - child_main(slot); - } - - (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(slot), SERVER_STARTING, (request_rec *) NULL); - - -#ifdef _OSD_POSIX - /* BS2000 requires a "special" version of fork() before a setuid() call */ - if ((pid = os_fork(unixd_config.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, errno, 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(AP_CHILD_THREAD_FROM_ID(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 <sys/processor.h> - int status = bindprocessor(BINDPROCESS, (int)getpid(), - PROCESSOR_CLASS_ANY); - if (status != OK) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, ap_server_conf, - "processor unbind failed %d", status); - } -#endif - RAISE_SIGSTOP(MAKE_CHILD); - /* Disable the restart signal handlers and enable the please_die_gracefully stuff. - * Note that since restart() just notes that a restart has been - * requested there's no race condition here. - */ - apr_signal(SIGHUP, please_die_gracefully); - apr_signal(SIGWINCH, please_die_gracefully); - apr_signal(SIGTERM, just_die); - ap_scoreboard_image->servers[slot][0].life_status = SB_WORKING; - child_main(slot); - } - - 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; - - for (i = 0; number_to_start && i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { - continue; - } - if (make_child(ap_server_conf, i) < 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; - 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 >= ap_max_daemons_limit && free_length == idle_spawn_rate) - break; - ss = &ap_scoreboard_image->servers[i][0]; - 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; - } - } - ap_max_daemons_limit = last_non_dead + 1; - if (idle_count > ap_daemons_max_free) { - /* kill off one child... we use SIGWINCH 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, SIGWINCH); - 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, 0, ap_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, 0, ap_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(ap_server_conf, free_slots[i]) == -1) { - if(free_length == 1) { - shutdown_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, 0, ap_server_conf, - "No active child processes: shutting down"); - } - } -#else - make_child(ap_server_conf, free_slots[i]); -#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 int setup_listeners(server_rec *s) -{ - ap_listen_rec *lr; - int sockdes; - - if (ap_setup_listeners(s) < 1 ) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s, - "no listening sockets available, shutting down"); - return -1; - } - - listenmaxfd = -1; - FD_ZERO(&listenfds); - for (lr = ap_listeners; lr; lr = lr->next) { - apr_os_sock_get(&sockdes, lr->sd); - FD_SET(sockdes, &listenfds); - if (sockdes > listenmaxfd) { - listenmaxfd = sockdes; - } - } - return 0; -} - -/***************************************************************** - * Executive routines. - */ - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int index; - int remaining_children_to_start; - - pconf = _pconf; - - ap_server_conf = s; - - ap_log_pid(pconf, ap_pid_fname); - - if (setup_listeners(s)) { - /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */ - return 1; - } - - SAFE_ACCEPT(accept_mutex_init(pconf)); - if (!is_graceful) { - ap_create_scoreboard(pconf, SB_SHARED); - } -#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 SIGWINCH). 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, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); - restart_pending = shutdown_pending = 0; - - while (!restart_pending && !shutdown_pending) { - int child_slot; - apr_wait_t status; - /* this is a memory leak, but I'll fix it later. */ - apr_proc_t pid; - - ap_wait_or_timeout(&status, &pid, pconf); - - /* 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.pid != -1) { - ap_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); - if (child_slot >= 0) { - (void) ap_update_child_status(AP_CHILD_THREAD_FROM_ID(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(ap_server_conf, child_slot); - --remaining_children_to_start; - } -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&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, - 0, ap_server_conf, - "long lost child came home! (pid %ld)", (long)pid.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 (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM"); - } - ap_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, - 0, ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - } - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "caught SIGTERM, shutting down"); - return 1; - } - - /* we've been told to restart */ - apr_signal(SIGHUP, SIG_IGN); - apr_signal(SIGWINCH, SIG_IGN); - if (one_process) { - /* not worth thinking about */ - return 1; - } - - /* 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(); - - for (index = 0; index < ap_daemons_limit; ++index) { - ap_scoreboard_image->servers[index][0].life_status = SB_IDLE_DIE; - } - - if (is_graceful) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "SIGWINCH received. Doing graceful restart"); - - /* kill off the idle ones */ - if (unixd_killpg(getpgrp(), SIGWINCH) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGWINCH"); - } -#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 (index = 0; index < ap_daemons_limit; ++index) { - if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) { - ap_scoreboard_image->servers[index][0].status = SERVER_GRACEFUL; - } - } -#endif - } - else { - /* Kill 'em off */ - if (unixd_killpg(getpgrp(), SIGHUP) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGHUP"); - } - ap_reclaim_child_processes(0); /* Not when just starting up */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "SIGHUP received. Attempting to restart"); - } - - return 0; -} - -static void prefork_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach = 0; - - no_detach = !!ap_exists_config_define("NO_DETACH"); - one_process = !!ap_exists_config_define("ONE_PROCESS"); - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !no_detach) { - apr_proc_detach(); - } - - ap_my_pid = getpid(); - } - - unixd_pre_config(ptemp); - ap_listen_pre_config(); - 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_extended_status = 0; - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); -} - -static void prefork_hooks(apr_pool_t *p) -{ -#ifdef AUX3 - (void) set42sig(); -#endif - - ap_hook_pre_config(prefork_pre_config, NULL, NULL, APR_HOOK_MIDDLE); -} - -static const char *set_pidfile(cmd_parms *cmd, void *dummy, const 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 <VirtualHost>"; - } - ap_pid_fname = arg; - return NULL; -} - -static const char *set_scoreboard(cmd_parms *cmd, void *dummy, const 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, const 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_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_to_start = atoi(arg); - return NULL; -} - -static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, const 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) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: detected MinSpareServers set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Please read the documentation."); - ap_daemons_min_free = 1; - } - - return NULL; -} - -static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, const 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, const 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) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: MaxClients of %d exceeds compile time limit " - "of %d servers,", ap_daemons_limit, HARD_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering MaxClients to %d. To increase, please " - "see the", HARD_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " HARD_SERVER_LIMIT define in %s.", - AP_MPM_HARD_LIMITS_FILE); - ap_daemons_limit = HARD_SERVER_LIMIT; - } - else if (ap_daemons_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: Require MaxClients > 0, setting to 1"); - ap_daemons_limit = 1; - } - return NULL; -} - -static const char *set_max_requests(cmd_parms *cmd, void *dummy, const 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_coredumpdir (cmd_parms *cmd, void *dummy, const char *arg) -{ - apr_finfo_t finfo; - const char *fname; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - fname = ap_server_root_relative(cmd->pool, arg); - if ((apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) - || (finfo.filetype != APR_DIR)) { - return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, - " does not exist or is not a directory", NULL); - } - apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir)); - return NULL; -} - -static const command_rec prefork_cmds[] = { -UNIX_DAEMON_COMMANDS -LISTEN_COMMANDS -AP_INIT_TAKE1("PidFile", set_pidfile, NULL, RSRC_CONF, - "A file for logging the server process ID"), -AP_INIT_TAKE1("ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, - "A file for Apache to maintain runtime process management information"), -AP_INIT_TAKE1("LockFile", set_lockfile, NULL, RSRC_CONF, - "The lockfile used when Apache needs to lock the accept() call"), -AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, - "Number of child processes launched at server startup"), -AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, - "Minimum number of idle children, to handle request spikes"), -AP_INIT_TAKE1("MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, - "Maximum number of idle children"), -AP_INIT_TAKE1("MaxClients", set_server_limit, NULL, RSRC_CONF, - "Maximum number of children alive at the same time"), -AP_INIT_TAKE1("MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, - "Maximum number of requests a particular child serves before dying."), -AP_INIT_TAKE1("CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, - "The location of the directory Apache changes to before dumping core"), -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA mpm_prefork_module = { - MPM20_MODULE_STUFF, - NULL, /* hook to run before apache parses args */ - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - prefork_cmds, /* command apr_table_t */ - prefork_hooks, /* register hooks */ -}; diff --git a/server/mpm/spmt_os2/.cvsignore b/server/mpm/spmt_os2/.cvsignore deleted file mode 100644 index dc53ac865d..0000000000 --- a/server/mpm/spmt_os2/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -*.lo -*.la -Makefile -.deps -.libs diff --git a/server/mpm/spmt_os2/Makefile.in b/server/mpm/spmt_os2/Makefile.in deleted file mode 100644 index 105f39128f..0000000000 --- a/server/mpm/spmt_os2/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libspmt_os2.la -LTLIBRARY_SOURCES = spmt_os2.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/server/mpm/spmt_os2/config5.m4 b/server/mpm/spmt_os2/config5.m4 deleted file mode 100644 index 770b9d2212..0000000000 --- a/server/mpm/spmt_os2/config5.m4 +++ /dev/null @@ -1,5 +0,0 @@ -if test "$MPM_NAME" = "spmt_os2" ; then - AC_CACHE_SAVE - APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile) - APR_ADDTO(CFLAGS,-Zmt) -fi diff --git a/server/mpm/spmt_os2/mpm.h b/server/mpm/spmt_os2/mpm.h deleted file mode 100644 index 96062ed7d6..0000000000 --- a/server/mpm/spmt_os2/mpm.h +++ /dev/null @@ -1,74 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_SPMT_OS2_H -#define APACHE_MPM_SPMT_OS2_H - -#define SPMT_OS2_MPM - -#include "httpd.h" -#include "mpm_default.h" -#include "scoreboard.h" - -#define MPM_NAME "SPMT_OS2" - -extern char ap_coredump_dir[MAX_STRING_LEN]; -extern server_rec *ap_server_conf; -extern int ap_threads_per_child; - -#endif /* APACHE_MPM_SPMT_OS2_H */ diff --git a/server/mpm/spmt_os2/mpm_default.h b/server/mpm/spmt_os2/mpm_default.h deleted file mode 100644 index c554fddf60..0000000000 --- a/server/mpm/spmt_os2/mpm_default.h +++ /dev/null @@ -1,123 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -/* 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 - -/* SPMT_OS2 only ever has 1 process */ -#define HARD_SERVER_LIMIT 1 - -/* 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_THREAD_LIMIT -#define HARD_THREAD_LIMIT 256 -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG "logs/httpd.pid" -#endif - -/* - * Interval, in microseconds, between scoreboard maintenance. - */ -#ifndef SCOREBOARD_MAINTENANCE_INTERVAL -#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 -#endif - -/* Number of requests to try to handle in a single process. If <= 0, - * the children don't die off. - */ -#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD -#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 -#endif - -/* AP_CHILD_THREAD_FROM_ID is used by the scoreboard. */ -#define AP_CHILD_THREAD_FROM_ID(i) 0, i - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/server/mpm/spmt_os2/spmt_os2.c b/server/mpm/spmt_os2/spmt_os2.c deleted file mode 100644 index b991c9df36..0000000000 --- a/server/mpm/spmt_os2/spmt_os2.c +++ /dev/null @@ -1,1322 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#define CORE_PRIVATE -#define INCL_DOS -#define INCL_DOSERRORS - -#include "ap_config.h" -#include "httpd.h" -#include "mpm_default.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "mpm.h" -#include "ap_mpm.h" -#include "ap_listen.h" -#include "apr_portable.h" -#include "mpm_common.h" -#include "apr_strings.h" - -#include <os2.h> -#include <stdlib.h> -#include <sys/signal.h> -#include <process.h> -#include <time.h> -#include <io.h> - -/* config globals */ - -static int ap_max_requests_per_child=0; -static char *ap_pid_fname=NULL; -static int ap_daemons_to_start=0; -static int ap_daemons_min_free=0; -static int ap_daemons_max_free=0; -static int ap_daemons_limit=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; -int ap_threads_per_child = HARD_THREAD_LIMIT; -ap_generation_t volatile ap_my_generation=0; /* Used by the scoreboard */ - -char ap_coredump_dir[MAX_STRING_LEN]; - -/* *Non*-shared http_main globals... */ - -server_rec *ap_server_conf; - -/* 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; - -static apr_pool_t *pconf; /* Pool for config stuff */ - -struct thread_globals { - int thread_num; - apr_pool_t *pchild; /* Pool for httpd child stuff */ - int usr1_just_die; -}; - -static struct thread_globals **ppthread_globals = NULL; - -#define THREAD_GLOBAL(gvar) ((*ppthread_globals)->gvar) - -struct thread_control_t { - apr_wait_t thread_retval; - char deferred_die; - ap_generation_t generation; /* generation of this thread */ -} thread_control[HARD_THREAD_LIMIT]; - -/* a clean exit from a child with proper cleanup */ -static void clean_child_exit(int code) -{ - if (THREAD_GLOBAL(pchild)) { - apr_pool_destroy(THREAD_GLOBAL(pchild)); - } - - thread_control[THREAD_GLOBAL(thread_num)].deferred_die = 0; - thread_control[THREAD_GLOBAL(thread_num)].thread_retval = code; - _endthread(); -} - - - -static apr_lock_t *accept_mutex = NULL; - -static apr_status_t accept_mutex_child_cleanup(void *foo) -{ - return apr_lock_release(accept_mutex); -} - -/* - * Initialize mutex lock. - * Done by each child at it's birth - */ -static void accept_mutex_child_init(apr_pool_t *p) -{ - apr_pool_cleanup_register(p, NULL, accept_mutex_child_cleanup, apr_pool_cleanup_null); -} - -/* - * Initialize mutex lock. - * Must be safe to call this on a restart. - */ -static void accept_mutex_init(apr_pool_t *p) -{ - apr_status_t rc = apr_lock_create(&accept_mutex, APR_MUTEX, APR_INTRAPROCESS, NULL, p); - - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rc, ap_server_conf, - "Error creating accept lock. Exiting!"); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - -static void accept_mutex_on(void) -{ - apr_status_t rc = apr_lock_acquire(accept_mutex); - - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rc, ap_server_conf, - "Error getting accept lock. Exiting!"); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - -static void accept_mutex_off(void) -{ - apr_status_t rc = apr_lock_release(accept_mutex); - - if (rc != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rc, ap_server_conf, - "Error freeing accept lock. Exiting!"); - clean_child_exit(APEXIT_CHILDFATAL); - } -} - - - -/* 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) {stmt;}} while(0) -#else -#define SAFE_ACCEPT(stmt) do {stmt;} while(0) -#endif - -static int find_thread_by_tid(int tid) -{ - int i; - - for (i = 0; i < max_daemons_limit; ++i) - if (ap_scoreboard_image->servers[0][i].tid == tid) - return i; - - return -1; -} - -/* Finally, this routine is used by the caretaker thread 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(apr_wait_t *status) -{ - int ret; - ULONG tid; - - ++wait_or_timeout_counter; - if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) { - wait_or_timeout_counter = 0; -#if APR_HAS_OTHER_CHILD - apr_proc_probe_writable_fds(); -#endif - } - - tid = 0; - ret = DosWaitThread(&tid, DCWW_NOWAIT); - - if (ret == 0) { - int thread_num = find_thread_by_tid(tid); - ap_assert( thread_num > 0 ); - *status = thread_control[thread_num].thread_retval; - return tid; - } - - DosSleep(SCOREBOARD_MAINTENANCE_INTERVAL / 1000); - return -1; -} - - - -/* handle all varieties of core dumping signals */ -static void sig_coredump(int sig) -{ - chdir(ap_coredump_dir); - signal(sig, SIG_DFL); - kill(getpid(), sig); - /* 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) -{ - clean_child_exit(0); -} - - -static void usr1_handler(int sig) -{ - if (THREAD_GLOBAL(usr1_just_die)) { - just_die(sig); - } - thread_control[THREAD_GLOBAL(thread_num)].deferred_die = 1; -} - -/* volatile just in case */ -static int volatile shutdown_pending; -static int volatile restart_pending; -static int volatile is_graceful; - -static void sig_term(int sig) -{ - 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; -} - -static void restart(int sig) -{ - if (restart_pending == 1) { - /* Probably not an error - don't bother reporting it */ - return; - } - restart_pending = 1; - is_graceful = sig == SIGUSR1; -} - -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, errno, ap_server_conf, "sigaction(SIGSEGV)"); -#ifdef SIGBUS - if (sigaction(SIGBUS, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)"); -#endif -#ifdef SIGABORT - if (sigaction(SIGABORT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)"); -#endif -#ifdef SIGABRT - if (sigaction(SIGABRT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)"); -#endif -#ifdef SIGILL - if (sigaction(SIGILL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_server_conf, "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_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, errno, ap_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, errno, ap_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, errno, ap_server_conf, "sigaction(SIGHUP)"); - if (sigaction(SIGUSR1, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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 -} - -/***************************************************************** - * Child process main loop. - */ - -AP_DECLARE(void) ap_child_terminate(request_rec *r) -{ - r->connection->keepalive = 0; - thread_control[THREAD_GLOBAL(thread_num)].deferred_die = 1; -} - - - -int ap_graceful_stop_signalled(void) -{ - if (thread_control[THREAD_GLOBAL(thread_num)].deferred_die || - ap_scoreboard_image->global.running_generation != thread_control[THREAD_GLOBAL(thread_num)].generation) { - return 1; - } - return 0; -} - - - -int ap_stop_signalled(void) -{ - if (shutdown_pending || restart_pending || - thread_control[THREAD_GLOBAL(thread_num)].deferred_die || - ap_scoreboard_image->global.running_generation != thread_control[THREAD_GLOBAL(thread_num)].generation) { - return 1; - } - return 0; -} - - - -static int setup_listen_poll(apr_pool_t *pchild, apr_pollfd_t **listen_poll) -{ - ap_listen_rec *lr; - int numfds = 0; - - for (lr = ap_listeners; lr; lr = lr->next) { - numfds++; - } - - apr_poll_setup(listen_poll, numfds, pchild); - - for (lr = ap_listeners; lr; lr = lr->next) { - apr_poll_socket_add(*listen_poll, lr->sd, APR_POLLIN); - } - return 0; -} - - - -static void thread_main(void *thread_num_arg) -{ - ap_listen_rec *lr = NULL; - ap_listen_rec *first_lr = NULL; - apr_pool_t *ptrans; - conn_rec *current_conn; - apr_pool_t *pchild; - int requests_this_child = 0; - apr_pollfd_t *listen_poll; - apr_socket_t *csd = NULL; - int nsds, rv; - - /* 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. - */ - - set_signals(); /* signals aren't inherrited by child threads */ - signal(SIGHUP, just_die); - signal(SIGUSR1, just_die); - signal(SIGTERM, just_die); - - /* Get a sub pool for global allocations in this child, so that - * we can have cleanups occur when the child exits. - */ - apr_pool_create(&pchild, pconf); - *ppthread_globals = (struct thread_globals *)apr_palloc(pchild, sizeof(struct thread_globals)); - THREAD_GLOBAL(thread_num) = (int)thread_num_arg; - THREAD_GLOBAL(pchild) = pchild; - thread_control[THREAD_GLOBAL(thread_num)].generation = ap_scoreboard_image->global.running_generation; - apr_pool_create(&ptrans, pchild); - - if (setup_listen_poll(pchild, &listen_poll)) { - clean_child_exit(1); - } - - /* needs to be done before we switch UIDs so we have permissions */ - SAFE_ACCEPT(accept_mutex_child_init(pchild)); - - ap_run_child_init(pchild, ap_server_conf); - - (void) ap_update_child_status(0, THREAD_GLOBAL(thread_num), SERVER_READY, (request_rec *) NULL); - - - signal(SIGHUP, just_die); - signal(SIGTERM, just_die); - - while (!ap_stop_signalled()) { - int srv; - apr_socket_t *sd; - - /* Prepare to receive a SIGUSR1 due to graceful restart so that - * we can exit cleanly. - */ - THREAD_GLOBAL(usr1_just_die) = 1; - signal(SIGUSR1, usr1_handler); - - /* - * (Re)initialize this child to a pre-connection state. - */ - - current_conn = NULL; - - apr_pool_clear(ptrans); - - if ((ap_max_requests_per_child > 0 - && requests_this_child++ >= ap_max_requests_per_child)) { - clean_child_exit(0); - } - - (void) ap_update_child_status(0, THREAD_GLOBAL(thread_num), SERVER_READY, (request_rec *) NULL); - - /* - * Wait for an acceptable connection to arrive. - */ - - /* Lock around "accept", if necessary */ - SAFE_ACCEPT(accept_mutex_on()); - - if (ap_stop_signalled()) { - clean_child_exit(0); - } - - for (;;) { - if (ap_listeners->next) { - /* more than one socket */ - srv = apr_poll(listen_poll, &nsds, -1); - - if (srv != APR_SUCCESS) { - /* 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, errno, ap_server_conf, "select: (listen)"); - clean_child_exit(1); - } - - /* we remember the last_lr we searched last time around so that - we don't end up starving any particular listening socket */ - if (first_lr == NULL) { - first_lr = ap_listeners; - } - - lr = first_lr; - - do { - apr_int16_t event; - - if (!lr) { - lr = ap_listeners; - } - - apr_poll_revents_get(&event, lr->sd, listen_poll); - - if (event == APR_POLLIN) { - first_lr = lr->next; - break; - } - lr = lr->next; - } while (lr != first_lr); - - if (lr == first_lr) { - continue; - } - sd = lr->sd; - } - else { - /* only one socket, just pretend we did the other stuff */ - sd = ap_listeners->sd; - } - - /* if we accept() something we don't want to die, so we have to - * defer the exit - */ - THREAD_GLOBAL(usr1_just_die) = 0; - rv = apr_accept(&csd, sd, ptrans); - - if (APR_STATUS_IS_SUCCESS(rv)) { - break; /* We have a socket ready for reading */ - } - else if (APR_STATUS_IS_ECONNABORTED(rv) - || APR_STATUS_IS_ECONNRESET(rv) - || APR_STATUS_IS_ETIMEDOUT(rv) - || APR_STATUS_IS_EHOSTUNREACH(rv) - || APR_STATUS_IS_ENETUNREACH(rv)) { - - /* 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. - */ - - /* Linux generates most 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. - */ - break; - } - else if (APR_STATUS_IS_EINTR(rv)) { - /* We only get hit by an EINTR if the parent is - * killing us off - */ - clean_child_exit(0); - } - else { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "accept: (client socket)"); - clean_child_exit(1); - } - - if (ap_stop_signalled()) { - clean_child_exit(0); - } - THREAD_GLOBAL(usr1_just_die) = 1; - } - - SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ - - /* We've got a socket, let's at least process one request off the - * socket before we accept a graceful restart request. We set - * the signal to ignore because we don't want to disturb any - * third party code. - */ - signal(SIGUSR1, SIG_IGN); - - /* - * We now have a connection, so set it up with the appropriate - * socket options, file descriptors, and read/write buffers. - */ - - ap_sock_disable_nagle(csd); - - current_conn = ap_new_connection(ptrans, ap_server_conf, csd, - THREAD_GLOBAL(thread_num)); - - if (current_conn) { - ap_process_connection(current_conn); - ap_lingering_close(current_conn); - } - } - - clean_child_exit(0); -} - - -static int make_child(server_rec *s, int slot) -{ - TID tid; - - if (slot + 1 > max_daemons_limit) { - max_daemons_limit = slot + 1; - } - - if (one_process) { - struct thread_globals *parent_globals = *ppthread_globals; - signal(SIGHUP, just_die); - signal(SIGINT, just_die); -#ifdef SIGQUIT - signal(SIGQUIT, SIG_DFL); -#endif - signal(SIGTERM, just_die); - thread_main((void *)slot); - *ppthread_globals = parent_globals; - } - - ap_update_child_status(0, slot, SERVER_STARTING, (request_rec *) NULL); - - if ((tid = _beginthread(thread_main, NULL, 256*1024, (void *)slot)) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, s, "_beginthread: Unable to create new thread"); - - /* _beginthread didn't succeed. Fix the scoreboard or else - * it will say SERVER_STARTING forever and ever - */ - (void) ap_update_child_status(0, 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 _beginthread over and - over and over again. */ - sleep(10); - - return -1; - } - - ap_scoreboard_image->servers[0][slot].tid = tid; - return 0; -} - - -/* start up a bunch of children */ -static void startup_children(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->servers[0][i].status != SERVER_DEAD) { - continue; - } - if (make_child(ap_server_conf, i) < 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; - 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; - - 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[0][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; - } - } - 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 - */ - thread_control[to_kill].deferred_die = 1; - 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, 0, ap_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, 0, ap_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) { - make_child(ap_server_conf, free_slots[i]); - } - /* 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; - } -} - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMONS: - *result = max_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_NOT_SUPPORTED; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = ap_threads_per_child; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -/***************************************************************** - * Executive routines. - */ - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int remaining_children_to_start; - int i; - apr_status_t status; - - pconf = _pconf; - ap_server_conf = s; - ap_log_pid(pconf, ap_pid_fname); - - if ((status = ap_listen_open(s->process, s->port)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, status, s, - "no listening sockets available, shutting down"); - return -1; - } - - SAFE_ACCEPT(accept_mutex_init(pconf)); - - if (!is_graceful) { - ap_create_scoreboard(pconf, SB_NOT_SHARED); - memset(thread_control, 0, sizeof(thread_control)); - } - - set_signals(); - DosSetMaxFH(ap_daemons_limit * 2); - - if (ppthread_globals == NULL) { - if (DosAllocThreadLocalMemory(1, (PULONG *)&ppthread_globals)) { - ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO, 0, ap_server_conf, - "Error allocating thread local storage" - "Apache is exiting!"); - } else { - *ppthread_globals = (struct thread_globals *)apr_palloc(pconf, sizeof(struct thread_globals)); - } - } - - 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, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); - restart_pending = shutdown_pending = 0; - - printf("%s \n", ap_get_server_version()); - - while (!restart_pending && !shutdown_pending) { - int thread_slot; - apr_wait_t status; - int tid = 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 (tid >= 0) { - apr_proc_t dummyproc; - dummyproc.pid = tid; - ap_process_child_status(&dummyproc, status); - /* non-fatal death... note that it's gone in the scoreboard. */ - thread_slot = find_thread_by_tid(tid); - if (thread_slot >= 0) { - (void) ap_update_child_status(0, thread_slot, SERVER_DEAD, - (request_rec *) NULL); - if (remaining_children_to_start - && thread_slot < ap_daemons_limit) { - /* we're still doing a 1-for-1 replacement of dead - * children with new children - */ - make_child(ap_server_conf, thread_slot); - --remaining_children_to_start; - } -#if APR_HAS_OTHER_CHILD -/* TODO: this won't work, we waited on a thread not a process - } - else if (reap_other_child(pid, status) == 0) { -*/ -#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, 0, ap_server_conf, - "long lost child came home! (tid %d)", tid); - } - /* 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(); - } - - if (shutdown_pending) { - /* Time to gracefully shut down */ - const char *pidfile = NULL; - int slot; - TID tid; - ULONG rc; - ap_listen_rec *lr; - - for (lr = ap_listeners; lr; lr = lr->next) { - apr_socket_close(lr->sd); - DosSleep(0); - } - - /* Kill off running threads */ - for (slot=0; slot<max_daemons_limit; slot++) { - if (ap_scoreboard_image->servers[0][slot].status != SERVER_DEAD) { - tid = ap_scoreboard_image->servers[0][slot].tid; - rc = DosKillThread(tid); - - if (rc != ERROR_INVALID_THREADID) { // Already dead, ignore - if (rc == 0) { - rc = DosWaitThread(&tid, DCWW_WAIT); - - if (rc) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, ap_server_conf, - "error %lu waiting for thread to terminate", rc); - } - } else { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, ap_server_conf, - "error %lu killing thread", rc); - } - } - } - } - - /* cleanup pid file on normal shutdown */ - pidfile = ap_server_root_relative (pconf, ap_pid_fname); - if ( pidfile != NULL && unlink(pidfile) == 0) - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, - ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "caught SIGTERM, shutting down"); - return 1; - } - - /* we've been told to restart */ - signal(SIGHUP, SIG_IGN); - signal(SIGUSR1, SIG_IGN); - - if (one_process) { - /* not worth thinking about */ - return 1; - } - - /* 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_scoreboard_image->global.running_generation; - - if (is_graceful) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "SIGUSR1 received. Doing graceful restart"); - - /* kill off the idle ones */ - for (i = 0; i < ap_daemons_limit; ++i) { - thread_control[i].deferred_die = 1; - } - - /* 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. - */ - for (i = 0; i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->servers[0][i].status != SERVER_DEAD) { - ap_scoreboard_image->servers[0][i].status = SERVER_GRACEFUL; - } - } - } - else { - /* Kill 'em off */ - for (i = 0; i < ap_daemons_limit; ++i) { - DosKillThread(ap_scoreboard_image->servers[0][i].tid); - } - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "SIGHUP received. Attempting to restart"); - } - - return 0; -} - -static void spmt_os2_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) -{ - one_process = !!ap_exists_config_define("ONE_PROCESS"); - - is_graceful = 0; - ap_listen_pre_config(); - 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_THREAD_LIMIT; - ap_pid_fname = DEFAULT_PIDLOG; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - ap_extended_status = 0; - ap_scoreboard_fname = NULL; - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); -} - -static void spmt_os2_hooks(apr_pool_t *p) -{ - /* TODO: set one_process properly */ one_process = 0; - - ap_hook_pre_config(spmt_os2_pre_config, NULL, NULL, APR_HOOK_MIDDLE); -} - -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 <VirtualHost>"; - } - ap_pid_fname = arg; - return NULL; -} - -static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_to_start = atoi(arg); - 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) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: detected MinSpareServers set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Please read the documentation."); - 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_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: MaxClients of %d exceeds compile time limit " - "of %d servers,", ap_daemons_limit, HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering MaxClients to %d. To increase, please " - "see the", HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " HARD_THREAD_LIMIT define in %s.", - AP_MPM_HARD_LIMITS_FILE); - ap_daemons_limit = HARD_THREAD_LIMIT; - } - else if (ap_daemons_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: Require MaxClients > 0, setting to 1"); - 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_coredumpdir (cmd_parms *cmd, void *dummy, char *arg) -{ - apr_finfo_t finfo; - const char *fname; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - fname = ap_server_root_relative(cmd->pool, arg); - if ((apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) - || (finfo.filetype != APR_DIR)) { - return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, - " does not exist or is not a directory", NULL); - } - apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir)); - return NULL; -} - -/* Stub functions until this MPM supports the connection status API */ - -AP_DECLARE(void) ap_update_connection_status(long conn_id, const char *key, \ - const char *value) -{ - /* NOP */ -} - -AP_DECLARE(void) ap_reset_connection_status(long conn_id) -{ - /* NOP */ -} - -static const command_rec spmt_os2_cmds[] = { -LISTEN_COMMANDS -{ "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1, - "A file for logging the server process ID"}, -{ "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" }, -{ "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." }, -{ "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1, - "The location of the directory Apache changes to before dumping core" }, -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA mpm_spmt_os2_module = { - MPM20_MODULE_STUFF, - NULL, /* hook to run before apache parses args */ - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - spmt_os2_cmds, /* command apr_table_t */ - spmt_os2_hooks, /* register_hooks */ -}; diff --git a/server/mpm/threaded/.cvsignore b/server/mpm/threaded/.cvsignore deleted file mode 100644 index 84df257214..0000000000 --- a/server/mpm/threaded/.cvsignore +++ /dev/null @@ -1,5 +0,0 @@ -.deps -.libs -*.lo -*.la -Makefile diff --git a/server/mpm/threaded/Makefile.in b/server/mpm/threaded/Makefile.in deleted file mode 100644 index b5fb3691a6..0000000000 --- a/server/mpm/threaded/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ - -LTLIBRARY_NAME = libthreaded.la -LTLIBRARY_SOURCES = threaded.c - -include $(top_srcdir)/build/ltlib.mk diff --git a/server/mpm/threaded/config5.m4 b/server/mpm/threaded/config5.m4 deleted file mode 100644 index dbc00cbf72..0000000000 --- a/server/mpm/threaded/config5.m4 +++ /dev/null @@ -1,5 +0,0 @@ -dnl ## XXX - Need a more thorough check of the proper flags to use - -if test "$MPM_NAME" = "threaded" ; then - APACHE_FAST_OUTPUT(server/mpm/$MPM_NAME/Makefile) -fi diff --git a/server/mpm/threaded/mpm.h b/server/mpm/threaded/mpm.h deleted file mode 100644 index 3359f8cca5..0000000000 --- a/server/mpm/threaded/mpm.h +++ /dev/null @@ -1,79 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ -#include "scoreboard.h" -#include "unixd.h" - -#ifndef APACHE_MPM_THREADED_H -#define APACHE_MPM_THREADED_H - -#define THREADED_MPM - -#define MPM_NAME "Threaded" - -#define AP_MPM_NEEDS_RECLAIM_CHILD_PROCESSES 1 -#define MPM_SYNC_CHILD_TABLE() (ap_sync_scoreboard_image()) -#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) -#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) - -extern int ap_threads_per_child; -extern int ap_max_requests_per_child; -extern int ap_max_daemons_limit; -extern server_rec *ap_server_conf; -extern char ap_coredump_dir[MAX_STRING_LEN]; - -#endif /* APACHE_MPM_THREADED_H */ diff --git a/server/mpm/threaded/mpm_default.h b/server/mpm/threaded/mpm_default.h deleted file mode 100644 index 84c1304bfa..0000000000 --- a/server/mpm/threaded/mpm_default.h +++ /dev/null @@ -1,154 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -#define AP_ID_FROM_CHILD_THREAD(c, t) ((c * HARD_THREAD_LIMIT) + t) -#define AP_CHILD_THREAD_FROM_ID(i) (i / HARD_THREAD_LIMIT), (i % HARD_THREAD_LIMIT) - -/* 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 3 -#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 3 -#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. - */ -#ifdef NO_THREADS -#define HARD_SERVER_LIMIT 256 -#endif -#ifndef HARD_SERVER_LIMIT -#define HARD_SERVER_LIMIT 8 -#endif - -/* Limit on the threads per process. Clients will be locked out if more than - * this * HARD_SERVER_LIMIT are needed. - * - * We keep this for one reason it keeps the size of the scoreboard file small - * enough that we can read the whole thing without worrying too much about - * the overhead. - */ -#ifdef NO_THREADS -#define HARD_THREAD_LIMIT 1 -#endif -#ifndef HARD_THREAD_LIMIT -#define HARD_THREAD_LIMIT 64 -#endif - -#ifdef NO_THREADS -#define DEFAULT_THREADS_PER_CHILD 1 -#endif -#ifndef DEFAULT_THREADS_PER_CHILD -#define DEFAULT_THREADS_PER_CHILD 25 -#endif - -/* File used for accept locking, when we use a file */ -#ifndef DEFAULT_LOCKFILE -#define DEFAULT_LOCKFILE "logs/accept.lock" -#endif - -/* Scoreboard file, if there is one */ -#ifndef DEFAULT_SCOREBOARD -#define DEFAULT_SCOREBOARD "logs/apache_runtime_status" -#endif - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG "logs/httpd.pid" -#endif - -/* - * Interval, in microseconds, between scoreboard maintenance. - */ -#ifndef SCOREBOARD_MAINTENANCE_INTERVAL -#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 -#endif - -/* Number of requests to try to handle in a single process. If <= 0, - * the children don't die off. - */ -#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD -#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 -#endif - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/server/mpm/threaded/threaded.c b/server/mpm/threaded/threaded.c deleted file mode 100644 index 05e29a781b..0000000000 --- a/server/mpm/threaded/threaded.c +++ /dev/null @@ -1,1450 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr.h" -#include "apr_portable.h" -#include "apr_strings.h" -#include "apr_file_io.h" -#include "apr_thread_proc.h" -#include "apr_signal.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#if APR_HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif - -#if !APR_HAS_THREADS -#error The threaded MPM requires APR threads, but they are unavailable. -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" /* for read_config */ -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "ap_mpm.h" -#include "unixd.h" -#include "mpm_common.h" -#include "ap_listen.h" -#include "scoreboard.h" - -#include <signal.h> -#include <limits.h> /* for INT_MAX */ - -/* - * Actual definitions of config globals - */ - -int ap_threads_per_child=0; /* Worker threads per child */ -int ap_max_requests_per_child=0; -static const char *ap_pid_fname=NULL; -static int ap_daemons_to_start=0; -static int min_spare_threads=0; -static int max_spare_threads=0; -static int ap_daemons_limit=0; -static int workers_may_exit = 0; -static int requests_this_child; -static int num_listensocks = 0; -static apr_socket_t **listensocks; - -/* The structure used to pass unique initialization info to each thread */ -typedef struct { - int pid; - int tid; - int sd; - apr_pool_t *tpool; /* "pthread" would be confusing */ -} proc_info; - -/* - * The max child slot ever assigned, preserved across restarts. Necessary - * to deal with MaxClients changes across SIGWINCH restarts. We use this - * value to optimize routines that have to scan the entire scoreboard. - */ -int ap_max_daemons_limit = -1; - -char ap_coredump_dir[MAX_STRING_LEN]; - -static apr_file_t *pipe_of_death_in = NULL; -static apr_file_t *pipe_of_death_out = NULL; -static apr_lock_t *pipe_of_death_mutex; /* insures that a child process only - consumes one character */ - -/* *Non*-shared http_main globals... */ - -server_rec *ap_server_conf; - -/* 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; - -#ifdef DEBUG_SIGSTOP -int raise_sigstop_flags; -#endif - -static apr_pool_t *pconf; /* Pool for config stuff */ -static apr_pool_t *pchild; /* Pool for httpd child stuff */ - -static pid_t ap_my_pid; /* Linux getpid() doesn't work except in main - thread. Use this instead */ -/* Keep track of the number of worker threads currently active */ -static int worker_thread_count; -static apr_lock_t *worker_thread_count_mutex; - -/* Locks for accept serialization */ -static apr_lock_t *accept_mutex; -static const char *lock_fname; - -#ifdef NO_SERIALIZED_ACCEPT -#define SAFE_ACCEPT(stmt) APR_SUCCESS -#else -#define SAFE_ACCEPT(stmt) (stmt) -#endif - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMONS: - *result = ap_max_daemons_limit; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_STATIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_DYNAMIC; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = ap_threads_per_child; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -/* 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) { - apr_pool_destroy(pchild); - } - exit(code); -} - -/* handle all varieties of core dumping signals */ -static void sig_coredump(int sig) -{ - chdir(ap_coredump_dir); - apr_signal(sig, SIG_DFL); - kill(ap_my_pid, sig); - /* 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. - */ -} - -static void just_die(int sig) -{ - clean_child_exit(0); -} - -/***************************************************************** - * Connection structures and accounting... - */ - -/* 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; - -/* - * 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. - * - * These should only be called from the parent process itself, since the - * parent process will use the shutdown_pending and restart_pending variables - * to determine whether to shutdown or restart. The child process should - * call signal_parent() directly to tell the parent to die -- this will - * cause neither of those variable to be set, which the parent will - * assume means something serious is wrong (which it will be, for the - * child to force an exit) and so do an exit anyway. - */ - -static void ap_start_shutdown(void) -{ - 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; -} - -/* do a graceful restart if graceful == 1 */ -static void ap_start_restart(int graceful) -{ - - if (restart_pending == 1) { - /* Probably not an error - don't bother reporting it */ - return; - } - restart_pending = 1; - is_graceful = graceful; - if (is_graceful) { - apr_pool_cleanup_kill(pconf, NULL, ap_cleanup_scoreboard); - } -} - -static void sig_term(int sig) -{ - ap_start_shutdown(); -} - -static void restart(int sig) -{ - ap_start_restart(sig == SIGWINCH); -} - -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, errno, ap_server_conf, "sigaction(SIGSEGV)"); -#ifdef SIGBUS - if (sigaction(SIGBUS, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)"); -#endif -#ifdef SIGABORT - if (sigaction(SIGABORT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)"); -#endif -#ifdef SIGABRT - if (sigaction(SIGABRT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)"); -#endif -#ifdef SIGILL - if (sigaction(SIGILL, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_server_conf, "sigaction(SIGTERM)"); -#ifdef SIGINT - if (sigaction(SIGINT, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_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, errno, ap_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, errno, ap_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, errno, ap_server_conf, "sigaction(SIGPIPE)"); -#endif - - /* we want to ignore HUPs and WINCH while we're busy processing one */ - sigaddset(&sa.sa_mask, SIGHUP); - sigaddset(&sa.sa_mask, SIGWINCH); - sa.sa_handler = restart; - if (sigaction(SIGHUP, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); - if (sigaction(SIGWINCH, &sa, NULL) < 0) - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGWINCH)"); -#else - if (!one_process) { - apr_signal(SIGSEGV, sig_coredump); -#ifdef SIGBUS - apr_signal(SIGBUS, sig_coredump); -#endif /* SIGBUS */ -#ifdef SIGABORT - apr_signal(SIGABORT, sig_coredump); -#endif /* SIGABORT */ -#ifdef SIGABRT - apr_signal(SIGABRT, sig_coredump); -#endif /* SIGABRT */ -#ifdef SIGILL - apr_signal(SIGILL, sig_coredump); -#endif /* SIGILL */ -#ifdef SIGXCPU - apr_signal(SIGXCPU, SIG_DFL); -#endif /* SIGXCPU */ -#ifdef SIGXFSZ - apr_signal(SIGXFSZ, SIG_DFL); -#endif /* SIGXFSZ */ - } - - apr_signal(SIGTERM, sig_term); -#ifdef SIGHUP - apr_signal(SIGHUP, restart); -#endif /* SIGHUP */ -#ifdef SIGWINCH - apr_signal(SIGWINCH, restart); -#endif /* SIGWINCH */ -#ifdef SIGPIPE - apr_signal(SIGPIPE, SIG_IGN); -#endif /* SIGPIPE */ - -#endif -} - -/***************************************************************** - * Here follows a long bunch of generic server bookkeeping stuff... - */ - -int ap_graceful_stop_signalled(void) -{ - /* XXX - Does this really work? - Manoj */ - return is_graceful; -} - -/***************************************************************** - * Child process main loop. - */ - -static void process_socket(apr_pool_t *p, apr_socket_t *sock, int my_child_num, int my_thread_num) -{ - conn_rec *current_conn; - long conn_id = AP_ID_FROM_CHILD_THREAD(my_child_num, my_thread_num); - int csd; - - (void) apr_os_sock_get(&csd, sock); - - if (csd >= FD_SETSIZE) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, NULL, - "new file descriptor %d is too large; you probably need " - "to rebuild Apache with a larger FD_SETSIZE " - "(currently %d)", - csd, FD_SETSIZE); - apr_socket_close(sock); - return; - } - - ap_sock_disable_nagle(sock); - - current_conn = ap_new_connection(p, ap_server_conf, sock, conn_id); - if (current_conn) { - ap_process_connection(current_conn); - ap_lingering_close(current_conn); - } -} -/* Sets workers_may_exit if we received a character on the pipe_of_death */ -static void check_pipe_of_death(void) -{ - apr_lock_acquire(pipe_of_death_mutex); - if (!workers_may_exit) { - apr_status_t ret; - char pipe_read_char; - apr_size_t n = 1; - - ret = apr_recv(listensocks[0], &pipe_read_char, &n); - if (APR_STATUS_IS_EAGAIN(ret)) { - /* It lost the lottery. It must continue to suffer - * through a life of servitude. */ - } - else { - /* It won the lottery (or something else is very - * wrong). Embrace death with open arms. */ - workers_may_exit = 1; - } - } - apr_lock_release(pipe_of_death_mutex); -} - -static void * worker_thread(void * dummy) -{ - proc_info * ti = dummy; - int process_slot = ti->pid; - int thread_slot = ti->tid; - apr_pool_t *tpool = ti->tpool; - apr_socket_t *csd = NULL; - apr_pool_t *ptrans; /* Pool for per-transaction stuff */ - apr_socket_t *sd = NULL; - int n; - int curr_pollfd, last_pollfd = 0; - apr_pollfd_t *pollset; - apr_status_t rv; - - free(ti); - - apr_pool_create(&ptrans, tpool); - - apr_lock_acquire(worker_thread_count_mutex); - worker_thread_count++; - apr_lock_release(worker_thread_count_mutex); - - apr_poll_setup(&pollset, num_listensocks+1, tpool); - for(n=0 ; n <= num_listensocks ; ++n) - apr_poll_socket_add(pollset, listensocks[n], APR_POLLIN); - - /* TODO: Switch to a system where threads reuse the results from earlier - poll calls - manoj */ - while (1) { - workers_may_exit |= (requests_this_child <= 0); - if (workers_may_exit) break; - - (void) ap_update_child_status(process_slot, thread_slot, SERVER_READY, - (request_rec *) NULL); - if ((rv = SAFE_ACCEPT(apr_lock_acquire(accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_lock_acquire failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - - while (!workers_may_exit) { - apr_status_t ret; - apr_int16_t event; - - ret = apr_poll(pollset, &n, -1); - if (ret != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(ret)) { - continue; - } - - /* apr_poll() will only return errors in catastrophic - * circumstances. Let's try exiting gracefully, for now. */ - ap_log_error(APLOG_MARK, APLOG_ERR, ret, (const server_rec *) - ap_server_conf, "apr_poll: (listen)"); - workers_may_exit = 1; - } - - if (workers_may_exit) break; - - apr_poll_revents_get(&event, listensocks[0], pollset); - if (event & APR_POLLIN) { - /* A process got a signal on the shutdown pipe. Check if we're - * the lucky process to die. */ - check_pipe_of_death(); - continue; - } - - if (num_listensocks == 1) { - sd = ap_listeners->sd; - goto got_fd; - } - else { - /* find a listener */ - curr_pollfd = last_pollfd; - do { - curr_pollfd++; - if (curr_pollfd > num_listensocks) { - curr_pollfd = 1; - } - /* XXX: Should we check for POLLERR? */ - apr_poll_revents_get(&event, listensocks[curr_pollfd], pollset); - if (event & APR_POLLIN) { - last_pollfd = curr_pollfd; - sd=listensocks[curr_pollfd]; - goto got_fd; - } - } while (curr_pollfd != last_pollfd); - } - } - got_fd: - if (!workers_may_exit) { - if ((rv = apr_accept(&csd, sd, ptrans)) != APR_SUCCESS) { - csd = NULL; - ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, - "apr_accept"); - } - if ((rv = SAFE_ACCEPT(apr_lock_release(accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_lock_release failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - if (csd != NULL) { - process_socket(ptrans, csd, process_slot, thread_slot); - requests_this_child--; - } - } - else { - if ((rv = SAFE_ACCEPT(apr_lock_release(accept_mutex))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "apr_lock_release failed. Attempting to shutdown " - "process gracefully."); - workers_may_exit = 1; - } - break; - } - apr_pool_clear(ptrans); - } - - apr_pool_destroy(tpool); - ap_update_child_status(process_slot, thread_slot, SERVER_DEAD, - (request_rec *) NULL); - apr_lock_acquire(worker_thread_count_mutex); - worker_thread_count--; - if (worker_thread_count == 0) { - /* All the threads have exited, now finish the shutdown process - * by signalling the sigwait thread */ - kill(ap_my_pid, SIGTERM); - } - apr_lock_release(worker_thread_count_mutex); - - return NULL; -} - -static int check_signal(int signum) -{ - switch (signum) { - case SIGTERM: - case SIGINT: - return 1; - } - return 0; -} - -static void child_main(int child_num_arg) -{ - apr_thread_t **threads; - apr_threadattr_t *thread_attr; - int i; - int my_child_num = child_num_arg; - proc_info *my_info = NULL; - ap_listen_rec *lr; - apr_status_t rv; - - - ap_my_pid = getpid(); - apr_pool_create(&pchild, pconf); - - /*stuff to do before we switch id's, so we have permissions.*/ - reopen_scoreboard(pchild); - - rv = SAFE_ACCEPT(apr_lock_child_init(&accept_mutex, lock_fname, - pchild)); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize cross-process lock in child"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - if (unixd_setup_child()) { - clean_child_exit(APEXIT_CHILDFATAL); - } - - ap_run_child_init(pchild, ap_server_conf); - - /*done with init critical section */ - - rv = apr_setup_signal_thread(); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, - "Couldn't initialize signal thread"); - clean_child_exit(APEXIT_CHILDFATAL); - } - - requests_this_child = ap_max_requests_per_child; - - /* Set up the pollfd array */ - listensocks = apr_pcalloc(pchild, - sizeof(*listensocks) * (num_listensocks + 1)); -#if APR_FILES_AS_SOCKETS - apr_socket_from_file(&listensocks[0], pipe_of_death_in); -#endif - for (lr = ap_listeners, i = 1; i <= num_listensocks; lr = lr->next, ++i) - listensocks[i]=lr->sd; - - /* Setup worker threads */ - - threads = (apr_thread_t **)malloc(sizeof(apr_thread_t *) * ap_threads_per_child); - if (threads == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf, - "malloc: out of memory"); - clean_child_exit(APEXIT_CHILDFATAL); - } - worker_thread_count = 0; - apr_lock_create(&worker_thread_count_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - apr_lock_create(&pipe_of_death_mutex, APR_MUTEX, APR_INTRAPROCESS, - NULL, pchild); - apr_threadattr_create(&thread_attr, pchild); - apr_threadattr_detach_set(thread_attr, 0); /* 0 means PTHREAD_CREATE_JOINABLE */ - - for (i=0; i < ap_threads_per_child; i++) { - - my_info = (proc_info *)malloc(sizeof(proc_info)); - if (my_info == NULL) { - ap_log_error(APLOG_MARK, APLOG_ALERT, errno, ap_server_conf, - "malloc: out of memory"); - clean_child_exit(APEXIT_CHILDFATAL); - } - my_info->pid = my_child_num; - my_info->tid = i; - my_info->sd = 0; - apr_pool_create(&my_info->tpool, pchild); - - /* We are creating threads right now */ - (void) ap_update_child_status(my_child_num, i, SERVER_STARTING, - (request_rec *) NULL); - if ((rv = apr_thread_create(&threads[i], thread_attr, worker_thread, my_info, pchild))) { - ap_log_error(APLOG_MARK, APLOG_ALERT, rv, ap_server_conf, - "apr_thread_create: unable to create worker thread"); - /* 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 if we exit. */ - sleep(10); - clean_child_exit(APEXIT_CHILDFATAL); - } - /* We let each thread update it's own scoreboard entry. This is done - * because it let's us deal with tid better. - */ - } - - /* What state should this child_main process be listed as in the scoreboard...? - * ap_update_child_status(my_child_num, i, SERVER_STARTING, (request_rec *) NULL); - * - * This state should be listed separately in the scoreboard, in some kind - * of process_status, not mixed in with the worker threads' status. - * "life_status" is almost right, but it's in the worker's structure, and - * the name could be clearer. gla - */ - - apr_signal_thread(check_signal); - - workers_may_exit = 1; /* helps us terminate a little more quickly when - * the dispatch of the signal thread - * beats the Pipe of Death and the browsers - */ - - /* A terminating signal was received. Now join each of the workers to clean them up. - * If the worker already exited, then the join frees their resources and returns. - * If the worker hasn't exited, then this blocks until they have (then cleans up). - */ - for (i = 0; i < ap_threads_per_child; i++) { - apr_thread_join(&rv, threads[i]); - } - - free (threads); - - clean_child_exit(0); -} - -static int make_child(server_rec *s, int slot) -{ - int pid; - - if (slot + 1 > ap_max_daemons_limit) { - ap_max_daemons_limit = slot + 1; - } - - if (one_process) { - set_signals(); - ap_scoreboard_image->parent[slot].pid = getpid(); - child_main(slot); - } - - /* Tag this slot as occupied so that perform_idle_server_maintenance - * doesn't try to steal it */ - (void) ap_update_child_status(slot, 0, SERVER_STARTING, (request_rec *) NULL); - - if ((pid = fork()) == -1) { - ap_log_error(APLOG_MARK, APLOG_ERR, errno, 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, 0, 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 <sys/processor.h> - int status = bindprocessor(BINDPROCESS, (int)getpid(), - PROCESSOR_CLASS_ANY); - if (status != OK) - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, errno, ap_server_conf, - "processor unbind failed %d", status); -#endif - - RAISE_SIGSTOP(MAKE_CHILD); - - apr_signal(SIGTERM, just_die); - child_main(slot); - - clean_child_exit(0); - } - /* else */ - ap_scoreboard_image->parent[slot].pid = pid; - return 0; -} - -/* If there aren't many connections coming in from the network, the child - * processes may need to be awakened from their network i/o waits. - * The pipe of death is an effective prod. - */ - -static void wake_up_and_die(void) -{ - int i; - char char_of_death = '!'; - apr_size_t one = 1; - apr_status_t rv; - - for (i = 0; i < ap_daemons_limit;) { - if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) - != APR_SUCCESS) { - if (APR_STATUS_IS_EINTR(rv)) continue; - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, - "write pipe_of_death"); - } - i++; - } -} - -/* start up a bunch of children */ -static void startup_children(int number_to_start) -{ - int i; - - for (i = 0; number_to_start && i < ap_daemons_limit; ++i) { - if (ap_scoreboard_image->parent[i].pid != 0) { - continue; - } - if (make_child(ap_server_conf, i) < 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, j; - int idle_thread_count; - short_score *ss; - int free_length; - int free_slots[MAX_SPAWN_RATE]; - int last_non_dead; - int total_non_dead; - apr_size_t one = 1; - apr_status_t rv; - - /* initialize the free_list */ - free_length = 0; - - idle_thread_count = 0; - last_non_dead = -1; - total_non_dead = 0; - - ap_sync_scoreboard_image(); - for (i = 0; i < ap_daemons_limit; ++i) { - /* Initialization to satisfy the compiler. It doesn't know - * that ap_threads_per_child is always > 0 */ - int status = SERVER_DEAD; - int any_dying_threads = 0; - int all_dead_threads = 1; - int idle_thread_addition = 0; - - if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate) - break; - for (j = 0; j < ap_threads_per_child; j++) { - ss = &ap_scoreboard_image->servers[i][j]; - status = ss->status; - - any_dying_threads = any_dying_threads || (status == SERVER_DEAD) - || (status == SERVER_GRACEFUL); - all_dead_threads = all_dead_threads && (status == SERVER_DEAD); - - /* 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_thread_addition; - } - } - if (all_dead_threads && free_length < idle_spawn_rate) { - free_slots[free_length] = i; - ++free_length; - } - if (!all_dead_threads) { - last_non_dead = i; - } - if (!any_dying_threads) { - ++total_non_dead; - idle_thread_count += idle_thread_addition; - } - } - ap_max_daemons_limit = last_non_dead + 1; - - if (idle_thread_count > max_spare_threads) { - /* Kill off one child */ - char char_of_death = '!'; - if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, "write pipe_of_death"); - } - idle_spawn_rate = 1; - } - else if (idle_thread_count < min_spare_threads) { - /* 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, 0, ap_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, 0, ap_server_conf, - "server seems busy, (you may need " - "to increase StartServers, ThreadsPerChild " - "or Min/MaxSpareThreads), " - "spawning %d children, there are around %d idle " - "threads, and %d total children", idle_spawn_rate, - idle_thread_count, total_non_dead); - } - for (i = 0; i < free_length; ++i) { - make_child(ap_server_conf, free_slots[i]); - } - /* 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 server_main_loop(int remaining_children_to_start) -{ - int child_slot; - apr_wait_t status; - apr_proc_t pid; - int i; - - while (!restart_pending && !shutdown_pending) { - ap_wait_or_timeout(&status, &pid, pconf); - - if (pid.pid != -1) { - ap_process_child_status(&pid, status); - /* non-fatal death... note that it's gone in the scoreboard. */ - child_slot = find_child_by_pid(&pid); - if (child_slot >= 0) { - for (i = 0; i < ap_threads_per_child; i++) - ap_update_child_status(child_slot, i, 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(ap_server_conf, child_slot); - --remaining_children_to_start; - } -#if APR_HAS_OTHER_CHILD - } - else if (apr_proc_other_child_read(&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, 0, - ap_server_conf, - "long lost child came home! (pid %ld)", - (long)pid.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(); - } -} - -int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) -{ - int remaining_children_to_start; - apr_status_t rv; - - pconf = _pconf; - ap_server_conf = s; - rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out, pconf); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, - (const server_rec*) ap_server_conf, - "apr_file_pipe_create (pipe_of_death)"); - exit(1); - } - - if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, - (const server_rec*) ap_server_conf, - "apr_file_pipe_timeout_set (pipe_of_death)"); - exit(1); - } - ap_server_conf = s; - if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { - /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s, - "no listening sockets available, shutting down"); - return 1; - } - ap_log_pid(pconf, ap_pid_fname); - - /* Initialize cross-process accept lock */ - lock_fname = apr_psprintf(_pconf, "%s.%" APR_OS_PROC_T_FMT, - ap_server_root_relative(_pconf, lock_fname), - ap_my_pid); - rv = apr_lock_create(&accept_mutex, APR_MUTEX, APR_LOCKALL, - lock_fname, _pconf); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, - "Couldn't create accept lock"); - return 1; - } - - - if (!is_graceful) { - ap_create_scoreboard(pconf, SB_SHARED); - } - - set_signals(); - /* Don't thrash... */ - if (max_spare_threads < min_spare_threads + ap_threads_per_child) - max_spare_threads = min_spare_threads + ap_threads_per_child; - - /* 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 SIGWINCH). 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, 0, ap_server_conf, - "%s configured -- resuming normal operations", - ap_get_server_version()); - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf, - "Server built: %s", ap_get_server_built()); - restart_pending = shutdown_pending = 0; - - server_main_loop(remaining_children_to_start); - - if (shutdown_pending) { - /* Time to gracefully shut down: - * Kill child processes, tell them to call child_exit, etc... - */ - wake_up_and_die(); - - if (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM"); - } - ap_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, 0, - ap_server_conf, - "removed PID file %s (pid=%ld)", - pidfile, (long)getpid()); - } - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "caught SIGTERM, shutting down"); - - return 1; - } - - /* we've been told to restart */ - apr_signal(SIGHUP, SIG_IGN); - - if (one_process) { - /* not worth thinking about */ - return 1; - } - - /* 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(); - - /* wake up the children...time to die. But we'll have more soon */ - wake_up_and_die(); - - if (is_graceful) { - int i, j; - - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "SIGWINCH received. Doing graceful restart"); - - /* This is mostly for debugging... so that we know what is still - * gracefully dealing with existing request. - */ - - for (i = 0; i < ap_daemons_limit; ++i) { - for (j = 0; j < ap_threads_per_child; j++) { - if (ap_scoreboard_image->servers[i][j].status != SERVER_DEAD) { - ap_scoreboard_image->servers[i][j].status = SERVER_GRACEFUL; - } - } - } - } - else { - /* Kill 'em all. Since the child acts the same on the parents SIGTERM - * and a SIGHUP, we may as well use the same signal, because some user - * pthreads are stealing signals from us left and right. - */ - if (unixd_killpg(getpgrp(), SIGTERM) < 0) { - ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM"); - } - ap_reclaim_child_processes(1); /* Start with SIGTERM */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf, - "SIGHUP received. Attempting to restart"); - } - return 0; -} - -static void threaded_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) -{ - static int restart_num = 0; - int no_detach = 0; - - one_process = !!ap_exists_config_define("ONE_PROCESS"); - no_detach = !!ap_exists_config_define("NO_DETACH"); - - /* sigh, want this only the second time around */ - if (restart_num++ == 1) { - is_graceful = 0; - - if (!one_process && !no_detach) { - apr_proc_detach(); - } - ap_my_pid = getpid(); - } - - unixd_pre_config(ptemp); - ap_listen_pre_config(); - ap_daemons_to_start = DEFAULT_START_DAEMON; - min_spare_threads = DEFAULT_MIN_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; - max_spare_threads = DEFAULT_MAX_FREE_DAEMON * DEFAULT_THREADS_PER_CHILD; - ap_daemons_limit = HARD_SERVER_LIMIT; - ap_threads_per_child = DEFAULT_THREADS_PER_CHILD; - ap_pid_fname = DEFAULT_PIDLOG; - ap_scoreboard_fname = DEFAULT_SCOREBOARD; - lock_fname = DEFAULT_LOCKFILE; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - ap_extended_status = 0; - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); -} - -static void threaded_hooks(apr_pool_t *p) -{ - one_process = 0; - - ap_hook_pre_config(threaded_pre_config, NULL, NULL, APR_HOOK_MIDDLE); -} - - -static const char *set_pidfile(cmd_parms *cmd, void *dummy, const 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 <VirtualHost>"; - } - ap_pid_fname = arg; - return NULL; -} - -static const char *set_scoreboard(cmd_parms *cmd, void *dummy, - const 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, const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - lock_fname = arg; - return NULL; -} - -static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_daemons_to_start = atoi(arg); - return NULL; -} - -static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - min_spare_threads = atoi(arg); - if (min_spare_threads <= 0) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: detected MinSpareThreads set to non-positive."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Resetting to 1 to avoid almost certain Apache failure."); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Please read the documentation."); - min_spare_threads = 1; - } - - return NULL; -} - -static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - max_spare_threads = atoi(arg); - return NULL; -} - -static const char *set_server_limit (cmd_parms *cmd, void *dummy, - const 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) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: MaxClients of %d exceeds compile time limit " - "of %d servers,", ap_daemons_limit, HARD_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering MaxClients to %d. To increase, please " - "see the", HARD_SERVER_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " HARD_SERVER_LIMIT define in %s.", - AP_MPM_HARD_LIMITS_FILE); - ap_daemons_limit = HARD_SERVER_LIMIT; - } - else if (ap_daemons_limit < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "WARNING: Require MaxClients > 0, setting to 1"); - ap_daemons_limit = 1; - } - return NULL; -} - -static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, - const 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_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds compile time" - "limit of %d threads,", ap_threads_per_child, - HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering ThreadsPerChild to %d. To increase, please" - " see the", HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " HARD_THREAD_LIMIT define in %s.", - AP_MPM_HARD_LIMITS_FILE); - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 1; - } - return NULL; -} - -static const char *set_max_requests(cmd_parms *cmd, void *dummy, - const char *arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - ap_max_requests_per_child = atoi(arg); - - /* a value of zero means infinity. The following removes a conditional - * from worker_thread's hot path - */ - - if (!ap_max_requests_per_child) { - ap_max_requests_per_child = INT_MAX; - } - - return NULL; -} - -static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, - const char *arg) -{ - apr_finfo_t finfo; - const char *fname; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - fname = ap_server_root_relative(cmd->pool, arg); - if ((apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) - || (finfo.filetype != APR_DIR)) { - return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, - " does not exist or is not a directory", NULL); - } - apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir)); - return NULL; -} - -static const command_rec threaded_cmds[] = { -UNIX_DAEMON_COMMANDS -LISTEN_COMMANDS -AP_INIT_TAKE1("PidFile", set_pidfile, NULL, RSRC_CONF, - "A file for logging the server process ID"), -AP_INIT_TAKE1("ScoreBoardFile", set_scoreboard, NULL, RSRC_CONF, - "A file for Apache to maintain runtime process management information"), -AP_INIT_TAKE1("LockFile", set_lockfile, NULL, RSRC_CONF, - "The lockfile used when Apache needs to lock the accept() call"), -AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, - "Number of child processes launched at server startup"), -AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF, - "Minimum number of idle children, to handle request spikes"), -AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF, - "Maximum number of idle children"), -AP_INIT_TAKE1("MaxClients", set_server_limit, NULL, RSRC_CONF, - "Maximum number of children alive at the same time"), -AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, - "Number of threads each child creates"), -AP_INIT_TAKE1("MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, - "Maximum number of requests a particular child serves before dying."), -AP_INIT_TAKE1("CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, - "The location of the directory Apache changes to before dumping core"), -{ NULL } -}; - -module AP_MODULE_DECLARE_DATA mpm_threaded_module = { - MPM20_MODULE_STUFF, - NULL, /* hook to run before apache parses args */ - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - threaded_cmds, /* command apr_table_t */ - threaded_hooks /* register_hooks */ -}; - diff --git a/server/mpm/winnt/Win9xConHook.c b/server/mpm/winnt/Win9xConHook.c deleted file mode 100644 index a285329b43..0000000000 --- a/server/mpm/winnt/Win9xConHook.c +++ /dev/null @@ -1,739 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifdef WIN32 - -/* - * Win9xConHook.dll - a hook proc to clean up Win95/98 console behavior. - * - * It is well(?) documented by Microsoft that the Win9x HandlerRoutine - * hooked by the SetConsoleCtrlHandler never receives the CTRL_CLOSE_EVENT, - * CTRL_LOGOFF_EVENT or CTRL_SHUTDOWN_EVENT signals. - * - * It is possible to have a second window to monitor the WM_ENDSESSION - * message, but the close button still fails.. - * - * There is a 16bit polling method for the close window option, but this - * is CPU intensive and requires thunking. - * - * Attempts to subclass the 'tty' console fail, since that message thread - * is actually owned by the 16 bit winoldap.mod process, although the - * window reports it is owned by the process/thread of the console app. - * - * Win9xConHook is thunks the WM_CLOSE and WM_ENDSESSION messages, - * first through a window hook procedure in the winoldap context, into - * a subclass WndProc, and on to a second hidden monitor window in the - * console application's context that dispatches them to the console app's - * registered HandlerRoutine. - */ - -/* This debugging define turns on output to COM1, although you better init - * the port first (even using hyperterm). It's the only way to catch the - * goings on within system logoff/shutdown. - * #define DBG 1 - */ - -#include <windows.h> - -/* Variables used within any process context: - * hookwndmsg is a shared message to send Win9xConHook signals - * origwndprop is a wndprop atom to store the orig wndproc of the tty - * hookwndprop is a wndprop atom to store the hwnd of the hidden child - * is_service reminds us to unmark this process on the way out - */ -static UINT hookwndmsg = 0; -static LPCTSTR origwndprop; -static LPCTSTR hookwndprop; -static BOOL is_service = 0; -//static HMODULE hmodThis = NULL; - -/* Variables used within the tty processes' context: - * is_tty flags this process; -1 == unknown, 1 == if tty, 0 == if not - * hw_tty is the handle of the top level tty in this process context - * is_subclassed is toggled to assure DllMain removes the subclass on unload - * hmodLock is there to try and prevent this dll from being unloaded if the - * hook is removed while we are subclassed - */ -static int is_tty = -1; -static HWND hwtty = NULL; -static BOOL is_subclassed = 0; - -// This simply causes a gpfault the moment it tries to FreeLibrary within -// the subclass procedure ... not good. -//static HMODULE hmodLock = NULL; - -/* Variables used within the service or console app's context: - * hmodHook is the instance handle of this module for registering the hooks - * hhkGetMessage is the hook handle for catching Posted messages - * hhkGetMessage is the hook handle for catching Sent messages - * monitor_hwnd is the invisible window that handles our tty messages - * the tty_info strucure is used to pass args into the hidden window's thread - */ -static HMODULE hmodHook = NULL; -static HHOOK hhkGetMessage; -//static HHOOK hhkCallWndProc; -static HWND monitor_hwnd = NULL; - -typedef struct { - PHANDLER_ROUTINE phandler; - HINSTANCE instance; - HWND parent; - INT type; - LPCSTR name; -} tty_info; - -/* These are the GetWindowLong offsets for the hidden window's internal info - * gwltty_phandler is the address of the app's HandlerRoutine - * gwltty_ttywnd is the tty this hidden window will handle messages from - */ -#define gwltty_phandler 0 -#define gwltty_ttywnd 4 - -/* Forward declaration prototypes for internal functions - */ -static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd); -static LRESULT WINAPI RegisterWindows9xService(BOOL set_service); -static LRESULT CALLBACK ttyConsoleCtrlWndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam); -static DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty); -static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam); -static int HookProc(int hc, HWND *hwnd, UINT *msg, - WPARAM *wParam, LPARAM *lParam); -#ifdef DBG -static VOID DbgPrintf(LPTSTR fmt, ...); -#endif - - -/* DllMain is invoked by every process in the entire system that is hooked - * by our window hooks, notably the tty processes' context, and by the user - * who wants tty messages (the app). Keep it light and simple. - */ -BOOL __declspec(dllexport) APIENTRY DllMain(HINSTANCE hModule, ULONG ulReason, - LPVOID pctx) -{ - if (ulReason == DLL_PROCESS_ATTACH) - { - //hmodThis = hModule; - if (!hookwndmsg) { - origwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookOrigProc")); - hookwndprop = MAKEINTATOM(GlobalAddAtom("Win9xConHookThunkWnd")); - hookwndmsg = RegisterWindowMessage("Win9xConHookMsg"); - } -#ifdef DBG -// DbgPrintf("H ProcessAttach:%8.8x\r\n", -// GetCurrentProcessId()); -#endif - } - else if ( ulReason == DLL_PROCESS_DETACH ) - { -#ifdef DBG -// DbgPrintf("H ProcessDetach:%8.8x\r\n", GetCurrentProcessId()); -#endif - if (monitor_hwnd) - SendMessage(monitor_hwnd, WM_DESTROY, 0, 0); - if (is_subclassed) - SendMessage(hwtty, hookwndmsg, 0, (LPARAM)hwtty); - if (hmodHook) - { - if (hhkGetMessage) { - UnhookWindowsHookEx(hhkGetMessage); - hhkGetMessage = NULL; - } - //if (hhkCallWndProc) { - // UnhookWindowsHookEx(hhkCallWndProc); - // hhkCallWndProc = NULL; - //} - FreeLibrary(hmodHook); - hmodHook = NULL; - } - if (is_service) - RegisterWindows9xService(FALSE); - if (hookwndmsg) { - GlobalDeleteAtom((ATOM)origwndprop); - GlobalDeleteAtom((ATOM)hookwndprop); - hookwndmsg = 0; - } - } - return TRUE; -} - - -/* This group of functions are provided for the service/console app - * to register itself a HandlerRoutine to accept tty or service messages - */ - - -/* Exported function that creates a Win9x 'service' via a hidden window, - * that notifies the process via the HandlerRoutine messages. - */ -BOOL __declspec(dllexport) WINAPI Windows9xServiceCtrlHandler( - PHANDLER_ROUTINE phandler, - LPCSTR name) -{ - /* If we have not yet done so */ - FreeConsole(); - - if (name) - { - DWORD tid; - HANDLE hThread; - /* NOTE: this is static so the module can continue to - * access these args while we go on to other things - */ - static tty_info tty; - tty.instance = GetModuleHandle(NULL); - tty.phandler = phandler; - tty.parent = NULL; - tty.name = name; - tty.type = 2; - RegisterWindows9xService(TRUE); - hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread, - (LPVOID)&tty, 0, &tid); - if (hThread) - { - CloseHandle(hThread); - return TRUE; - } - } - else /* remove */ - { - if (monitor_hwnd) - SendMessage(monitor_hwnd, WM_DESTROY, 0, 0); - RegisterWindows9xService(FALSE); - return TRUE; - } - return FALSE; -} - - -/* Exported function that registers a HandlerRoutine to accept missing - * Win9x CTRL_EVENTs from the tty window, as NT does without a hassle. - * If add is 1 or 2, register the handler, if 2 also mark it as a service. - * If add is 0 deregister the handler, and unmark if a service - */ -BOOL __declspec(dllexport) WINAPI FixConsoleCtrlHandler( - PHANDLER_ROUTINE phandler, - INT add) -{ - HWND parent; - - if (add) - { - HANDLE hThread; - DWORD tid; - /* NOTE: this is static so the module can continue to - * access these args while we go on to other things - */ - static tty_info tty; - EnumWindows(EnumttyWindow, (LPARAM)&parent); - if (!parent) { -#ifdef DBG - DbgPrintf("A EnumttyWindow failed (%d)\r\n", GetLastError()); -#endif - return FALSE; - } - tty.instance = GetModuleHandle(NULL); - tty.phandler = phandler; - tty.parent = parent; - tty.type = add; - if (add == 2) { - tty.name = "ttyService"; - RegisterWindows9xService(TRUE); - } - else - tty.name = "ttyMonitor"; - hThread = CreateThread(NULL, 0, ttyConsoleCtrlThread, - (LPVOID)&tty, 0, &tid); - if (!hThread) - return FALSE; - CloseHandle(hThread); - hmodHook = LoadLibrary("Win9xConHook.dll"); - if (hmodHook) - { - hhkGetMessage = SetWindowsHookEx(WH_GETMESSAGE, - (HOOKPROC)GetProcAddress(hmodHook, "GetMsgProc"), hmodHook, 0); - //hhkCallWndProc = SetWindowsHookEx(WH_CALLWNDPROC, - // (HOOKPROC)GetProcAddress(hmodHook, "CallWndProc"), hmodHook, 0); - } - return TRUE; - } - else /* remove */ - { - if (monitor_hwnd) { - SendMessage(monitor_hwnd, WM_DESTROY, 0, 0); - } - if (hmodHook) - { - if (hhkGetMessage) { - UnhookWindowsHookEx(hhkGetMessage); - hhkGetMessage = NULL; - } - //if (hhkCallWndProc) { - // UnhookWindowsHookEx(hhkCallWndProc); - // hhkCallWndProc = NULL; - //} - FreeLibrary(hmodHook); - hmodHook = NULL; - } - if (is_service) - RegisterWindows9xService(FALSE); - return TRUE; - } - return FALSE; -} - - -/* The following internal helpers are only used within the app's context - */ - -/* ttyConsoleCreateThread is the process that runs within the user app's - * context. It creates and pumps the messages of a hidden monitor window, - * watching for messages from the system, or the associated subclassed tty - * window. Things can happen in our context that can't be done from the - * tty's context, and visa versa, so the subclass procedure and this hidden - * window work together to make it all happen. - */ -static DWORD WINAPI ttyConsoleCtrlThread(LPVOID tty) -{ - WNDCLASS wc; - MSG msg; - wc.style = CS_GLOBALCLASS; - wc.lpfnWndProc = ttyConsoleCtrlWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 8; - wc.hInstance = NULL; - wc.hIcon = NULL; - wc.hCursor = NULL; - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - if (((tty_info*)tty)->parent) - wc.lpszClassName = "ttyConHookChild"; - else - wc.lpszClassName = "ApacheWin95ServiceMonitor"; - - if (!RegisterClass(&wc)) { -#ifdef DBG - DbgPrintf("A proc %8.8x Error creating class %s (%d)\r\n", - GetCurrentProcessId(), wc.lpszClassName, GetLastError()); -#endif - return 0; - } - - /* Create an invisible window */ - monitor_hwnd = CreateWindow(wc.lpszClassName, ((tty_info*)tty)->name, - WS_OVERLAPPED & ~WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, - ((tty_info*)tty)->instance, tty); - - if (!monitor_hwnd) { -#ifdef DBG - DbgPrintf("A proc %8.8x Error creating window %s %s (%d)\r\n", - GetCurrentProcessId(), wc.lpszClassName, - ((tty_info*)tty)->name, GetLastError()); -#endif - return 0; - } - - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - /* Tag again as deleted, just in case we missed WM_DESTROY */ - monitor_hwnd = NULL; - return 0; -} - - -/* This is the WndProc procedure for our invisible window. - * When our subclasssed tty window receives the WM_CLOSE, WM_ENDSESSION, - * or WM_QUERYENDSESSION messages, the message is dispatched to our hidden - * window (this message process), and we call the installed HandlerRoutine - * that was registered by the app. - */ -static LRESULT CALLBACK ttyConsoleCtrlWndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_CREATE) - { - tty_info *tty = (tty_info*)(((LPCREATESTRUCT)lParam)->lpCreateParams); - SetWindowLong(hwnd, gwltty_phandler, (LONG)tty->phandler); - SetWindowLong(hwnd, gwltty_ttywnd, (LONG)tty->parent); -#ifdef DBG - DbgPrintf("A proc %8.8x created %8.8x %s for tty wnd %8.8x\r\n", - GetCurrentProcessId(), hwnd, - tty->name, tty->parent); -#endif - if (tty->parent) { - SetProp(tty->parent, hookwndprop, hwnd); - PostMessage(tty->parent, hookwndmsg, - tty->type, (LPARAM)tty->parent); - } - return 0; - } - else if (msg == WM_DESTROY) - { - HWND parent = (HWND)GetWindowLong(hwnd, gwltty_ttywnd); -#ifdef DBG - DbgPrintf("A proc %8.8x destroyed %8.8x ttyConHookChild\r\n", - GetCurrentProcessId(), hwnd); -#endif - if (parent) { - RemoveProp(parent, hookwndprop); - SendMessage(parent, hookwndmsg, 0, (LPARAM)parent); - } - monitor_hwnd = NULL; - } - else if (msg == WM_CLOSE) - { - PHANDLER_ROUTINE phandler = - (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler); - LRESULT rv = phandler(CTRL_CLOSE_EVENT); -#ifdef DBG - DbgPrintf("A proc %8.8x invoked CTRL_CLOSE_EVENT " - "returning %d\r\n", - GetCurrentProcessId(), rv); -#endif - if (rv) - return !rv; - } - else if ((msg == WM_QUERYENDSESSION) || (msg == WM_ENDSESSION)) - { - if (lParam & ENDSESSION_LOGOFF) - { - PHANDLER_ROUTINE phandler = - (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler); - LRESULT rv = phandler(CTRL_LOGOFF_EVENT); -#ifdef DBG - DbgPrintf("A proc %8.8x invoked CTRL_LOGOFF_EVENT " - "returning %d\r\n", - GetCurrentProcessId(), rv); -#endif - if (rv) - return ((msg == WM_QUERYENDSESSION) ? rv : !rv); - } - else - { - PHANDLER_ROUTINE phandler = - (PHANDLER_ROUTINE)GetWindowLong(hwnd, gwltty_phandler); - LRESULT rv = phandler(CTRL_SHUTDOWN_EVENT); -#ifdef DBG - DbgPrintf("A proc %8.8x invoked CTRL_SHUTDOWN_EVENT " - "returning %d\r\n", GetCurrentProcessId(), rv); -#endif - if (rv) - return ((msg == WM_QUERYENDSESSION) ? rv : !rv); - } - } - return (DefWindowProc(hwnd, msg, wParam, lParam)); -} - - -/* The following internal helpers are invoked by the hooked tty and our app - */ - - -/* Register or deregister the current process as a Windows9x style service. - * Experience shows this call is ignored across processes, so the second - * arg to RegisterServiceProcess (process group id) is effectively useless. - */ -static LRESULT WINAPI RegisterWindows9xService(BOOL set_service) -{ - static HINSTANCE hkernel; - static DWORD (WINAPI *register_service_process)(DWORD, DWORD) = NULL; - BOOL rv; - - if (set_service == is_service) - return 1; - -#ifdef DBG - DbgPrintf("R %s proc %8.8x as a service\r\n", - set_service ? "installing" : "removing", - GetCurrentProcessId()); -#endif - - if (!register_service_process) - { - /* Obtain a handle to the kernel library */ - hkernel = LoadLibrary("KERNEL32.DLL"); - if (!hkernel) - return 0; - - /* Find the RegisterServiceProcess function */ - register_service_process = (DWORD (WINAPI *)(DWORD, DWORD)) - GetProcAddress(hkernel, "RegisterServiceProcess"); - if (register_service_process == NULL) { - FreeLibrary(hkernel); - return 0; - } - } - - /* Register this process as a service */ - rv = register_service_process(0, set_service != FALSE); - if (rv) - is_service = set_service; - - if (!is_service) - { - /* Unload the kernel library */ - FreeLibrary(hkernel); - register_service_process = NULL; - } - return rv; -} - - -/* - * This function only works when this process is the active process - * (e.g. once it is running a child process, it can no longer determine - * which console window is its own.) - */ -static BOOL CALLBACK EnumttyWindow(HWND wnd, LPARAM retwnd) -{ - char tmp[8]; - if (GetClassName(wnd, tmp, sizeof(tmp)) && !strcmp(tmp, "tty")) - { - DWORD wndproc, thisproc = GetCurrentProcessId(); - GetWindowThreadProcessId(wnd, &wndproc); - if (wndproc == thisproc) { - *((HWND*)retwnd) = wnd; - return FALSE; - } - } - return TRUE; -} - - -/* The remaining code all executes --in the tty's own process context-- - * - * That means special attention must be paid to what it's doing... - */ - -/* Subclass message process for the tty window - * - * This code -handles- WM_CLOSE, WM_ENDSESSION and WM_QUERYENDSESSION - * by dispatching them to the window identified by the hookwndprop - * property atom set against our window. Messages are then dispatched - * to origwndprop property atom we set against the window when we - * injected this subclass. This trick did not work with simply a hook. - */ -static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ - WNDPROC origproc = (WNDPROC) GetProp(hwnd, origwndprop); - if (!origproc) - return 0; - - if (msg == WM_NCDESTROY - || (msg == hookwndmsg && !LOWORD(wParam) && (HWND)lParam == hwnd)) - { - if (is_subclassed) { -#ifdef DBG - DbgPrintf("W proc %08x hwnd:%08x Subclass removed\r\n", - GetCurrentProcessId(), hwnd); -#endif - if (is_service) - RegisterWindows9xService(FALSE); - SetWindowLong(hwnd, GWL_WNDPROC, (LONG)origproc); - RemoveProp(hwnd, origwndprop); - RemoveProp(hwnd, hookwndprop); - is_subclassed = FALSE; - //if (hmodLock) - // FreeLibrary(hmodLock); - //hmodLock = NULL; - } - } - else if (msg == WM_CLOSE || msg == WM_ENDSESSION - || msg == WM_QUERYENDSESSION) - { - HWND child = (HWND)GetProp(hwnd, hookwndprop); - if (child) { -#ifdef DBG - DbgPrintf("W proc %08x hwnd:%08x forwarded msg:%d\r\n", - GetCurrentProcessId(), hwnd, msg); -#endif - return SendMessage(child, msg, wParam, lParam); - } - } - return CallWindowProc(origproc, hwnd, msg, wParam, lParam); -} - - -/* HookProc, once installed, is responsible for subclassing the system - * tty windows. It generally does nothing special itself, since - * research indicates that it cannot deal well with the messages we are - * interested in, that is, WM_CLOSE, WM_QUERYSHUTDOWN and WM_SHUTDOWN - * of the tty process. - * - * Respond and subclass only when a WM_NULL is received by the window. - */ -int HookProc(int hc, HWND *hwnd, UINT *msg, WPARAM *wParam, LPARAM *lParam) -{ - if (is_tty == -1 && *hwnd) - { - char ttybuf[8]; - HWND htty; - hwtty = *hwnd; - while (htty = GetParent(hwtty)) - hwtty = htty; - is_tty = (GetClassName(hwtty, ttybuf, sizeof(ttybuf)) - && !strcmp(ttybuf, "tty")); -#ifdef DBG - if (is_tty) - DbgPrintf("H proc %08x tracking hwnd %08x\r\n", - GetCurrentProcessId(), hwtty); -#endif - } - - if (*msg == hookwndmsg && *wParam && *lParam == (LPARAM)hwtty && is_tty) - { - WNDPROC origproc = (WNDPROC)GetWindowLong(hwtty, GWL_WNDPROC); - //char myname[MAX_PATH]; - //if (GetModuleFileName(hmodThis, myname, sizeof(myname))) - // hmodLock = LoadLibrary(myname); - SetProp(hwtty, origwndprop, origproc); - SetWindowLong(hwtty, GWL_WNDPROC, (LONG)WndProc); - is_subclassed = TRUE; -#ifdef DBG - DbgPrintf("H proc %08x hwnd:%08x Subclassed\r\n", - GetCurrentProcessId(), hwtty); -#endif - if (LOWORD(*wParam) == 2) - RegisterWindows9xService(TRUE); - } - - return -1; -} - - -/* - * PostMessage Hook: - */ -LRESULT __declspec(dllexport) CALLBACK GetMsgProc(INT hc, WPARAM wParam, - LPARAM lParam) -{ - PMSG pmsg; - - pmsg = (PMSG)lParam; - - if (pmsg) { - int rv = HookProc(hc, &pmsg->hwnd, &pmsg->message, - &pmsg->wParam, &pmsg->lParam); - if (rv != -1) - return rv; - } - /* - * CallNextHookEx apparently ignores the hhook argument, so pass NULL - */ - return CallNextHookEx(NULL, hc, wParam, lParam); -} - - -/* - * SendMessage Hook: - */ -LRESULT __declspec(dllexport) CALLBACK CallWndProc(INT hc, WPARAM wParam, - LPARAM lParam) -{ - PCWPSTRUCT pcwps = (PCWPSTRUCT)lParam; - - if (pcwps) { - int rv = HookProc(hc, &pcwps->hwnd, &pcwps->message, - &pcwps->wParam, &pcwps->lParam); - if (rv != -1) - return rv; - } - /* - * CallNextHookEx apparently ignores the hhook argument, so pass NULL - */ - return CallNextHookEx(NULL, hc, wParam, lParam); -} - - -#ifdef DBG -VOID DbgPrintf( - LPTSTR fmt, - ... - ) -{ - static HANDLE mutex; - va_list marker; - TCHAR szBuf[256]; - DWORD t; - HANDLE gDbgOut; - - va_start(marker, fmt); - wvsprintf(szBuf, fmt, marker); - va_end(marker); - - if (!mutex) - mutex = CreateMutex(NULL, FALSE, "Win9xConHookDbgOut"); - WaitForSingleObject(mutex, INFINITE); - gDbgOut = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL); - WriteFile(gDbgOut, szBuf, strlen(szBuf), &t, NULL); - CloseHandle(gDbgOut); - ReleaseMutex(mutex); -} -#endif - -#endif /* WIN32 */ diff --git a/server/mpm/winnt/Win9xConHook.def b/server/mpm/winnt/Win9xConHook.def deleted file mode 100644 index 85ec166404..0000000000 --- a/server/mpm/winnt/Win9xConHook.def +++ /dev/null @@ -1,10 +0,0 @@ -LIBRARY Win9xConHook - -EXETYPE WINDOWS - -EXPORTS - DllMain - GetMsgProc - CallWndProc - FixConsoleCtrlHandler - Windows9xServiceCtrlHandler diff --git a/server/mpm/winnt/Win9xConHook.dsp b/server/mpm/winnt/Win9xConHook.dsp deleted file mode 100644 index 56ad1180a9..0000000000 --- a/server/mpm/winnt/Win9xConHook.dsp +++ /dev/null @@ -1,103 +0,0 @@ -# Microsoft Developer Studio Project File - Name="Win9xConHook" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=Win9xConHook - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Win9xConHook.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Win9xConHook.mak" CFG="Win9xConHook - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Win9xConHook - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "Win9xConHook - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Win9xConHook - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir ".\Release" -# PROP BASE Intermediate_Dir ".\Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MD /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "SHARED_MODULE" /Fd"Release\Win9xConHook" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "NDEBUG" -# ADD RSC /l 0x809 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /map /machine:I386 /base:"0x1c0f0000" -# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /map /machine:I386 /base:"0x1c0f0000" - -!ELSEIF "$(CFG)" == "Win9xConHook - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MDd /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c -# ADD CPP /nologo /MDd /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "SHARED_MODULE" /Fd"Debug\Win9xConHook" /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x809 /d "_DEBUG" -# ADD RSC /l 0x809 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /base:"0x1c0f0000" -# ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386 /base:"0x1c0f0000" - -!ENDIF - -# Begin Target - -# Name "Win9xConHook - Win32 Release" -# Name "Win9xConHook - Win32 Debug" -# Begin Source File - -SOURCE=.\Win9xConHook.c -# End Source File -# Begin Source File - -SOURCE=.\Win9xConHook.def -# End Source File -# Begin Source File - -SOURCE=.\Win9xConHook.h -# End Source File -# End Target -# End Project diff --git a/server/mpm/winnt/Win9xConHook.h b/server/mpm/winnt/Win9xConHook.h deleted file mode 100644 index 312e82cd2d..0000000000 --- a/server/mpm/winnt/Win9xConHook.h +++ /dev/null @@ -1,99 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef AP_WIN9XCONHOOK_H -#define AP_WIN9XCONHOOK_H - -#ifdef WIN32 - -/* Windows9xServiceCtrlHandler registers a handler routine, frees the - * console window, and registers this process as a service in Win9x. - * It creats a hidden window of class "ApacheWin95ServiceMonitor" - * and titled by the name passed, which passes the WM_SHUTDOWN message - * through the given HandlerRoutine's CTRL_SHUTDOWN event. - * Call with name of NULL to remove the Service handler. - */ -BOOL WINAPI Windows9xServiceCtrlHandler(PHANDLER_ROUTINE phandler, LPCSTR name); - - -/* FixConsoleControlHandler registers a handler routine with the - * Win9xConHook.dll, creating a hidden window and forwarding the - * WM_ENDSESSION and WM_CLOSE messages to the given HandlerRoutine - * as CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT and CTRL_CLOSE_EVENT. - * The application should still use SetConsoleCtrlHandler to grab - * the CTRL_BREAK_EVENT and CTRL_C_EVENT, if desired. - */ -BOOL WINAPI FixConsoleCtrlHandler(PHANDLER_ROUTINE phandler, BOOL add); - - -/* - * Exported PostMessage Hook, never use this directly: - * - * LRESULT CALLBACK GetMsgProc(INT hc, WPARAM wParam, LPARAM lParam); - */ - - -/* - * Exported SendMessage Hook, never use this directly: - * - * LRESULT CALLBACK CallWndProc(INT hc, WPARAM wParam, LPARAM lParam); - */ - -#endif /* WIN32 */ - -#endif AP_WIN9XCONHOOK_H
\ No newline at end of file diff --git a/server/mpm/winnt/mpm.h b/server/mpm/winnt/mpm.h deleted file mode 100644 index 4c17b8a55f..0000000000 --- a/server/mpm/winnt/mpm.h +++ /dev/null @@ -1,71 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_H -#define APACHE_MPM_H - -/* mpm.h is the place to make declarations that are MPM specific but that must be - * shared with non-mpm specific code in the server. Hummm, perhaps we can - * move most of this stuff to mpm_common.h? - */ - -#define MPM_NAME "WinNT" - -extern int ap_threads_per_child; - -#endif /* APACHE_MPM_H */ diff --git a/server/mpm/winnt/mpm_default.h b/server/mpm/winnt/mpm_default.h deleted file mode 100644 index 876503a47d..0000000000 --- a/server/mpm/winnt/mpm_default.h +++ /dev/null @@ -1,135 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_DEFAULT_H -#define APACHE_MPM_DEFAULT_H - -/* AP_CHILD_THREAD_FROM_ID is used by the scoreboard. */ -#define AP_CHILD_THREAD_FROM_ID(i) 0, i - -/* Number of threads to spawn off by default --- also, if fewer than - * this free when the caretaker checks, it will spawn more. - */ -#ifndef DEFAULT_START_THREAD -#define DEFAULT_START_THREAD 5 -#endif - -/* Maximum number of *free* server threads --- more than this, and - * they will die off. -#ifndef DEFAULT_MAX_SPARE_THREAD -#define DEFAULT_MAX_SPARE_THREAD 10 -#endif -*/ - -/* Minimum --- fewer than this, and more will be created */ -/* -#ifndef DEFAULT_MIN_SPARE_THREAD -#define DEFAULT_MIN_SPARE_THREAD 5 -#endif -*/ - -/* Limit on the threads per process. Clients will be locked out if more than - * this * HARD_SERVER_LIMIT are needed. - * - * We keep this for one reason 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_THREAD_LIMIT -#define HARD_THREAD_LIMIT 4096 -#endif - -/* Number of servers to spawn off by default - */ -#ifndef DEFAULT_NUM_DAEMON -#define DEFAULT_NUM_DAEMON 1 -#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. - */ -#define HARD_SERVER_LIMIT 1 - -/* Where the main/parent process's pid is logged */ -#ifndef DEFAULT_PIDLOG -#define DEFAULT_PIDLOG "logs/httpd.pid" -#endif - -/* - * Interval, in microseconds, between scoreboard maintenance. - */ -#ifndef SCOREBOARD_MAINTENANCE_INTERVAL -#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 -#endif - -/* Number of requests to try to handle in a single process. If <= 0, - * the children don't die off. - */ -#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD -#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 -#endif - -#endif /* AP_MPM_DEFAULT_H */ diff --git a/server/mpm/winnt/mpm_winnt.c b/server/mpm/winnt/mpm_winnt.c deleted file mode 100644 index 921e362ddd..0000000000 --- a/server/mpm/winnt/mpm_winnt.c +++ /dev/null @@ -1,2114 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#define CORE_PRIVATE -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_config.h" /* for read_config */ -#include "http_core.h" /* for get_remote_host */ -#include "http_connection.h" -#include "apr_portable.h" -#include "apr_getopt.h" -#include "apr_strings.h" -#include "apr_lib.h" -#include "ap_mpm.h" -#include "ap_config.h" -#include "ap_listen.h" -#include "mpm_default.h" -#include "mpm_winnt.h" -#include "mpm_common.h" -#include "scoreboard.h" - - -typedef HANDLE thread; -#ifdef CONTAINING_RECORD -#undef CONTAINING_RECORD -#endif -#define CONTAINING_RECORD(address, type, field) ((type *)( \ - (PCHAR)(address) - \ - (PCHAR)(&((type *)0)->field))) -#define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN)+16 - -typedef struct CompContext { - struct CompContext *next; - OVERLAPPED Overlapped; - apr_socket_t *sock; - SOCKET accept_socket; - char buff[2*PADDED_ADDR_SIZE]; - struct sockaddr *sa_server; - int sa_server_len; - struct sockaddr *sa_client; - int sa_client_len; - apr_pool_t *ptrans; -} COMP_CONTEXT, *PCOMP_CONTEXT; - -typedef enum { - IOCP_CONNECTION_ACCEPTED = 1, - IOCP_WAIT_FOR_RECEIVE = 2, - IOCP_WAIT_FOR_TRANSMITFILE = 3, - IOCP_SHUTDOWN = 4 -} io_state_e; - -/* Queue for managing the passing of COMP_CONTEXTs from - * the accept thread to the worker threads and back again - */ -apr_lock_t *qlock; -COMP_CONTEXT *qhead = NULL; -COMP_CONTEXT *qtail = NULL; - -static HANDLE ThreadDispatchIOCP = NULL; - -/* Definitions of WINNT MPM specific config globals */ -static server_rec *server_conf; -static apr_pool_t *pconf; -static apr_pool_t *pchild = NULL; -static int workers_may_exit = 0; -static int shutdown_in_progress = 0; -static unsigned int g_blocked_threads = 0; -static int ap_max_requests_per_child=0; - -static char *ap_pid_fname = NULL; - -static HANDLE shutdown_event; /* used to signal the parent to shutdown */ -static HANDLE restart_event; /* used to signal the parent to restart */ -static HANDLE exit_event; /* used by parent to signal the child to exit */ -static HANDLE maintenance_event; - -static char ap_coredump_dir[MAX_STRING_LEN]; - -static int one_process = 0; -static char const* signal_arg; - -OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */ - -apr_lock_t *start_mutex; -static DWORD my_pid; -static DWORD parent_pid; - -int ap_threads_per_child = 0; -int ap_daemons_to_start=0; - -/* ap_get_max_daemons and ap_my_generation are used by the scoreboard - * code - */ -ap_generation_t volatile ap_my_generation=0; /* Used by the scoreboard */ - -/* This is the helper code to resolve late bound entry points - * missing from one or more releases of the Win32 API... - * but it sure would be nice if we didn't duplicate this code - * from the APR ;-) - */ -static const char* const lateDllName[DLL_defined] = { - "kernel32", "advapi32", "mswsock", "ws2_32" }; -static HMODULE lateDllHandle[DLL_defined] = { - NULL, NULL, NULL, NULL }; - -FARPROC ap_load_dll_func(ap_dlltoken_e fnLib, char* fnName, int ordinal) -{ - if (!lateDllHandle[fnLib]) { - lateDllHandle[fnLib] = LoadLibrary(lateDllName[fnLib]); - if (!lateDllHandle[fnLib]) - return NULL; - } - if (ordinal) - return GetProcAddress(lateDllHandle[fnLib], (char *) ordinal); - else - return GetProcAddress(lateDllHandle[fnLib], fnName); -} - -/* 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; - } - apr_set_os_error(0); - if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION) - || apr_get_os_error()) { - LocalFree( pSD ); - LocalFree( sa ); - return NULL; - } - if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE) - || apr_get_os_error()) { - 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 ); - } -} - -/* - * 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; -} - -/* - * 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. - */ -/* - * Initialise the signal names, in the global variables signal_name_prefix, - * signal_restart_name and signal_shutdown_name. - */ -#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]; -void setup_signal_names(char *prefix) -{ - apr_snprintf(signal_name_prefix, sizeof(signal_name_prefix), prefix); - apr_snprintf(signal_shutdown_name, sizeof(signal_shutdown_name), - "%s_shutdown", signal_name_prefix); - apr_snprintf(signal_restart_name, sizeof(signal_restart_name), - "%s_restart", signal_name_prefix); -} - -void signal_parent(int type) -{ - HANDLE e; - char *signal_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; - } - 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, apr_get_os_error(), server_conf, - "OpenEvent on %s event", signal_name); - return; - } - if (SetEvent(e) == 0) { - /* Same problem as above */ - ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), server_conf, - "SetEvent on %s event", signal_name); - CloseHandle(e); - return; - } - CloseHandle(e); -} - -static int volatile is_graceful = 0; - -AP_DECLARE(int) ap_graceful_stop_signalled(void) -{ - return is_graceful; -} - -AP_DECLARE(void) ap_start_shutdown(void) -{ - signal_parent(0); -} - -AP_DECLARE(void) ap_start_restart(int gracefully) -{ - is_graceful = gracefully; - signal_parent(1); -} - - -/* - * find_ready_listener() - * Only used by Win9* and should go away when the win9*_accept() function is - * reimplemented using apr_poll(). - */ -static ap_listen_rec *head_listener; -static APR_INLINE ap_listen_rec *find_ready_listener(fd_set * main_fds) -{ - ap_listen_rec *lr; - SOCKET nsd; - - for (lr = head_listener; lr ; lr = lr->next) { - apr_os_sock_get(&nsd, lr->sd); - if (FD_ISSET(nsd, main_fds)) { - head_listener = lr->next; - if (head_listener == NULL) - head_listener = ap_listeners; - - return (lr); - } - } - return NULL; -} - -/* - * get_listeners_from_parent() - * The listen sockets are opened in the parent. This function, which runs - * exclusively in the child process, receives them from the parent and - * makes them availeble in the child. - */ -static int get_listeners_from_parent(server_rec *s) -{ - WSAPROTOCOL_INFO WSAProtocolInfo; - HANDLE pipe; - ap_listen_rec *lr; - DWORD BytesRead; - int num_listeners = 0; - SOCKET nsd; - - /* Set up a default listener if necessary */ - if (ap_listeners == NULL) { - ap_listen_rec *lr; - lr = apr_palloc(s->process->pool, sizeof(ap_listen_rec)); - if (!lr) - return 0; - lr->sd = NULL; - lr->next = ap_listeners; - ap_listeners = lr; - } - - /* 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); - for (lr = ap_listeners; lr; lr = lr->next) { - if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO), - &BytesRead, (LPOVERLAPPED) NULL)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, - "setup_inherited_listeners: Unable to read socket data from parent"); - signal_parent(0); /* tell parent to die */ - exit(1); - } - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: setup_inherited_listener() read = %d bytes of WSAProtocolInfo.", my_pid); - nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, - &WSAProtocolInfo, 0, 0); - if (nsd == INVALID_SOCKET) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), server_conf, - "Child %d: setup_inherited_listeners(), WSASocket failed to open the inherited socket.", my_pid); - signal_parent(0); /* tell parent to die */ - exit(1); - } - apr_os_sock_put(&lr->sd, &nsd, pconf); - num_listeners++; - } - - CloseHandle(pipe); - - return num_listeners; -} - - -/* Windows 9x specific code... - * Accept processing for on Windows 95/98 uses a producer/consumer queue - * model. A single thread accepts connections and queues the accepted socket - * to the accept queue for consumption by a pool of worker threads. - * - * win9x_accept() - * The accept threads runs this function, which accepts connections off - * the network and calls add_job() to queue jobs to the accept_queue. - * 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. - * win9x_get_connection() - * Calls remove_job() to pull a job from the accept queue. All the worker - * threads block on remove_job. - */ - -typedef struct joblist_s { - struct joblist_s *next; - int sock; -} joblist; - -typedef struct globals_s { - HANDLE jobsemaphore; - joblist *jobhead; - joblist *jobtail; - apr_lock_t *jobmutex; - int jobcount; -} globals; - -globals allowed_globals = {NULL, NULL, NULL, NULL, 0}; -#define MAX_SELECT_ERRORS 100 - -static void add_job(int sock) -{ - joblist *new_job; - - new_job = (joblist *) malloc(sizeof(joblist)); - if (new_job == NULL) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "Ouch! Out of memory in add_job()!"); - return; - } - new_job->next = NULL; - new_job->sock = sock; - - apr_lock_acquire(allowed_globals.jobmutex); - - 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++; - ReleaseSemaphore(allowed_globals.jobsemaphore, 1, NULL); - - apr_lock_release(allowed_globals.jobmutex); -} - -static int remove_job(void) -{ - joblist *job; - int sock; - - WaitForSingleObject(allowed_globals.jobsemaphore, INFINITE); - apr_lock_acquire(allowed_globals.jobmutex); - - if (shutdown_in_progress && !allowed_globals.jobhead) { - apr_lock_release(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; - apr_lock_release(allowed_globals.jobmutex); - sock = job->sock; - free(job); - - return (sock); -} - -static void win9x_accept(void * dummy) -{ - int requests_this_child = 0; - struct timeval tv; - fd_set main_fds; - int wait_time = 1; - int csd; - SOCKET nsd = INVALID_SOCKET; - struct sockaddr_in sa_client; - int count_select_errors = 0; - int rc; - int clen; - ap_listen_rec *lr; - struct fd_set listenfds; - SOCKET listenmaxfd = INVALID_SOCKET; - - /* Setup the listeners - * ToDo: Use apr_poll() - */ - FD_ZERO(&listenfds); - for (lr = ap_listeners; lr; lr = lr->next) { - if (lr->sd != NULL) { - apr_os_sock_get(&nsd, lr->sd); - FD_SET(nsd, &listenfds); - if (listenmaxfd == INVALID_SOCKET || nsd > listenmaxfd) { - listenmaxfd = nsd; - } - } - } - head_listener = ap_listeners; - - while (!shutdown_in_progress) { - if (ap_max_requests_per_child && (requests_this_child > ap_max_requests_per_child)) { - break; - } - - tv.tv_sec = wait_time; - tv.tv_usec = 0; - memcpy(&main_fds, &listenfds, sizeof(fd_set)); - - rc = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv); - - if (rc == 0 || (rc == SOCKET_ERROR && APR_STATUS_IS_EINTR(apr_get_netos_error()))) { - count_select_errors = 0; /* reset count of errors */ - continue; - } - else if (rc == SOCKET_ERROR) { - /* 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_INFO, apr_get_netos_error(), server_conf, - "select failed with error %d", apr_get_netos_error()); - count_select_errors++; - if (count_select_errors > MAX_SELECT_ERRORS) { - shutdown_in_progress = 1; - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), server_conf, - "Too many errors in select loop. Child process exiting."); - break; - } - } else { - ap_listen_rec *lr; - - lr = find_ready_listener(&main_fds); - if (lr != NULL) { - /* fetch the native socket descriptor */ - apr_os_sock_get(&nsd, lr->sd); - } - } - - do { - clen = sizeof(sa_client); - csd = accept(nsd, (struct sockaddr *) &sa_client, &clen); - if (csd == INVALID_SOCKET) { - csd = -1; - } - } while (csd < 0 && APR_STATUS_IS_EINTR(apr_get_netos_error())); - - if (csd < 0) { - if (APR_STATUS_IS_ECONNABORTED(apr_get_netos_error())) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), server_conf, - "accept: (client socket)"); - } - } - else { - add_job(csd); - requests_this_child++; - } - } - SetEvent(exit_event); -} - -static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context) -{ - int len; - - if (context == NULL) { - /* allocate the completion context and the transaction pool */ - context = apr_pcalloc(pconf, sizeof(COMP_CONTEXT)); - if (!context) { - ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_os_error(), server_conf, - "win9x_get_connection: apr_pcalloc() failed. Process will exit."); - return NULL; - } - apr_pool_create(&context->ptrans, pconf); - } - - - while (1) { - apr_pool_clear(context->ptrans); - context->accept_socket = remove_job(); - if (context->accept_socket == -1) { - return NULL; - } - len = sizeof(struct sockaddr); - context->sa_server = apr_palloc(context->ptrans, len); - if (getsockname(context->accept_socket, - context->sa_server, &len)== SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), server_conf, - "getsockname failed"); - continue; - } - len = sizeof(struct sockaddr); - context->sa_client = apr_palloc(context->ptrans, len); - if ((getpeername(context->accept_socket, - context->sa_client, &len)) == SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), server_conf, - "getpeername failed"); - memset(&context->sa_client, '\0', sizeof(context->sa_client)); - } - - /* do we NEED_DUPPED_CSD ?? */ - - return context; - } -} -/* Windows NT/2000 specific code... - * Accept processing for on Windows NT uses a producer/consumer queue - * model. An accept thread accepts connections off the network then issues - * PostQueuedCompletionStatus() to awake a thread blocked on the ThreadDispatch - * IOCompletionPort. - * - * winnt_accept() - * One or more accept threads run in this function, each of which accepts - * connections off the network and calls PostQueuedCompletionStatus() to - * queue an io completion packet to the ThreadDispatch IOCompletionPort. - * winnt_get_connection() - * Worker threads block on the ThreadDispatch IOCompletionPort awaiting - * connections to service. - */ -static void winnt_accept(void *listen_socket) -{ - static int num_completion_contexts = 0; - static int requests_this_child = 0; - PCOMP_CONTEXT pCompContext; - DWORD BytesRead; - SOCKET nlsd; - int lasterror; - - nlsd = (SOCKET) listen_socket; - - while (!shutdown_in_progress) { - if (ap_max_requests_per_child && (requests_this_child > ap_max_requests_per_child)) { - break; - } - pCompContext = NULL; - /* Grab a context off the queue */ - apr_lock_acquire(qlock); - if (qhead) { - pCompContext = qhead; - qhead = qhead->next; - if (!qhead) - qtail = NULL; - } - apr_lock_release(qlock); - - /* If we failed to grab a context off the queue, alloc one out of - * the child pool. There may be up to ap_threads_per_child contexts - * in the system at once. - */ - if (!pCompContext) { - if (num_completion_contexts >= ap_threads_per_child) { - static int reported = 0; - if (!reported) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, server_conf, - "Server ran out of threads to serve requests. Consider " - "raising the ThreadsPerChild setting"); - reported = 1; - } - Sleep(500); - continue; - } - pCompContext = (PCOMP_CONTEXT) apr_pcalloc(pchild, sizeof(COMP_CONTEXT)); - - pCompContext->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (pCompContext->Overlapped.hEvent == NULL) { - ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_os_error(), server_conf, - "winnt_accept: CreateEvent failed. Process will exit."); - // return -1; - } - pCompContext->accept_socket = INVALID_SOCKET; - num_completion_contexts++; - } - - again: - /* Create and initialize the accept socket */ - if (pCompContext->accept_socket == INVALID_SOCKET) { - pCompContext->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - - if (pCompContext->accept_socket == INVALID_SOCKET) { - ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_netos_error(), server_conf, - "winnt_accept: socket() failed. Process will exit."); - // return -1; - } - - /* SO_UPDATE_ACCEPT_CONTEXT is required for shutdown() to work */ - if (setsockopt(pCompContext->accept_socket, SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, (char *)&nlsd, - sizeof(nlsd))) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), server_conf, - "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed."); - /* Not a failure condition. Keep running. */ - } - } - - /* AcceptEx on the completion context. The completion context will be - * signaled when a connection is accepted. - */ - if (!AcceptEx(nlsd, pCompContext->accept_socket, - pCompContext->buff, - 0, - PADDED_ADDR_SIZE, - PADDED_ADDR_SIZE, - &BytesRead, - &pCompContext->Overlapped)) { - lasterror = apr_get_netos_error(); - if (lasterror == APR_FROM_OS_ERROR(WSAEINVAL)) { - /* Hack alert. Occasionally, TransmitFile will not recycle the - * accept socket (usually when the client disconnects early). - * Get a new socket and try the call again. - */ - pCompContext->accept_socket = INVALID_SOCKET; - ap_log_error(APLOG_MARK, APLOG_DEBUG, lasterror, server_conf, - "winnt_accept: AcceptEx failed. Reallocate the accept socket and try again."); - if (shutdown_in_progress) - break; - else - goto again; - } - else if (lasterror != APR_FROM_OS_ERROR(ERROR_IO_PENDING)) { - ap_log_error(APLOG_MARK,APLOG_ERR, lasterror, server_conf, - "winnt_accept: AcceptEx failed. Process will exit."); - // return -1; - } - - /* Wait for pending i/o */ - WaitForSingleObject(pCompContext->Overlapped.hEvent, INFINITE); - } - - /* When a connection is received, send an io completion notification to - * the ThreadDispatchIOCP - */ - PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_CONNECTION_ACCEPTED, - &pCompContext->Overlapped); - requests_this_child++; - } - - if (!shutdown_in_progress) { - /* Yow, hit an irrecoverable error! Tell the child to die. */ - SetEvent(exit_event); - } -} -static PCOMP_CONTEXT winnt_get_connection(PCOMP_CONTEXT pCompContext) -{ - int requests_this_child = 0; - int rc; - DWORD BytesRead; - DWORD CompKey; - LPOVERLAPPED pol; - - /* Recycle the completion context. - * - destroy the ptrans pool - * - put the context on the queue to be consumed by the accept thread - * Note: pCompContext->accept_socket may be in a disconnected - * but reusable state so -don't- close it. - */ - if (pCompContext) { - apr_pool_clear(pCompContext->ptrans); - apr_pool_destroy(pCompContext->ptrans); - pCompContext->ptrans = NULL; - pCompContext->next = NULL; - apr_lock_acquire(qlock); - if (qtail) - qtail->next = pCompContext; - else - qhead = pCompContext; - qtail = pCompContext; - apr_lock_release(qlock); - } - - g_blocked_threads++; - while (1) { - if (workers_may_exit) { - g_blocked_threads--; - return NULL; - } - rc = GetQueuedCompletionStatus(ThreadDispatchIOCP, &BytesRead, &CompKey, - &pol, INFINITE); - if (!rc) { - rc = apr_get_os_error(); - ap_log_error(APLOG_MARK,APLOG_DEBUG, rc, server_conf, - "Child %d: GetQueuedComplationStatus returned %d", my_pid, rc); - continue; - } - - switch (CompKey) { - case IOCP_CONNECTION_ACCEPTED: - pCompContext = CONTAINING_RECORD(pol, COMP_CONTEXT, Overlapped); - break; - case IOCP_SHUTDOWN: - g_blocked_threads--; - return NULL; - default: - g_blocked_threads--; - return NULL; - } - break; - } - - g_blocked_threads--; - - if ((rc = apr_pool_create(&pCompContext->ptrans, NULL)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_DEBUG, rc, server_conf, - "Child %d: apr_pool_create failed with rc %d", my_pid, rc); - } - - /* Get the local & remote address */ - GetAcceptExSockaddrs(pCompContext->buff, - 0, - PADDED_ADDR_SIZE, - PADDED_ADDR_SIZE, - &pCompContext->sa_server, - &pCompContext->sa_server_len, - &pCompContext->sa_client, - &pCompContext->sa_client_len); - - return pCompContext; - -} - -/* - * worker_main() - * Main entry point for the worker threads. Worker threads block in - * win*_get_connection() awaiting a connection to service. - */ -static void worker_main(int thread_num) -{ - PCOMP_CONTEXT context = NULL; - apr_os_sock_info_t sockinfo; - - while (1) { - conn_rec *c; - apr_int32_t disconnected; - - ap_update_child_status(0, thread_num, SERVER_READY, - (request_rec *) NULL); - - /* Grab a connection off the network */ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - context = win9x_get_connection(context); - } - else { - context = winnt_get_connection(context); - } - - if (!context) - break; - - sockinfo.os_sock = &context->accept_socket; - sockinfo.local = context->sa_server; - sockinfo.remote = context->sa_client; - sockinfo.family = APR_INET; - sockinfo.type = SOCK_STREAM; - apr_os_sock_make(&context->sock, &sockinfo, context->ptrans); - - c = ap_new_connection(context->ptrans, server_conf, context->sock, - thread_num); - - if (c) { - ap_process_connection(c); - apr_getsocketopt(context->sock, APR_SO_DISCONNECTED, &disconnected); - if (!disconnected) { - context->accept_socket = INVALID_SOCKET; - ap_lingering_close(c); - } - } - else { - /* ap_new_connection closes the socket on failure */ - context->accept_socket = INVALID_SOCKET; - } - } - - ap_update_child_status(0, thread_num, SERVER_DEAD, (request_rec *) NULL); - - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: Thread exiting.", my_pid); -} - -static void cleanup_thread(thread *handles, int *thread_cnt, int thread_to_clean) -{ - int i; - - CloseHandle(handles[thread_to_clean]); - for (i = thread_to_clean; i < ((*thread_cnt) - 1); i++) - handles[i] = handles[i + 1]; - (*thread_cnt)--; -} - -/* - * child_main() - * Entry point for the main control thread for the child process. - * This thread creates the accept thread, worker threads and - * monitors the child process for maintenance and shutdown - * events. - */ -static void child_main() -{ - apr_status_t status; - HANDLE child_events[2]; - char* exit_event_name; - int nthreads = ap_threads_per_child; - int tid; - thread *child_handles; - int rv; - time_t end_time; - int i; - int cld; - - /* This is the child process or we are running in single process mode. */ - exit_event_name = apr_psprintf(pconf, "apC%d", my_pid); - setup_signal_names(apr_psprintf(pconf,"ap%d", parent_pid)); - - if (one_process) { - /* Single process mode */ - apr_lock_create(&start_mutex, APR_MUTEX, APR_CROSS_PROCESS, - signal_name_prefix, pconf); - exit_event = CreateEvent(NULL, TRUE, FALSE, exit_event_name); - } - else { - /* Child process mode */ - apr_lock_child_init(&start_mutex, signal_name_prefix, pconf); - exit_event = OpenEvent(EVENT_ALL_ACCESS, FALSE, exit_event_name); - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: exit_event_name = %s", my_pid, exit_event_name); - } - - /* Initialize the child_events */ - maintenance_event = CreateEvent(NULL, TRUE, FALSE, NULL); - child_events[0] = exit_event; - child_events[1] = maintenance_event; - - ap_assert(start_mutex); - ap_assert(exit_event); - ap_assert(maintenance_event); - - apr_pool_create(&pchild, pconf); - allowed_globals.jobsemaphore = CreateSemaphore(NULL, 0, 1000000, NULL); - apr_lock_create(&allowed_globals.jobmutex, APR_MUTEX, APR_INTRAPROCESS, NULL, pchild); - - /* - * 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. - */ - status = apr_lock_acquire(start_mutex); - if (status != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_ERR, status, server_conf, - "Child %d: Failed to acquire the start_mutex. Process will exit.", my_pid); - signal_parent(0); /* tell parent to die */ - exit(0); - } - ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: Acquired the start mutex.", my_pid); - - /* - * Create the worker thread dispatch IOCompletionPort - * on Windows NT/2000 - */ - if (osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) { - /* Create the worker thread dispatch IOCP */ - ThreadDispatchIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, - NULL, - 0, - 0); /* CONCURRENT ACTIVE THREADS */ - apr_lock_create(&qlock, APR_MUTEX, APR_INTRAPROCESS, NULL, pchild); - } - - /* - * Create the pool of worker threads - */ - ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: Starting %d worker threads.", my_pid, nthreads); - child_handles = (thread) alloca(nthreads * sizeof(int)); - for (i = 0; i < nthreads; i++) { - ap_update_child_status(0, i, SERVER_STARTING, (request_rec *) NULL); - child_handles[i] = (thread) _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE) worker_main, - (void *) i, 0, &tid); - } - - /* - * Start the accept thread - */ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - _beginthreadex(NULL, 0, (LPTHREAD_START_ROUTINE) win9x_accept, - (void *) i, 0, &tid); - } else { - /* Start an accept thread per listener */ - SOCKET nlsd; /* native listening sock descriptor */ - ap_listen_rec *lr; - for (lr = ap_listeners; lr; lr = lr->next) { - if (lr->sd != NULL) { - apr_os_sock_get(&nlsd, lr->sd); - _beginthreadex(NULL, 1000, (LPTHREAD_START_ROUTINE) winnt_accept, - (void *) nlsd, 0, &tid); - } - } - } - - /* Wait for one of three events: - * exit_event: - * The exit_event is signaled by the parent process to notify - * the child that it is time to exit. - * - * maintenance_event: - * This event is signaled by the worker thread pool to direct - * this thread to create more completion contexts. - * - * TIMEOUT: - * To do periodic maintenance on the server (check for thread exits, - * number of completion contexts, etc.) - */ - while (1) { - rv = WaitForMultipleObjects(2, (HANDLE *) child_events, FALSE, INFINITE); - cld = rv - WAIT_OBJECT_0; - if (rv == WAIT_FAILED) { - /* Something serious is wrong */ - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, - "Child %d: WAIT_FAILED -- shutting down server"); - break; - } - else if (rv == WAIT_TIMEOUT) { - /* Hey, this cannot happen */ - ap_log_error(APLOG_MARK, APLOG_CRIT, APR_SUCCESS, server_conf, - "Child %d: WAIT_TIMEOUT -- shutting down server", my_pid); - break; - } - else if (cld == 0) { - /* Exit event was signaled */ - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: Exit event signaled. Child process is ending.", my_pid); - break; - } - else { - /* Child maintenance event signaled */ - ResetEvent(maintenance_event); - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: Child maintenance event signaled.", my_pid); - } - } - - /* Setting is_graceful will cause keep-alive connections to be closed - * rather than block on the next network read. - */ - is_graceful = 1; - - /* Setting shutdown_in_progress prevents new connections from - * being accepted but allows the worker threads to continue - * handling connections that have already been accepted. - */ - shutdown_in_progress = 1; - - /* Close the listening sockets */ - { - ap_listen_rec *lr; - for (lr = ap_listeners; lr ; lr = lr->next) { - apr_socket_close(lr->sd); - } - } - - /* Give the worker threads time to handle already accepted connections */ - Sleep(1000); - - /* Release the start_mutex to let the new process (in the restart - * scenario) a chance to begin accepting and servicing requests - */ - ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: Releasing the start mutex", my_pid); - apr_lock_release(start_mutex); - - /* Tell the worker threads they may exit when done handling - * a connection. - */ - workers_may_exit = 1; - - /* Shutdown the worker threads */ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - for (i = 0; i < nthreads; i++) { - add_job(-1); - } - } - else { /* Windows NT/2000 */ - /* Post worker threads blocked on the ThreadDispatch IOCompletion port */ - while (g_blocked_threads > 0) { - ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: %d threads blocked on the completion port", my_pid, g_blocked_threads); - for (i=g_blocked_threads; i > 0; i--) { - PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_SHUTDOWN, NULL); - } - Sleep(1000); - } - /* Empty the accept queue of completion contexts */ - apr_lock_acquire(qlock); - while (qhead) { - CloseHandle(qhead->Overlapped.hEvent); - closesocket(qhead->accept_socket); - qhead = qhead->next; - } - apr_lock_release(qlock); - } - - /* Give busy worker threads a chance to service their connections */ - ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: Waiting for %d threads to die.", my_pid, nthreads); - 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; - } - - /* Kill remaining threads off the hard way */ - for (i = 0; i < nthreads; i++) { - TerminateThread(child_handles[i], 1); - CloseHandle(child_handles[i]); - } - ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: All worker threads have ended.", my_pid); - - CloseHandle(allowed_globals.jobsemaphore); - apr_lock_destroy(allowed_globals.jobmutex); - apr_lock_destroy(qlock); - - apr_pool_destroy(pchild); - CloseHandle(exit_event); -} - -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)--; -} - -static int create_process(apr_pool_t *p, HANDLE *handles, HANDLE *events, int *processes) -{ - int rv; - char buf[1024]; - char *pCommand; - char *pEnvVar; - char *pEnvBlock; - int i; - int iEnvBlockLen; - STARTUPINFO si; /* Filled in prior to call to CreateProcess */ - PROCESS_INFORMATION pi; /* filled in on call to CreateProcess */ - - ap_listen_rec *lr; - DWORD BytesWritten; - HANDLE hPipeRead = NULL; - HANDLE hPipeWrite = NULL; - SECURITY_ATTRIBUTES sa = {0}; - - HANDLE kill_event; - LPWSAPROTOCOL_INFO lpWSAProtocolInfo; - - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - - /* Build the command line. Should look something like this: - * C:/apache/bin/apache.exe -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_CRIT, ERROR_BAD_PATHNAME, server_conf, - "Parent: Path to Apache process too long"); - return -1; - } else if (rv == 0) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, - "Parent: GetModuleFileName() returned NULL for current process."); - return -1; - } - - /* Build the command line */ - pCommand = apr_psprintf(p, "\"%s\"", buf); - for (i = 1; i < server_conf->process->argc; i++) { - pCommand = apr_pstrcat(p, pCommand, " \"", server_conf->process->argv[i], "\"", NULL); - } - - /* Build the environment, since Win9x disrespects the active env */ - pEnvVar = apr_psprintf(p, "AP_PARENT_PID=%i", parent_pid); - /* - * Win32's CreateProcess call requires that the environment - * be passed in an environment block, a null terminated block of - * null terminated strings. - */ - i = 0; - iEnvBlockLen = 1; - while (_environ[i]) { - iEnvBlockLen += strlen(_environ[i]) + 1; - i++; - } - - pEnvBlock = (char *)apr_pcalloc(p, iEnvBlockLen + strlen(pEnvVar) + 1); - strcpy(pEnvBlock, pEnvVar); - pEnvVar = strchr(pEnvBlock, '\0') + 1; - - i = 0; - while (_environ[i]) { - strcpy(pEnvVar, _environ[i]); - pEnvVar = strchr(pEnvVar, '\0') + 1; - i++; - } - pEnvVar = '\0'; - /* Create a pipe to send socket info to the child */ - if (!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, - "Parent: Unable to create pipe to child process."); - return -1; - } - - /* Give the read end of the 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 */ - CREATE_SUSPENDED, /* Creation flags */ - pEnvBlock, /* Environment block */ - NULL, - &si, &pi)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), 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; - } - - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf, - "Parent: Created child process %d", pi.dwProcessId); - - SetEnvironmentVariable("AP_PARENT_PID",NULL); - - /* Create the exit_event, apCchild_pid */ - sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - kill_event = CreateEvent(&sa, TRUE, FALSE, apr_psprintf(pconf,"apC%d", pi.dwProcessId)); - if (!kill_event) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, - "Parent: Could not create exit event for child process"); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - return -1; - } - - /* 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. */ - ResumeThread(pi.hThread); - 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. - */ - for (lr = ap_listeners; lr; lr = lr->next) { - int nsd; - lpWSAProtocolInfo = apr_pcalloc(p, sizeof(WSAPROTOCOL_INFO)); - apr_os_sock_get(&nsd,lr->sd); - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf, - "Parent: Duplicating socket %d and sending it to child process %d", nsd, pi.dwProcessId); - if (WSADuplicateSocket(nsd, pi.dwProcessId, - lpWSAProtocolInfo) == SOCKET_ERROR) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), server_conf, - "Parent: WSADuplicateSocket failed for socket %d. Check the FAQ.", lr->sd ); - return -1; - } - - if (!WriteFile(hPipeWrite, lpWSAProtocolInfo, (DWORD) sizeof(WSAPROTOCOL_INFO), - &BytesWritten, - (LPOVERLAPPED) NULL)) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, - "Parent: Unable to write duplicated socket %d to the child.", lr->sd ); - return -1; - } - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, server_conf, - "Parent: BytesWritten = %d WSAProtocolInfo = %x20", BytesWritten, *lpWSAProtocolInfo); - } - - CloseHandle(hPipeRead); - CloseHandle(hPipeWrite); - - return 0; -} - -/********************************************************************** - * master_main() - * This is the parent process. master_main() creates a multithreaded - * child process to handle connections, then blocks waiting to receive - * a shutdown, restart event or child exit event. - * - * restart_event - * - Child is signaled to die gracefully - * shutdown_event - * - Child is signaled to die gracefully - * child_exit_event - * - Child has died, either normally (max_request_per_child) - * or abnormally (seg fault, irrecoverable error condition detected by the - * child) - **********************************************************************/ -#define MAX_PROCESSES 50 /* must be < MAX_WAIT_OBJECTS-1 */ -static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_event) -{ - int remaining_children_to_start = ap_daemons_to_start; - int i; - int rv, cld; - int child_num = 0; - int restart_pending = 0; - int shutdown_pending = 0; - int current_live_processes = 0; /* number of child process we know about */ - - HANDLE process_handles[MAX_PROCESSES]; - HANDLE process_kill_events[MAX_PROCESSES]; - - - /* Create child process - * Should only be one in this version of Apache for WIN32 - */ - while (remaining_children_to_start--) { - if (create_process(pconf, process_handles, process_kill_events, - ¤t_live_processes) < 0) { - ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, - "master_main: create child process failed. Exiting."); - shutdown_pending = 1; - goto die_now; - } - } - - restart_pending = shutdown_pending = 0; - - if (!strcasecmp(signal_arg, "runservice")) - mpm_service_started(); - - /* Wait for shutdown or restart events or for child death */ - process_handles[current_live_processes] = shutdown_event; - process_handles[current_live_processes+1] = restart_event; - - rv = WaitForMultipleObjects(current_live_processes+2, (HANDLE *)process_handles, - FALSE, INFINITE); - cld = rv - WAIT_OBJECT_0; - if (rv == WAIT_FAILED) { - /* Something serious is wrong */ - ap_log_error(APLOG_MARK,APLOG_CRIT, apr_get_os_error(), server_conf, - "master_main: WaitForMultipeObjects WAIT_FAILED -- doing server shutdown"); - shutdown_pending = 1; - } - else if (rv == WAIT_TIMEOUT) { - /* Hey, this cannot happen */ - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "master_main: WaitForMultipeObjects with INFINITE wait exited with WAIT_TIMEOUT"); - shutdown_pending = 1; - } - else if (cld == current_live_processes) { - /* shutdown_event signalled */ - shutdown_pending = 1; - printf("shutdown event signaled\n"); - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, s, - "Parent: SHUTDOWN EVENT SIGNALED -- Shutting down the server."); - if (ResetEvent(shutdown_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "ResetEvent(shutdown_event)"); - } - - } - else if (cld == current_live_processes+1) { - /* restart_event signalled */ - int children_to_kill = current_live_processes; - restart_pending = 1; - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s, - "Parent: RESTART EVENT SIGNALED -- Restarting the server."); - if (ResetEvent(restart_event) == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "master_main: ResetEvent(restart_event) failed."); - } - /* Signal each child process to die - * We are making a big assumption here that the child process, once signaled, - * will REALLY go away. Since this is a restart, we do not want to hold the - * new child process up waiting for the old child to die. Remove the old - * child out of the process_handles apr_table_t and hope for the best... - */ - for (i = 0; i < children_to_kill; i++) { - if (SetEvent(process_kill_events[i]) == 0) - ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), s, - "master_main: SetEvent for child process in slot #%d failed", i); - cleanup_process(process_handles, process_kill_events, i, ¤t_live_processes); - } - } - else { - /* A child process must have exited because of a fatal error condition (seg fault, etc.). - * Remove the dead process - * from the process_handles and process_kill_events apr_table_t and create a new - * child process. - * TODO: Consider restarting the child immediately without looping through http_main - * and without rereading the configuration. Will need this if we ever support multiple - * children. One option, create a parent thread which waits on child death and restarts it. - * Consider, however, that if the user makes httpd.conf invalid, we want to die before - * our child tries it... otherwise we have a nasty loop. - */ - restart_pending = 1; - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, server_conf, - "Parent: CHILD PROCESS FAILED -- 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); */ - /* restart_child(process_hancles, process_kill_events, cld, ¤t_live_processes); */ - } - -die_now: - if (shutdown_pending) - { - int tmstart = time(NULL); - - if (strcasecmp(signal_arg, "runservice")) { - mpm_service_stopping(); - } - /* Signal each child processes to die */ - for (i = 0; i < current_live_processes; i++) { - printf("SetEvent handle = %d\n", process_kill_events[i]); - if (SetEvent(process_kill_events[i]) == 0) - ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_os_error(), server_conf, - "master_main: SetEvent for child process in slot #%d failed", i); - } - - while (current_live_processes && ((tmstart+60) > time(NULL))) { - 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); - 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, APR_SUCCESS, server_conf, - "Parent: Forcing termination of child #%d (handle %d)", i, process_handles[i]); - TerminateProcess((HANDLE) process_handles[i], 1); - } - return 0; /* Tell the caller we do not want to restart */ - } - - return 1; /* Tell the caller we want a restart */ -} - - -/* service_nt_main_fn needs to append the StartService() args - * outside of our call stack and thread as the service starts... - */ -apr_array_header_t *mpm_new_argv; - -/* Remember service_to_start failures to log and fail in pre_config. - * Remember inst_argc and inst_argv for installing or starting the - * service after we preflight the config. - */ - -AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) -{ - switch(query_code){ - case AP_MPMQ_MAX_DAEMONS: - *result = MAXIMUM_WAIT_OBJECTS; - return APR_SUCCESS; - case AP_MPMQ_IS_THREADED: - *result = AP_MPMQ_STATIC; - return APR_SUCCESS; - case AP_MPMQ_IS_FORKED: - *result = AP_MPMQ_NOT_SUPPORTED; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_DAEMONS: - *result = HARD_SERVER_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_HARD_LIMIT_THREADS: - *result = HARD_THREAD_LIMIT; - return APR_SUCCESS; - case AP_MPMQ_MAX_THREADS: - *result = ap_threads_per_child; - return APR_SUCCESS; - } - return APR_ENOTIMPL; -} - -#define SERVICE_UNSET (-1) -static apr_status_t service_set = SERVICE_UNSET; -static apr_status_t service_to_start_success; -static int inst_argc; -static const char * const *inst_argv; -static char *service_name = NULL; - -void winnt_rewrite_args(process_rec *process) -{ - /* Handle the following SCM aspects in this phase: - * - * -k runservice [transition for WinNT, nothing for Win9x] - * -k (!)install [error out if name is not installed] - * - * We can't leave this phase until we know our identity - * and modify the command arguments appropriately. - */ - apr_status_t rv; - char *def_server_root; - char fnbuf[MAX_PATH]; - char optbuf[3]; - const char *optarg; - int fixed_args; - char *pid; - apr_getopt_t *opt; - int running_as_service = 1; - - osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osver); - - /* AP_PARENT_PID is only valid in the child */ - pid = getenv("AP_PARENT_PID"); - if (pid) - { - /* This is the child */ - my_pid = GetCurrentProcessId(); - parent_pid = (DWORD) atol(pid); - - /* The parent is responsible for providing the - * COMPLETE ARGUMENTS REQUIRED to the child. - * - * No further argument parsing is needed, but - * for good measure we will provide a simple - * signal string for later testing. - */ - signal_arg = "runchild"; - return; - } - - /* This is the parent, we have a long way to go :-) */ - parent_pid = my_pid = GetCurrentProcessId(); - - /* Rewrite process->argv[]; - * - * strip out -k signal into signal_arg - * strip out -n servicename and set the names - * add default -d serverroot from the path of this executable - * - * The end result will look like: - * - * The invocation command (%0) - * The -d serverroot default from the running executable - * The requested service's (-n) registry ConfigArgs - * The WinNT SCM's StartService() args - */ - if (!GetModuleFileName(NULL, fnbuf, sizeof(fnbuf))) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK,APLOG_ERR, rv, NULL, - "Failed to get the path of Apache.exe"); - exit(1); - } - /* WARNING: There is an implict assumption here that the - * executable resides in ServerRoot or ServerRoot\bin - */ - def_server_root = (char *) apr_filename_of_pathname(fnbuf); - if (def_server_root > fnbuf) { - *(def_server_root - 1) = '\0'; - def_server_root = (char *) apr_filename_of_pathname(fnbuf); - if (!strcasecmp(def_server_root, "bin")) - *(def_server_root - 1) = '\0'; - } - def_server_root = ap_os_canonical_filename(process->pool, fnbuf); - - /* Use process->pool so that the rewritten argv - * lasts for the lifetime of the server process, - * because pconf will be destroyed after the - * initial pre-flight of the config parser. - */ - mpm_new_argv = apr_array_make(process->pool, process->argc + 2, - sizeof(const char *)); - *(const char **)apr_array_push(mpm_new_argv) = process->argv[0]; - *(const char **)apr_array_push(mpm_new_argv) = "-d"; - *(const char **)apr_array_push(mpm_new_argv) = def_server_root; - - fixed_args = mpm_new_argv->nelts; - - optbuf[0] = '-'; - optbuf[2] = '\0'; - apr_getopt_init(&opt, process->pool, process->argc, (char**) process->argv); - while (apr_getopt(opt, "n:k:iu" AP_SERVER_BASEARGS, - optbuf + 1, &optarg) == APR_SUCCESS) { - switch (optbuf[1]) { - case 'n': - service_set = mpm_service_set_name(process->pool, &service_name, - optarg); - break; - case 'k': - signal_arg = optarg; - break; - case 'i': - ap_log_error(APLOG_MARK,APLOG_WARNING, 0, NULL, - "-i is deprecated. Use -k install."); - signal_arg = "install"; - break; - case 'u': - ap_log_error(APLOG_MARK,APLOG_WARNING, 0, NULL, - "-u is deprecated. Use -k uninstall."); - signal_arg = "uninstall"; - break; - default: - *(const char **)apr_array_push(mpm_new_argv) = - apr_pstrdup(process->pool, optbuf); - - if (optarg) { - *(const char **)apr_array_push(mpm_new_argv) = optarg; - } - break; - } - } - - /* Track the number of args actually entered by the user */ - inst_argc = mpm_new_argv->nelts - fixed_args; - - /* Provide a default 'run' -k arg to simplify signal_arg tests */ - if (!signal_arg) - { - signal_arg = "run"; - running_as_service = 0; - } - - if (!strcasecmp(signal_arg, "runservice")) - { - /* Start the NT Service _NOW_ because the WinNT SCM is - * expecting us to rapidly assume control of our own - * process, the SCM will tell us our service name, and - * may have extra StartService() command arguments to - * add for us. - * - * Any other process has a console, so we don't to begin - * a Win9x service until the configuration is parsed and - * any command line errors are reported. - * - * We hold the return value so that we can die in pre_config - * after logging begins, and the failure can land in the log. - */ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { - service_to_start_success = mpm_service_to_start(&service_name); - if (service_to_start_success == APR_SUCCESS) - service_set = APR_SUCCESS; - } - } - - if (service_set == SERVICE_UNSET && running_as_service) { - service_set = mpm_service_set_name(process->pool, &service_name, - DEFAULT_SERVICE_NAME); - } - - if (!strcasecmp(signal_arg, "install")) /* -k install */ - { - if (service_set == APR_SUCCESS) - { - ap_log_error(APLOG_MARK,APLOG_ERR, 0, NULL, - "%s: Service is already installed.", service_name); - exit(1); - } - } - else if (running_as_service) - { - if (service_set == APR_SUCCESS) - { - rv = mpm_merge_service_args(process->pool, mpm_new_argv, - fixed_args); - if (rv == APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_NOERRNO|APLOG_INFO, 0, NULL, - "Using ConfigArgs of the installed service " - "\"%s\".", service_name); - } - else { - ap_log_error(APLOG_MARK,APLOG_INFO, rv, NULL, - "No installed ConfigArgs for the service " - "\"%s\", using Apache defaults.", service_name); - } - } - else - { - ap_log_error(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO, 0, NULL, - "No installed service named \"%s\".", service_name); - exit(1); - } - } - - /* Track the args actually entered by the user. - * These will be used for the -k install parameters, as well as - * for the -k start service override arguments. - */ - inst_argv = (const char * const *)mpm_new_argv->elts - + mpm_new_argv->nelts - inst_argc; - - process->argc = mpm_new_argv->nelts; - process->argv = (const char * const *) mpm_new_argv->elts; -} - - -static void winnt_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) -{ - /* Handle the following SCM aspects in this phase: - * - * -k runservice [WinNT errors logged from rewrite_args] - * -k uninstall - * -k stop - * - * in these cases we -don't- care if httpd.conf has config errors! - */ - apr_status_t rv; - - if (ap_exists_config_define("ONE_PROCESS")) - one_process = -1; - - if (ap_exists_config_define("ONE_PROCESS")) - one_process = -1; - - if (!strcasecmp(signal_arg, "runservice") - && (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - && (service_to_start_success != APR_SUCCESS)) { - ap_log_error(APLOG_MARK,APLOG_ERR, service_to_start_success, NULL, - "%s: Unable to start the service manager.", - service_name); - exit(1); - } - - if (!strcasecmp(signal_arg, "uninstall")) { - rv = mpm_service_uninstall(); - exit(rv); - } - - if (!strcasecmp(signal_arg, "stop")) { - mpm_signal_service(ptemp, 0); - exit(0); - } - - ap_listen_pre_config(); - ap_daemons_to_start = DEFAULT_NUM_DAEMON; - ap_threads_per_child = DEFAULT_START_THREAD; - ap_pid_fname = DEFAULT_PIDLOG; - ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; - - apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); -} - -static void winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec* server) -{ - static int restart_num = 0; - apr_status_t rv = 0; - - server_conf = server; - - /* Handle the following SCM aspects in this phase: - * - * -k install - * -k start - * -k restart - * -k runservice [Win95, only once - after we parsed the config] - * - * because all of these signals are useful _only_ if there - * is a valid conf\httpd.conf environment to start. - * - * We reached this phase by avoiding errors that would cause - * these options to fail unexpectedly in another process. - */ - - if (!strcasecmp(signal_arg, "install")) { - rv = mpm_service_install(ptemp, inst_argc, inst_argv); - exit (rv); - } - - if (!strcasecmp(signal_arg, "start")) { - rv = mpm_service_start(ptemp, inst_argc, inst_argv); - exit (rv); - } - - if (!strcasecmp(signal_arg, "restart")) { - mpm_signal_service(ptemp, 1); - exit (rv); - } - - if (parent_pid == my_pid) - { - if (restart_num++ == 1) - { - /* This code should be run once in the parent and not run - * across a restart - */ - PSECURITY_ATTRIBUTES sa = GetNullACL(); /* returns NULL if invalid (Win95?) */ - setup_signal_names(apr_psprintf(pconf,"ap%d", parent_pid)); - - ap_log_pid(pconf, ap_pid_fname); - - /* Create shutdown event, apPID_shutdown, where PID is the parent - * Apache process ID. Shutdown is signaled by 'apache -k shutdown'. - */ - shutdown_event = CreateEvent(sa, FALSE, FALSE, signal_shutdown_name); - if (!shutdown_event) { - ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), server_conf, - "Parent: 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'. - */ - restart_event = CreateEvent(sa, FALSE, FALSE, signal_restart_name); - if (!restart_event) { - CloseHandle(shutdown_event); - ap_log_error(APLOG_MARK, APLOG_EMERG, apr_get_os_error(), server_conf, - "Parent: Cannot create restart event %s", signal_restart_name); - CleanNullACL((void *)sa); - exit(1); - } - CleanNullACL((void *)sa); - - /* Now that we are flying at 15000 feet... - * wipe out the Win95 service console, - * signal the SCM the WinNT service started, or - * if not a service, setup console handlers instead. - */ - if (!strcasecmp(signal_arg, "runservice")) - { - if (osver.dwPlatformId != VER_PLATFORM_WIN32_NT) - { - rv = mpm_service_to_start(&service_name); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_ERR, rv, server_conf, - "%s: Unable to start the service manager.", - service_name); - exit(1); - } - } - } - else /* ! -k runservice */ - { - mpm_start_console_handler(); - } - - /* 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. - */ - apr_lock_create(&start_mutex,APR_MUTEX, APR_CROSS_PROCESS, signal_name_prefix, - server_conf->process->pool); - } - } - else /* parent_pid != my_pid */ - { - mpm_start_child_console_handler(); - } -} - -AP_DECLARE(int) ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s ) -{ - static int restart = 0; /* Default is "not a restart" */ - - pconf = _pconf; - server_conf = s; - - if ((parent_pid != my_pid) || one_process) { - /* Child process or in one_process (debug) mode */ - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: Child process is running", my_pid); - - /* Set up the scoreboard. The scoreboard in this MPM only applies to the - * child process and is not shared across processes - */ - ap_create_scoreboard(pconf, SB_NOT_SHARED); - - if (one_process) { - if (ap_setup_listeners(server_conf) < 1) { - return 1; - } - } - else { - get_listeners_from_parent(server_conf); - } - - child_main(); - - ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf, - "Child %d: Child process is exiting", my_pid); - - return 1; - } - else { - /* Parent process */ - if (ap_setup_listeners(server_conf) < 1) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s, - "no listening sockets available, shutting down"); - return 1; - } - - restart = master_main(server_conf, shutdown_event, restart_event); - - if (!restart) { - /* Shutting down. Clean up... */ - const char *pidfile = ap_server_root_relative (pconf, ap_pid_fname); - - if (pidfile != NULL && unlink(pidfile) == 0) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, - server_conf, "removed PID file %s (pid=%ld)", - pidfile, GetCurrentProcessId()); - } - apr_lock_destroy(start_mutex); - - CloseHandle(restart_event); - CloseHandle(shutdown_event); - - return 1; - } - } /* Parent process */ - - return 0; /* Restart */ -} - -static void winnt_hooks(apr_pool_t *p) -{ - ap_hook_pre_config(winnt_pre_config, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(winnt_post_config, NULL, NULL, 0); -} - -/* - * Command processors - */ -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 <VirtualHost>"; - } - ap_pid_fname = arg; - return NULL; -} - -static const char *set_threads_per_child (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_THREAD_LIMIT) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: ThreadsPerChild of %d exceeds compile time" - " limit of %d threads,", ap_threads_per_child, - HARD_THREAD_LIMIT); - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - " lowering ThreadsPerChild to %d. To increase, please" - " see the HARD_THREAD_LIMIT define in %s.", - HARD_THREAD_LIMIT, AP_MPM_HARD_LIMITS_FILE); - ap_threads_per_child = HARD_THREAD_LIMIT; - } - else if (ap_threads_per_child < 1) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, - "WARNING: Require ThreadsPerChild > 0, setting to 1"); - ap_threads_per_child = 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_coredumpdir (cmd_parms *cmd, void *dummy, char *arg) -{ - apr_finfo_t finfo; - const char *fname; - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - - fname = ap_server_root_relative(cmd->pool, arg); - if ((apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) - || (finfo.filetype != APR_DIR)) { - return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, - " does not exist or is not a directory", NULL); - } - apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir)); - return NULL; -} - -/* Stub functions until this MPM supports the connection status API */ - -AP_DECLARE(void) ap_update_connection_status(long conn_id, const char *key, \ - const char *value) -{ - /* NOP */ -} - -AP_DECLARE(void) ap_reset_connection_status(long conn_id) -{ - /* NOP */ -} - -AP_DECLARE(apr_array_header_t *) ap_get_status_table(apr_pool_t *p) -{ - /* NOP */ - return NULL; -} - -static const command_rec winnt_cmds[] = { -LISTEN_COMMANDS -{ "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1, - "A file for logging the server process ID"}, -{ "ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, TAKE1, - "Number of threads each child creates" }, -{ "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1, - "Maximum number of requests a particular child serves before dying." }, -{ "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1, - "The location of the directory Apache changes to before dumping core" }, -{ NULL } -}; - -AP_MODULE_DECLARE_DATA module mpm_winnt_module = { - MPM20_MODULE_STUFF, - winnt_rewrite_args, /* hook to run before apache parses args */ - NULL, /* create per-directory config structure */ - NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ - NULL, /* merge per-server config structures */ - winnt_cmds, /* command apr_table_t */ - winnt_hooks /* register_hooks */ -}; diff --git a/server/mpm/winnt/mpm_winnt.h b/server/mpm/winnt/mpm_winnt.h deleted file mode 100644 index cec0a64ce4..0000000000 --- a/server/mpm/winnt/mpm_winnt.h +++ /dev/null @@ -1,159 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#ifndef APACHE_MPM_WINNT_H -#define APACHE_MPM_WINNT_H - -#include "ap_listen.h" - -/* From registry.c: */ - -apr_status_t ap_registry_create_key(const char *key); -apr_status_t ap_registry_delete_key(const char *key); - -apr_status_t ap_registry_store_value(const char *key, const char *name, - const char *value); -apr_status_t ap_registry_get_value(apr_pool_t *p, const char *key, - const char *name, char **ppValue); -apr_status_t ap_registry_store_array(apr_pool_t *p, const char *key, - const char *name, int nelts, - char const* const* elts); -apr_status_t ap_registry_get_array(apr_pool_t *p, const char *key, - const char *name, - apr_array_header_t **parray); -apr_status_t ap_registry_delete_value(const char *key, const char *name); - - -/* From service.c: */ - -#define SERVICE_APACHE_RESTART 128 - -#define DEFAULT_SERVICE_NAME AP_SERVER_BASEPRODUCT -#define SERVICECONFIG9X "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices" -#define SERVICECONFIG "System\\CurrentControlSet\\Services\\%s" -#define SERVICEPARAMS "System\\CurrentControlSet\\Services\\%s\\Parameters" - -apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name, - const char *set_name); -apr_status_t mpm_merge_service_args(apr_pool_t *p, apr_array_header_t *args, - int fixed_args); - -apr_status_t mpm_service_to_start(const char **display_name); -apr_status_t mpm_service_started(void); -apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc, - char const* const* argv); -apr_status_t mpm_service_uninstall(void); - -apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc, - char const* const* argv); - -void mpm_signal_service(apr_pool_t *ptemp, int signal); - -void mpm_service_stopping(void); - -void mpm_start_console_handler(void); -void mpm_start_child_console_handler(void); - -/* From winnt.c: */ - -extern OSVERSIONINFO osver; -extern int ap_max_requests_per_child; -extern void clean_child_exit(int); - -AP_DECLARE(void) ap_start_shutdown(void); -AP_DECLARE(void) ap_start_restart(int gracefully); - -void setup_signal_names(char *prefix); -void signal_parent(int type); - - -/* This code is stolen from the apr_private.h and misc/win32/misc.c - * Please see those sources for detailed documentation. - */ -typedef enum { - DLL_WINBASEAPI = 0, // kernel32 From WinBase.h - DLL_WINADVAPI = 1, // advapi32 From WinBase.h - DLL_WINSOCKAPI = 2, // mswsock From WinSock.h - DLL_WINSOCK2API = 3, // ws2_32 From WinSock2.h - DLL_defined = 4 // must define as last idx_ + 1 -} ap_dlltoken_e; - -FARPROC ap_load_dll_func(ap_dlltoken_e fnLib, char *fnName, int ordinal); - -#define AP_DECLARE_LATE_DLL_FUNC(lib, rettype, calltype, fn, ord, args, names) \ - typedef rettype (calltype *ap_winapi_fpt_##fn) args; \ - static ap_winapi_fpt_##fn ap_winapi_pfn_##fn = NULL; \ - __inline rettype ap_winapi_##fn args \ - { if (!ap_winapi_pfn_##fn) \ - ap_winapi_pfn_##fn = (ap_winapi_fpt_##fn) ap_load_dll_func(lib, #fn, ord); \ - return (*(ap_winapi_pfn_##fn)) names; }; \ - -/* WinNT kernel only */ -AP_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, BOOL, WINAPI, CancelIo, 0, ( - IN HANDLE hFile), - (hFile)); -#define CancelIo ap_winapi_CancelIo - -/* Win9x kernel only */ -AP_DECLARE_LATE_DLL_FUNC(DLL_WINBASEAPI, DWORD, WINAPI, RegisterServiceProcess, 0, ( - DWORD dwProcessId, - DWORD dwType), - (dwProcessId, dwType)); -#define RegisterServiceProcess ap_winapi_RegisterServiceProcess - -#endif /* APACHE_MPM_WINNT_H */ diff --git a/server/mpm/winnt/registry.c b/server/mpm/winnt/registry.c deleted file mode 100644 index aa23e54a4d..0000000000 --- a/server/mpm/winnt/registry.c +++ /dev/null @@ -1,489 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * Functions to handle interacting with the Win32 registry - */ - -/* - * Apache registry key structure - * - * Apache's registry information is stored in the HKEY_LOCAL_MACHINE - * key, under - * - * HKLM\SOFTWARE\Apache Software Foundation\Apache\version - * - * These keys are defined in this file. The definition of the "version" part - * will need updating each time Apache moves from beta to non-beta or from a - * release to a development or beta version. - */ - -#include "httpd.h" -#include "http_log.h" -#include "mpm_winnt.h" -#include "apr_strings.h" - -/* bet you are looking to change revisions to roll the tarball... - * Guess what, you already did. Revised May '00 to save you from - * searching all over creation for every revision tag. - */ - -#define VENDOR AP_SERVER_BASEVENDOR -#define SOFTWARE AP_SERVER_BASEPRODUCT -#define VERSION AP_SERVER_BASEREVISION - -#define REGKEY "SOFTWARE\\" VENDOR "\\" SOFTWARE "\\" VERSION - -/* - * The Windows API registry key functions don't set the last error - * value (the windows equivalent of errno). So we need to set it - * with SetLastError() before calling the aplog_error() function. - * Because this is common, let's have a macro. - */ -#define return_error(rv) return (apr_set_os_error(APR_FROM_OS_ERROR(rv)),\ - APR_FROM_OS_ERROR(rv)); - -apr_status_t ap_registry_create_key(const char *key) -{ - HKEY hKey = HKEY_LOCAL_MACHINE; - HKEY hKeyNext; - char keystr[MAX_PATH + 1]; - char *parsekey = keystr; - char *nextkey = keystr; - DWORD result; - int rv; - - apr_cpystrn(keystr, key, sizeof(keystr) - 1); - - /* Walk the tree, creating at each stage if necessary */ - while (parsekey) { - if (nextkey = strchr(parsekey, '\\')) - *(nextkey++) = '\0'; - - rv = RegCreateKeyEx(hKey, - parsekey, /* subkey */ - 0, /* reserved */ - NULL, /* class */ - REG_OPTION_NON_VOLATILE, - KEY_WRITE, - NULL, - &hKeyNext, - &result); - - /* Close the old key */ - if (hKey != HKEY_LOCAL_MACHINE) - RegCloseKey(hKey); - hKey = hKeyNext; - - if (rv != ERROR_SUCCESS) - break; - - parsekey = nextkey; - } - - if (hKey != HKEY_LOCAL_MACHINE) - RegCloseKey(hKey); - - return_error(rv); -} - -apr_status_t ap_registry_delete_key(const char *key) -{ - apr_status_t rv; - HKEY hKey; - int nSize = 0; - char tempkey[MAX_PATH + 1]; - char *parsekey; - - apr_cpystrn(tempkey, key, sizeof(parsekey) - 1); - parsekey = strrchr(tempkey, '\\'); - - if (parsekey) { - *(parsekey++) = '\0'; - rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - tempkey, - 0, - KEY_WRITE, - &hKey); - - if (rv != ERROR_SUCCESS) - return_error(rv); - } - else { - parsekey = tempkey; - hKey = HKEY_LOCAL_MACHINE; - } - - rv = RegDeleteKey(hKey, key); - - if (hKey != HKEY_LOCAL_MACHINE) - RegCloseKey(hKey); - - return_error(rv); -} - -/* Clean up a way over complicated process. - * - * The return value is APR_SUCCESS, APR_ENOENT, APR_NOTFOUND, or the OS error - */ - -apr_status_t ap_registry_get_value(apr_pool_t *p, const char *key, const char *name, char **ppValue) -{ - apr_status_t rv; - HKEY hKey; - int nSize = 0; - - rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - key, - 0, - KEY_READ, - &hKey); - - if (rv != ERROR_SUCCESS) - return_error(rv); - - /* Find the size required for the data by passing NULL as the buffer - * pointer. On return nSize will contain the size required for the - * buffer if the return value is ERROR_SUCCESS. - */ - rv = RegQueryValueEx(hKey, - name, /* key name */ - NULL, /* reserved */ - NULL, /* type */ - NULL, /* for value */ - &nSize); /* for size of "value" */ - - if (rv != ERROR_SUCCESS) - return_error(rv); - - *ppValue = apr_palloc(p, nSize); - rv = RegQueryValueEx(hKey, - name, /* key name */ - NULL, /* reserved */ - NULL, /* type */ - *ppValue, /* for value */ - &nSize); /* for size of "value" */ - - RegCloseKey(hKey); - - return_error(rv); -} - -apr_status_t ap_registry_get_array(apr_pool_t *p, const char *key, const char *name, apr_array_header_t **parray) -{ - char *pValue; - char *tmp; - char **newelem; - apr_status_t rv; - HKEY hKey; - int nSize = 0; - - rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - key, - 0, - KEY_READ, - &hKey); - - if (rv != ERROR_SUCCESS) - return_error(rv); - - /* Find the size required for the data by passing NULL as the buffer - * pointer. On return nSize will contain the size required for the - * buffer if the return value is ERROR_SUCCESS. - */ - rv = RegQueryValueEx(hKey, - name, /* key name */ - NULL, /* reserved */ - NULL, /* type */ - NULL, /* for value */ - &nSize); /* for size of "value" */ - - if (rv != ERROR_SUCCESS) { - return_error(rv); - } - else - { - pValue = apr_palloc(p, nSize); - rv = RegQueryValueEx(hKey, - name, /* key name */ - NULL, /* reserved */ - NULL, /* type */ - pValue, /* for value */ - &nSize); /* for size of "value" */ - - nSize = 1; /* Element Count */ - tmp = pValue; - while (tmp[0] || tmp[1]) - { - if (!tmp[0]) - ++nSize; - ++tmp; - } - - *parray = apr_array_make(p, nSize, sizeof(char *)); - tmp = pValue; - newelem = (char **) apr_array_push(*parray); - *newelem = tmp; - while (tmp[0] || tmp[1]) - { - if (!tmp[0]) { - newelem = (char **) apr_array_push(*parray); - *newelem = tmp + 1; - } - ++tmp; - } - } - - RegCloseKey(hKey); - - return_error(rv); -} - -/* - * ap_registry_store_key_value() stores a value name and value under the - * Apache registry key. If the Apache key does not exist it is created - * first. This function is intended to be called from a wrapper function - * in this file to set particular data values, such as - * ap_registry_set_server_root() below. - * - * Returns 0 if the value name and data was stored successfully, or - * returns -1 if the Apache key does not exist (since we try to create - * this key, this should never happen), or -4 if any other error occurred - * (these values are consistent with ap_registry_get_key_value()). - * If the return value is negative then the error will already have been - * logged via aplog_error(). - */ - -apr_status_t ap_registry_store_value(const char *key, const char *name, const char *value) -{ - long rv; - HKEY hKey; - - rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - key, - 0, - KEY_WRITE, - &hKey); - - if (rv == ERROR_FILE_NOT_FOUND) - { - rv = ap_registry_create_key(key); - - if (rv != APR_SUCCESS) - return_error(rv); - - rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - key, - 0, - KEY_WRITE, - &hKey); - } - - if (rv != ERROR_SUCCESS) - return_error(rv); - - /* Now set the value and data */ - rv = RegSetValueEx(hKey, - name, /* value key name */ - 0, /* reserved */ - REG_SZ, /* type */ - value, /* value data */ - (DWORD) strlen(value) + 1); /* for size of "value" */ - - if (rv == ERROR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,rv,NULL, - "Registry stored HKLM\\" REGKEY "\\%s value %s", key, value); - } - - /* Make sure we close the key even if there was an error storing - * the data - */ - RegCloseKey(hKey); - - return_error(rv); -} - -apr_status_t ap_registry_store_array(apr_pool_t *p, - const char *key, const char *name, - int nelts, const char * const * elts) -{ - int bufsize, i; - char *buf, *tmp; - long rv; - HKEY hKey; - - rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - key, - 0, - KEY_WRITE, - &hKey); - - if (rv == ERROR_FILE_NOT_FOUND) - { - rv = ap_registry_create_key(key); - - if (rv != APR_SUCCESS) - return_error(rv); - - rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - key, - 0, - KEY_WRITE, - &hKey); - } - - if (rv != ERROR_SUCCESS) - return_error(rv); - - bufsize = 1; /* For trailing second null */ - for (i = 0; i < nelts; ++i) - { - bufsize += strlen(elts[i]) + 1; - } - if (!nelts) - ++bufsize; - - buf = apr_palloc(p, bufsize); - tmp = buf; - for (i = 0; i < nelts; ++i) - { - strcpy(tmp, elts[i]); - tmp += strlen(elts[i]) + 1; - } - if (!nelts) - (*tmp++) = '\0'; - *tmp = '\0'; /* Trailing second null */ - - /* Now set the value and data */ - rv = RegSetValueEx(hKey, - name, /* value key name */ - 0, /* reserved */ - REG_MULTI_SZ, /* type */ - buf, /* value data */ - (DWORD) bufsize); /* for size of "value" */ - - if (rv == ERROR_SUCCESS) { - ap_log_error(APLOG_MARK,APLOG_INFO|APLOG_NOERRNO,rv,NULL, - "Registry stored HKLM\\" REGKEY "\\%s", key); - } - - /* Make sure we close the key even if there was an error storing - * the data - */ - RegCloseKey(hKey); - - return_error(rv); -} - -/* A key or value that does not exist is _not_ an error while deleting. */ - -apr_status_t ap_registry_delete_value(const char *key, const char *name) -{ - apr_status_t rv; - HKEY hKey; - - rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, - key, - 0, - KEY_WRITE, - &hKey); - - if (rv == ERROR_FILE_NOT_FOUND) - return APR_SUCCESS; - - if (rv != ERROR_SUCCESS) - return_error(rv); - - rv = RegDeleteValue(hKey, name); - - if (rv == ERROR_FILE_NOT_FOUND) - rv = APR_SUCCESS; - - RegCloseKey(hKey); - return_error(rv); -} - -/* - * Get the server root from the registry into 'dir' which is - * size bytes long. Returns 0 if the server root was found - * or if the serverroot key does not exist (in which case - * dir will contain an empty string), or -1 if there was - * an error getting the key. - */ -apr_status_t ap_registry_get_server_root(apr_pool_t *p, char **buf) -{ - apr_status_t rv; - - rv = ap_registry_get_value(p, REGKEY, "ServerRoot", buf); - if (rv) - *buf = NULL; - - return rv; -} - - -/* - * Sets the serverroot value within the registry. Returns 0 on success - * or -1 on error. If -1 is return the error will already have been - * logged via aplog_error(). - */ - -apr_status_t ap_registry_set_server_root(char *dir) -{ - return ap_registry_store_value(REGKEY, "ServerRoot", dir); -} diff --git a/server/mpm/winnt/service.c b/server/mpm/winnt/service.c deleted file mode 100644 index ac88e236c4..0000000000 --- a/server/mpm/winnt/service.c +++ /dev/null @@ -1,1292 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* This module ALONE requires the window message API from user.h - * and the default APR include of windows.h will omit it, so - * preload the API symbols now... - */ - -#define CORE_PRIVATE -#define _WINUSER_ - -#include "httpd.h" -#include "http_log.h" -#include "mpm_winnt.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#ifdef NOUSER -#undef NOUSER -#endif -#undef _WINUSER_ -#include <winuser.h> - -static char *mpm_service_name = NULL; -static char *mpm_display_name = NULL; - -static struct -{ - HANDLE mpm_thread; /* primary thread handle of the apache server */ - HANDLE service_thread; /* thread service/monitor handle */ - DWORD service_thread_id;/* thread service/monitor ID */ - HANDLE signal_monitor; /* service monitor thread signal event */ - SERVICE_STATUS ssStatus; - SERVICE_STATUS_HANDLE hServiceStatus; -} globdat; - -static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint); - -/* The service configuration's is stored under the following trees: - * - * HKLM\System\CurrentControlSet\Services\[service name] - * - * \DisplayName - * \ImagePath (NT Only) - * \Parameters\ConfigArgs - * - * For Win9x, the launch service command is stored under: - * - * HKLM\Software\Microsoft\Windows\CurrentVersion\RunServices\[service name] - */ - - -/* exit() for Win32 is macro mapped (horrible, we agree) that allows us - * to catch the non-zero conditions and inform the console process that - * the application died, and hang on to the console a bit longer. - * - * The macro only maps for http_main.c and other sources that include - * the service.h header, so we best assume it's an error to exit from - * _any_ other module. - * - * If real_exit_code is reset to 0, it will not be set or trigger this - * behavior on exit. All service and child processes are expected to - * reset this flag to zero to avoid undesireable side effects. - */ -int real_exit_code = 1; - -void hold_console_open_on_error(void) -{ - HANDLE hConIn; - HANDLE hConErr; - DWORD result; - time_t start; - time_t remains; - char *msg = "Note the errors or messages above, " - "and press the <ESC> key to exit. "; - CONSOLE_SCREEN_BUFFER_INFO coninfo; - INPUT_RECORD in; - char count[16]; - - if (!real_exit_code) - return; - hConIn = GetStdHandle(STD_INPUT_HANDLE); - hConErr = GetStdHandle(STD_ERROR_HANDLE); - if ((hConIn == INVALID_HANDLE_VALUE) || (hConErr == INVALID_HANDLE_VALUE)) - return; - if (!WriteConsole(hConErr, msg, strlen(msg), &result, NULL) || !result) - return; - if (!GetConsoleScreenBufferInfo(hConErr, &coninfo)) - return; - if (!SetConsoleMode(hConIn, ENABLE_MOUSE_INPUT | 0x80)) - return; - - start = time(NULL); - do - { - while (PeekConsoleInput(hConIn, &in, 1, &result) && result) - { - if (!ReadConsoleInput(hConIn, &in, 1, &result) || !result) - return; - if ((in.EventType == KEY_EVENT) && in.Event.KeyEvent.bKeyDown - && (in.Event.KeyEvent.uChar.AsciiChar == 27)) - return; - if (in.EventType == MOUSE_EVENT - && (in.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK)) - return; - } - remains = ((start + 30) - time(NULL)); - sprintf (count, "%d...", remains); - if (!SetConsoleCursorPosition(hConErr, coninfo.dwCursorPosition)) - return; - if (!WriteConsole(hConErr, count, strlen(count), &result, NULL) - || !result) - return; - } - while ((remains > 0) && WaitForSingleObject(hConIn, 1000) != WAIT_FAILED); -} - -static BOOL die_on_logoff = FALSE; - -static LRESULT CALLBACK monitor_service_9x_proc(HWND hWnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ -/* This is the WndProc procedure for our invisible window. - * When the user shuts down the system, this window is sent - * a signal WM_ENDSESSION. We clean up by signaling Apache - * to shut down, and idle until Apache's primary thread quits. - */ - if ((msg == WM_ENDSESSION) - && (die_on_logoff || (lParam != ENDSESSION_LOGOFF))) - { - signal_parent(0); - if (wParam) - /* Don't leave this message until we are dead! */ - WaitForSingleObject(globdat.mpm_thread, 30000); - return 0; - } - return (DefWindowProc(hWnd, msg, wParam, lParam)); -} - -static DWORD WINAPI monitor_service_9x_thread(void *service_name) -{ - /* When running as a service under Windows 9x, there is no console - * window present, and no ConsoleCtrlHandler to call when the system - * is shutdown. If the WatchWindow thread is created with a NULL - * service_name argument, then the ...SystemMonitor window class is - * used to create the "Apache" window to watch for logoff and shutdown. - * If the service_name is provided, the ...ServiceMonitor window class - * is used to create the window named by the service_name argument, - * and the logoff message is ignored. - */ - WNDCLASS wc; - HWND hwndMain; - MSG msg; - - wc.style = CS_GLOBALCLASS; - wc.lpfnWndProc = monitor_service_9x_proc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = NULL; - wc.hIcon = NULL; - wc.hCursor = NULL; - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - if (service_name) - wc.lpszClassName = "ApacheWin95ServiceMonitor"; - else - wc.lpszClassName = "ApacheWin95SystemMonitor"; - - die_on_logoff = service_name ? FALSE : TRUE; - - if (!RegisterClass(&wc)) - { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), - NULL, "Could not register window class for WatchWindow"); - SetEvent(globdat.signal_monitor); - globdat.service_thread_id = 0; - return 0; - } - - /* Create an invisible window */ - hwndMain = CreateWindow(wc.lpszClassName, - service_name ? (char *) service_name : "Apache", - WS_OVERLAPPEDWINDOW & ~WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, NULL, NULL, NULL, NULL); - - if (!hwndMain) - { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), - NULL, "Could not create WatchWindow"); - SetEvent(globdat.signal_monitor); - globdat.service_thread_id = 0; - return 0; - } - - /* If we succeed, eliminate the console window. - * Signal the parent we are all set up, and - * watch the message queue while the window lives. - */ - FreeConsole(); - SetEvent((HANDLE) globdat.signal_monitor); - while (GetMessage(&msg, NULL, 0, 0)) - { - if (msg.message == WM_CLOSE) - DestroyWindow(hwndMain); - else { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - globdat.service_thread_id = 0; - return 0; -} - - -static BOOL CALLBACK console_control_handler(DWORD ctrl_type) -{ - switch (ctrl_type) - { - case CTRL_BREAK_EVENT: - fprintf(stderr, "Apache server restarting...\n"); - signal_parent(1); - return TRUE; - case CTRL_C_EVENT: - fprintf(stderr, "Apache server interrupted...\n"); - /* for Interrupt signals, shut down the server. - * Tell the system we have dealt with the signal - * without waiting for Apache to terminate. - */ - signal_parent(0); - return TRUE; - - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - /* for Terminate signals, shut down the server. - * Wait for Apache to terminate, but respond - * after a reasonable time to tell the system - * that we did attempt to shut ourself down. - * THESE EVENTS WILL NOT OCCUR UNDER WIN9x! - */ - fprintf(stderr, "Apache server shutdown initiated...\n"); - signal_parent(0); - Sleep(30000); - return TRUE; - } - - /* We should never get here, but this is (mostly) harmless */ - return FALSE; -} - - -static void stop_console_handler(void) -{ - SetConsoleCtrlHandler(console_control_handler, FALSE); -} - - -void mpm_start_console_handler(void) -{ - SetConsoleCtrlHandler(console_control_handler, TRUE); - atexit(stop_console_handler); -} - - -/* Special situation - children of services need to mind their - * P's & Q's and wait quietly, ignoring the mean OS signaling - * shutdown and other horrors, to kill them gracefully... - */ - -static BOOL CALLBACK child_control_handler(DWORD ctrl_type) -{ - switch (ctrl_type) - { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - /* for Interrupt signals, ignore them. - * The system will also signal the parent process, - * which will terminate Apache. - */ - return TRUE; - - case CTRL_CLOSE_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - /* for Shutdown signals, ignore them, but... . - * The system will also signal the parent process, - * which will terminate Apache, so we need to wait. - */ - Sleep(30000); - return TRUE; - } - - /* We should never get here, but this is (mostly) harmless */ - return FALSE; -} - - -static void stop_child_console_handler(void) -{ - SetConsoleCtrlHandler(child_control_handler, FALSE); -} - - -void mpm_start_child_console_handler(void) -{ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) { - FreeConsole(); - } - else - { - SetConsoleCtrlHandler(child_control_handler, TRUE); - atexit(stop_child_console_handler); - } -} - - -/********************************** - WinNT service control management - **********************************/ - -static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint) -{ - static int checkPoint = 1; - int rv = APR_SUCCESS; - - if (globdat.hServiceStatus) - { - if (currentState == SERVICE_RUNNING) - globdat.ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; - else - globdat.ssStatus.dwControlsAccepted = 0; - - globdat.ssStatus.dwCurrentState = currentState; - globdat.ssStatus.dwWin32ExitCode = exitCode; - - if ( ( currentState == SERVICE_RUNNING ) || - ( currentState == SERVICE_STOPPED ) ) - { - globdat.ssStatus.dwWaitHint = 0; - globdat.ssStatus.dwCheckPoint = 0; - } - else - { - if(waitHint) - globdat.ssStatus.dwWaitHint = waitHint; - globdat.ssStatus.dwCheckPoint = ++checkPoint; - } - rv = SetServiceStatus(globdat.hServiceStatus, &globdat.ssStatus); - } - return(rv); -} - - -/* handle the SCM's ControlService() callbacks to our service */ - -static VOID WINAPI service_nt_ctrl(DWORD dwCtrlCode) -{ - if (dwCtrlCode == SERVICE_CONTROL_STOP) - { - ap_start_shutdown(); - globdat.ssStatus.dwCurrentState = SERVICE_STOP_PENDING; - ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 3000); - return; - } - if (dwCtrlCode == SERVICE_APACHE_RESTART) - { - ap_start_restart(1); - globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING; - ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000); - return; - } - - ReportStatusToSCMgr(globdat.ssStatus.dwCurrentState, NO_ERROR, 0); -} - - -long __stdcall service_stderr_thread(LPVOID hPipe) -{ - HANDLE hPipeRead = (HANDLE) hPipe; - HANDLE hEventSource; - char errbuf[256]; - char *errmsg = errbuf; - const char *errarg[9]; - DWORD errlen = 0; - DWORD errres; - HKEY hk; - - errarg[0] = "The Apache service named"; - errarg[1] = mpm_display_name; - errarg[2] = "reported the following error:\r\n>>>"; - errarg[3] = errmsg; - errarg[4] = "<<<\r\n before the error.log file could be opened.\r\n"; - errarg[5] = "More information may be available in the error.log file."; - errarg[6] = NULL; - errarg[7] = NULL; - errarg[8] = NULL; - - /* What are we going to do in here, bail on the user? not. */ - if (!RegCreateKey(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services" - "\\EventLog\\Application\\Apache Service", &hk)) - { - /* The stock message file */ - char *netmsgkey = "%SystemRoot%\\System32\\netmsg.dll"; - DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | - EVENTLOG_INFORMATION_TYPE; - - RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ, - (LPBYTE) netmsgkey, strlen(netmsgkey) + 1); - - RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, - (LPBYTE) &dwData, sizeof(dwData)); - RegCloseKey(hk); - } - - hEventSource = RegisterEventSource(NULL, "Apache Service"); - - while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1)) - { - if ((errmsg > errbuf) || !isspace(*errmsg)) - { - ++errlen; - ++errmsg; - if ((*(errmsg - 1) == '\n') || (errlen == sizeof(errbuf) - 1)) - { - while (errlen && isspace(errbuf[errlen - 1])) - --errlen; - errbuf[errlen] = '\0'; - - /* Generic message: '%1 %2 %3 %4 %5 %6 %7 %8 %9' - * The event code in netmsg.dll is 3299 - */ - ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, - 3299, NULL, 9, 0, errarg, NULL); - errmsg = errbuf; - errlen = 0; - } - } - } - - CloseHandle(hPipeRead); - return 0; -} - - -/* service_nt_main_fn is outside of the call stack and outside of the - * primary server thread... so now we _really_ need a placeholder! - * The winnt_rewrite_args has created and shared mpm_new_argv with us. - */ -extern apr_array_header_t *mpm_new_argv; - -static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv) -{ - HANDLE waitfor[2]; - HANDLE hCurrentProcess; - HANDLE hPipeRead = NULL; - HANDLE hPipeWrite = NULL; - HANDLE hPipeReadDup; - HANDLE thread; - DWORD threadid; - SECURITY_ATTRIBUTES sa = {0}; - const char *ignored; - - /* args and service names live in the same pool */ - mpm_service_set_name(mpm_new_argv->cont, &ignored, argv[0]); - - globdat.ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING; - globdat.ssStatus.dwServiceSpecificExitCode = 0; - globdat.ssStatus.dwCheckPoint = 1; - - if (!(globdat.hServiceStatus = RegisterServiceCtrlHandler(argv[0], service_nt_ctrl))) - { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), - NULL, "Failure registering service handler"); - PulseEvent(globdat.signal_monitor); - return; - } - - ReportStatusToSCMgr(globdat.ssStatus.dwCurrentState, // service state - NO_ERROR, // exit code - 3000); // wait hint, 3 seconds more - - /* Create a pipe to send stderr messages to the system error log */ - hCurrentProcess = GetCurrentProcess(); - if (CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) - { - if (DuplicateHandle(hCurrentProcess, hPipeRead, hCurrentProcess, - &hPipeReadDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - CloseHandle(hPipeRead); - hPipeRead = hPipeReadDup; - thread = CreateThread(NULL, 0, service_stderr_thread, - (LPVOID) hPipeRead, 0, &threadid); - if (thread) - { - int fh; - FILE *fl; - CloseHandle(thread); - fflush(stderr); - SetStdHandle(STD_ERROR_HANDLE, hPipeWrite); - - fh = _open_osfhandle((long) STD_ERROR_HANDLE, - _O_WRONLY | _O_BINARY); - dup2(fh, STDERR_FILENO); - fl = _fdopen(STDERR_FILENO, "wcb"); - memcpy(stderr, fl, sizeof(FILE)); - } - else - { - CloseHandle(hPipeRead); - CloseHandle(hPipeWrite); - hPipeWrite = NULL; - } - } - else - { - CloseHandle(hPipeRead); - CloseHandle(hPipeWrite); - hPipeWrite = NULL; - } - } - - /* We need to append all the command arguments passed via StartService() - * to our running service... which just got here via the SCM... - * but we hvae no interest in argv[0] for the mpm_new_argv list. - */ - if (argc > 1) - { - char **cmb_data; - - mpm_new_argv->nalloc = mpm_new_argv->nelts + argc - 1; - cmb_data = apr_palloc(mpm_new_argv->cont, - mpm_new_argv->nalloc * sizeof(const char *)); - - /* mpm_new_argv remains first (of lower significance) */ - memcpy (cmb_data, mpm_new_argv->elts, - mpm_new_argv->elt_size * mpm_new_argv->nelts); - - /* Service args follow from StartService() invocation */ - memcpy (cmb_data + mpm_new_argv->nelts, argv + 1, - mpm_new_argv->elt_size * (argc - 1)); - - /* The replacement arg list is complete */ - mpm_new_argv->elts = (char *)cmb_data; - mpm_new_argv->nelts = mpm_new_argv->nalloc; - } - - /* Let the main thread continue now... but hang on to the - * signal_monitor event so we can take further action - */ - SetEvent(globdat.signal_monitor); - - waitfor[0] = globdat.signal_monitor; - waitfor[1] = globdat.mpm_thread; - WaitForMultipleObjects(2, waitfor, FALSE, INFINITE); - /* The process is ready to terminate, or already has */ - - CloseHandle(hPipeWrite); -} - - -DWORD WINAPI service_nt_dispatch_thread(LPVOID nada) -{ - apr_status_t rv = APR_SUCCESS; - - SERVICE_TABLE_ENTRY dispatchTable[] = - { - { "", service_nt_main_fn }, - { NULL, NULL } - }; - - if (!StartServiceCtrlDispatcher(dispatchTable)) - { - /* This is a genuine failure of the SCM. */ - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Error starting service control dispatcher"); - } - - globdat.service_thread_id = 0; - return (rv); -} - - -apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name, - const char *set_name) -{ - char *key_name; - apr_status_t rv; - - /* ### Needs improvement, on Win2K the user can _easily_ - * change the display name to a string that doesn't reflect - * the internal service name + whitespace! - */ - mpm_service_name = apr_palloc(p, strlen(set_name) + 1); - apr_collapse_spaces((char*) mpm_service_name, set_name); - key_name = apr_psprintf(p, SERVICECONFIG, mpm_service_name); - rv = ap_registry_get_value(p, key_name, "DisplayName", &mpm_display_name); - if (rv != APR_SUCCESS) { - /* Take the given literal name if there is no service entry */ - mpm_display_name = apr_pstrdup(p, set_name); - } - *display_name = mpm_display_name; - return rv; -} - - -apr_status_t mpm_merge_service_args(apr_pool_t *p, - apr_array_header_t *args, - int fixed_args) -{ - apr_array_header_t *svc_args = NULL; - char conf_key[MAX_PATH]; - char **cmb_data; - apr_status_t rv; - - apr_snprintf(conf_key, sizeof(conf_key), SERVICEPARAMS, mpm_service_name); - rv = ap_registry_get_array(p, conf_key, "ConfigArgs", &svc_args); - if (rv != APR_SUCCESS) { - if (rv == ERROR_FILE_NOT_FOUND) { - ap_log_error(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, NULL, - "No ConfigArgs registered for %s, perhaps " - "this service is not installed?", - mpm_service_name); - return APR_SUCCESS; - } - else - return (rv); - } - - if (!svc_args || svc_args->nelts == 0) { - return (APR_SUCCESS); - } - - /* Now we have the mpm_service_name arg, and the mpm_runservice_nt() - * call appended the arguments passed by StartService(), so it's - * time to _prepend_ the default arguments for the server from - * the service's default arguments (all others override them)... - */ - args->nalloc = args->nelts + svc_args->nelts; - cmb_data = apr_palloc(p, args->nalloc * sizeof(const char *)); - - /* First three args (argv[0], -f, path) remain first */ - memcpy(cmb_data, args->elts, args->elt_size * fixed_args); - - /* Service args follow from service registry array */ - memcpy(cmb_data + fixed_args, svc_args->elts, - svc_args->elt_size * svc_args->nelts); - - /* Remaining new args follow */ - memcpy(cmb_data + fixed_args + svc_args->nelts, - (const char **)args->elts + fixed_args, - args->elt_size * (args->nelts - fixed_args)); - - args->elts = (char *)cmb_data; - args->nelts = args->nalloc; - - return APR_SUCCESS; -} - - -void service_stopped(void) -{ - /* Still have a thread & window to clean up, so signal now */ - if (globdat.service_thread_id) - { - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - ReportStatusToSCMgr(SERVICE_STOPPED, // service state - NO_ERROR, // exit code - 0); // wait hint - - /* Cause the service_nt_main_fn to complete */ - SetEvent(globdat.signal_monitor); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - RegisterServiceProcess(0, 0); - PostThreadMessage(globdat.service_thread_id, WM_CLOSE, 0, 0); - } - - WaitForSingleObject(globdat.service_thread, 5000); - CloseHandle(globdat.service_thread); - } -} - - -apr_status_t mpm_service_to_start(const char **display_name) -{ - HANDLE waitfor[2]; - - globdat.mpm_thread = GetCurrentThread(); - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - globdat.signal_monitor = CreateEvent(NULL, FALSE, FALSE, NULL); - if (globdat.signal_monitor) - globdat.service_thread = CreateThread(NULL, 0, - service_nt_dispatch_thread, - NULL, 0, - &globdat.service_thread_id); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - if (!RegisterServiceProcess(0, 1)) - return GetLastError(); - - globdat.signal_monitor = CreateEvent(NULL, FALSE, FALSE, NULL); - if (globdat.signal_monitor) - globdat.service_thread = CreateThread(NULL, 0, - monitor_service_9x_thread, - (LPVOID) mpm_service_name, 0, - &globdat.service_thread_id); - } - - if (globdat.signal_monitor && globdat.service_thread) - { - waitfor[0] = globdat.signal_monitor; - waitfor[1] = globdat.service_thread; - - /* SetEvent(globdat.signal_monitor) to clean up the SCM thread */ - if (WaitForMultipleObjects(2, waitfor, FALSE, 10000) != WAIT_OBJECT_0) { - CloseHandle(globdat.service_thread); - return APR_ENOTHREAD; - } - } - - if (globdat.service_thread_id) - atexit(service_stopped); - else if (globdat.service_thread) - CloseHandle(globdat.service_thread); - - *display_name = mpm_display_name; - return APR_SUCCESS; -} - - -apr_status_t mpm_service_started(void) -{ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - ReportStatusToSCMgr(SERVICE_RUNNING, // service state - NO_ERROR, // exit code - 0); // wait hint - } - return APR_SUCCESS; -} - - -void mpm_service_stopping(void) -{ - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - ReportStatusToSCMgr(SERVICE_STOP_PENDING, // service state - NO_ERROR, // exit code - 3000); // wait hint -} - - -apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc, - const char * const * argv) -{ - char key_name[MAX_PATH]; - char exe_path[MAX_PATH]; - char *launch_cmd; - apr_status_t(rv); - - printf("Installing the %s service\n", mpm_display_name); - - if (GetModuleFileName(NULL, exe_path, sizeof(exe_path)) == 0) - { - apr_status_t rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "GetModuleFileName failed"); - return rv; - } - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - SC_HANDLE schService; - SC_HANDLE schSCManager; - - // TODO: Determine the minimum permissions required for security - schSCManager = OpenSCManager(NULL, NULL, /* local, default database */ - SC_MANAGER_ALL_ACCESS); - if (!schSCManager) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Failed to open the WinNT service manager"); - return (rv); - } - - launch_cmd = apr_psprintf(ptemp, "\"%s\" -k runservice", exe_path); - - /* RPCSS is the Remote Procedure Call (RPC) Locator required for DCOM - * communication pipes. I am far from convinced we should add this to - * the default service dependencies, but be warned that future apache - * modules or ISAPI dll's may depend on it. - */ - schService = CreateService(schSCManager, // SCManager database - mpm_service_name, // name of service - mpm_display_name, // name to display - SERVICE_ALL_ACCESS, // access required - SERVICE_WIN32_OWN_PROCESS, // service type - SERVICE_AUTO_START, // start type - SERVICE_ERROR_NORMAL, // error control type - launch_cmd, // service's binary - NULL, // no load svc group - NULL, // no tag identifier - "Tcpip\0Afd\0", // dependencies - NULL, // use SYSTEM account - NULL); // no password - - if (!schService) - { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Failed to create WinNT Service Profile"); - CloseServiceHandle(schSCManager); - return (rv); - } - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - /* Store the launch command in the registry */ - launch_cmd = apr_psprintf(ptemp, "\"%s\" -n %s -k runservice", - exe_path, mpm_service_name); - rv = ap_registry_store_value(SERVICECONFIG9X, mpm_service_name, launch_cmd); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to add the RunServices registry entry.", - mpm_display_name); - return (rv); - } - - apr_snprintf(key_name, sizeof(key_name), SERVICECONFIG, mpm_service_name); - rv = ap_registry_store_value(key_name, "DisplayName", mpm_display_name); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to store DisplayName in the registry.", - mpm_display_name); - return (rv); - } - } - - /* For both WinNT & Win9x store the service ConfigArgs in the registry... - */ - apr_snprintf(key_name, sizeof(key_name), SERVICEPARAMS, mpm_service_name); - rv = ap_registry_store_array(ptemp, key_name, "ConfigArgs", argc, argv); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to store the ConfigArgs in the registry.", - mpm_display_name); - return (rv); - } - printf("The %s service is successfully installed.\n", mpm_display_name); -} - - -apr_status_t mpm_service_uninstall(void) -{ - char key_name[MAX_PATH]; - apr_status_t rv; - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - SC_HANDLE schService; - SC_HANDLE schSCManager; - - printf("Removing the %s service\n", mpm_display_name); - - // TODO: Determine the minimum permissions required for security - schSCManager = OpenSCManager(NULL, NULL, /* local, default database */ - SC_MANAGER_ALL_ACCESS); - if (!schSCManager) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Failed to open the WinNT service manager."); - return (rv); - } - - schService = OpenService(schSCManager, mpm_service_name, SERVICE_ALL_ACCESS); - - if (!schService) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: OpenService failed", mpm_display_name); - return (rv); - } - - /* assure the service is stopped before continuing - * - * This may be out of order... we might not be able to be - * granted all access if the service is running anyway. - * - * And do we want to make it *this easy* for them - * to uninstall their service unintentionally? - */ - // ap_stop_service(schService); - - if (DeleteService(schService) == 0) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to delete the service.", mpm_display_name); - return (rv); - } - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - printf("Removing the %s service\n", mpm_display_name); - - /* TODO: assure the service is stopped before continuing */ - - if (ap_registry_delete_value(SERVICECONFIG9X, mpm_service_name)) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to remove the RunServices registry " - "entry.", mpm_display_name); - return (rv); - } - - /* we blast Services/us, not just the Services/us/Parameters branch */ - apr_snprintf(key_name, sizeof(key_name), SERVICECONFIG, mpm_service_name); - if (ap_registry_delete_key(key_name)) - { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to remove the service config from the " - "registry.", mpm_display_name); - return (rv); - } - } - printf("The %s service has been removed successfully.\n", mpm_display_name); - return APR_SUCCESS; -} - - -/* signal_service_transition is a simple thunk to signal the service - * and monitor it's successful transition. If the signal passed is 0, - * then the caller is assumed to already have performed some service - * operation to be monitored (such as StartService), and no actual - * ControlService signal is sent. - */ - -static int signal_service_transition(SC_HANDLE schService, DWORD signal, DWORD pending, DWORD complete) -{ - if (signal && !ControlService(schService, signal, &globdat.ssStatus)) - return FALSE; - - do { - Sleep(1000); - if (!QueryServiceStatus(schService, &globdat.ssStatus)) - return FALSE; - } while (globdat.ssStatus.dwCurrentState == pending); - - return (globdat.ssStatus.dwCurrentState == complete); -} - - -apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc, - const char * const * argv) -{ - apr_status_t rv; - - printf("Starting the %s service\n", mpm_display_name); - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - char **start_argv; - SC_HANDLE schService; - SC_HANDLE schSCManager; - - // TODO: Determine the minimum permissions required for security - schSCManager = OpenSCManager(NULL, NULL, /* local, default database */ - SC_MANAGER_ALL_ACCESS); - if (!schSCManager) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "Failed to open the WinNT service manager"); - return (rv); - } - - schService = OpenService(schSCManager, mpm_service_name, - SERVICE_START | SERVICE_QUERY_STATUS); - if (!schService) { - rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "%s: Failed to open the service.", mpm_display_name); - CloseServiceHandle(schSCManager); - return (rv); - } - - if (QueryServiceStatus(schService, &globdat.ssStatus) - && (globdat.ssStatus.dwCurrentState == SERVICE_RUNNING)) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, 0, NULL, - "Service %s is already started!", mpm_display_name); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return 0; - } - - argc += 1; - start_argv = apr_palloc(ptemp, argc * sizeof(const char **)); - start_argv[0] = mpm_service_name; - if (argc > 1) - memcpy(start_argv + 1, argv, (argc - 1) * sizeof(const char **)); - - rv = APR_EINIT; - if (StartService(schService, argc, start_argv) - && signal_service_transition(schService, 0, /* test only */ - SERVICE_START_PENDING, - SERVICE_RUNNING)) - rv = APR_SUCCESS; - - if (rv != APR_SUCCESS) - rv = apr_get_os_error(); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */ - { - STARTUPINFO si; /* Filled in prior to call to CreateProcess */ - PROCESS_INFORMATION pi; /* filled in on call to CreateProcess */ - char exe_path[MAX_PATH]; - char *pCommand; - int i; - - /* Locate the active top level window named service_name - * provided the class is ApacheWin95ServiceMonitor - */ - if (FindWindow("ApacheWin95ServiceMonitor", mpm_service_name)) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, 0, NULL, - "Service %s is already started!", mpm_display_name); - return 0; - } - - /* This may not appear intuitive, but Win9x will not allow a process - * to detach from the console without releasing the entire console. - * Ergo, we must spawn a new process for the service to get back our - * console window. - * The config is pre-flighted, so there should be no danger of failure. - */ - - if (GetModuleFileName(NULL, exe_path, sizeof(exe_path)) == 0) - { - apr_status_t rv = apr_get_os_error(); - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL, - "GetModuleFileName failed"); - return rv; - } - - pCommand = apr_psprintf(ptemp, "\"%s\" -n %s -k runservice", - exe_path, mpm_service_name); - for (i = 0; i < argc; ++i) { - pCommand = apr_pstrcat(ptemp, pCommand, - " \"", argv[i], "\"", NULL); - } - - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - si.cb = sizeof(si); - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; /* This might be redundant */ - - rv = APR_EINIT; - if (CreateProcess(NULL, pCommand, NULL, NULL, FALSE, - DETACHED_PROCESS, /* Creation flags */ - NULL, NULL, &si, &pi)) - { - DWORD code; - while (GetExitCodeProcess(pi.hProcess, &code) == STILL_ACTIVE) { - if (FindWindow("ApacheWin95ServiceMonitor", mpm_service_name)) { - rv = APR_SUCCESS; - break; - } - Sleep (1000); - } - } - - if (rv != APR_SUCCESS) - rv = apr_get_os_error(); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - - if (rv == APR_SUCCESS) - printf("The %s service is running.\n", mpm_display_name); - else - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, - "%s: Failed to start the service process.", - mpm_display_name); - - return rv; -} - - -/* signal is zero to stop, non-zero for restart */ - -void mpm_signal_service(apr_pool_t *ptemp, int signal) -{ - int success = FALSE; - - if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - SC_HANDLE schService; - SC_HANDLE schSCManager; - - schSCManager = OpenSCManager(NULL, NULL, // default machine & database - SC_MANAGER_ALL_ACCESS); - - if (!schSCManager) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL, - "Failed to open the NT Service Manager"); - return; - } - - schService = OpenService(schSCManager, mpm_service_name, - SERVICE_ALL_ACCESS); - - if (schService == NULL) { - /* Could not open the service */ - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL, - "Failed to open the %s Service", mpm_display_name); - CloseServiceHandle(schSCManager); - return; - } - - if (!QueryServiceStatus(schService, &globdat.ssStatus)) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL, - "Query of Service %s failed", mpm_display_name); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return; - } - - if (!signal && (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED)) { - printf("The %s service is not started.\n", mpm_display_name); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return; - } - - printf("The %s service is %s.\n", mpm_display_name, - signal ? "restarting" : "stopping"); - - if (!signal) - success = signal_service_transition(schService, - SERVICE_CONTROL_STOP, - SERVICE_STOP_PENDING, - SERVICE_STOPPED); - else if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED) { - mpm_service_start(ptemp, 0, NULL); - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return; - } - else - success = signal_service_transition(schService, - SERVICE_APACHE_RESTART, - SERVICE_START_PENDING, - SERVICE_RUNNING); - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - } - else /* !isWindowsNT() */ - { - DWORD service_pid; - HANDLE hwnd; - char prefix[20]; - /* Locate the active top level window named service_name - * provided the class is ApacheWin95ServiceMonitor - */ - hwnd = FindWindow("ApacheWin95ServiceMonitor", mpm_service_name); - if (hwnd && GetWindowThreadProcessId(hwnd, &service_pid)) - globdat.ssStatus.dwCurrentState = SERVICE_RUNNING; - else - { - globdat.ssStatus.dwCurrentState = SERVICE_STOPPED; - if (!signal) { - printf("The %s service is not started.\n", mpm_display_name); - return; - } - } - - printf("The %s service is %s.\n", mpm_display_name, - signal ? "restarting" : "stopping"); - - apr_snprintf(prefix, sizeof(prefix), "ap%ld", (long)service_pid); - setup_signal_names(prefix); - - if (!signal) - { - int ticks = 60; - ap_start_shutdown(); - while (--ticks) - { - if (!IsWindow(hwnd)) { - success = TRUE; - break; - } - Sleep(1000); - } - } - else /* !stop */ - { - /* TODO: Aught to add a little test to the restart logic, and - * store the restart counter in the window's user dword. - * Then we can hang on and report a successful restart. But - * that's a project for another day. - */ - if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED) { - mpm_service_start(ptemp, 0, NULL); - return; - } - else { - success = TRUE; - ap_start_restart(1); - } - } - } - - if (success) - printf("The %s service has %s.\n", mpm_display_name, - signal ? "restarted" : "stopped"); - else - printf("Failed to %s the %s service.\n", - signal ? "restart" : "stop", mpm_display_name); -} diff --git a/server/mpm_common.c b/server/mpm_common.c deleted file mode 100644 index d024c24978..0000000000 --- a/server/mpm_common.c +++ /dev/null @@ -1,344 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* The purpose of this file is to store the code that MOST mpm's will need - * this does not mean a function only goes into this file if every MPM needs - * it. It means that if a function is needed by more than one MPM, and - * future maintenance would be served by making the code common, then the - * function belongs here. - * - * This is going in src/main because it is not platform specific, it is - * specific to multi-process servers, but NOT to Unix. Which is why it - * does not belong in src/os/unix - */ - -#include "apr.h" -#include "apr_thread_proc.h" -#include "apr_signal.h" - -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_main.h" -#include "mpm.h" -#include "mpm_common.h" -#include "ap_mpm.h" - -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#ifdef HAVE_GRP_H -#include <grp.h> -#endif - -#ifdef AP_MPM_NEEDS_RECLAIM_CHILD_PROCESSES -void ap_reclaim_child_processes(int terminate) -{ - int i; - long int waittime = 1024 * 16; /* in usecs */ - apr_status_t waitret; - int tries; - int not_dead_yet; - int max_daemons; - - ap_mpm_query(AP_MPMQ_MAX_DAEMONS, &max_daemons); - MPM_SYNC_CHILD_TABLE(); - - 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. - */ - waittime = waittime * 4; - apr_sleep(waittime); - - /* now see who is done */ - not_dead_yet = 0; - for (i = 0; i < max_daemons; ++i) { - pid_t pid = MPM_CHILD_PID(i); - apr_proc_t proc; - - if (pid == 0) - continue; - - proc.pid = pid; - waitret = apr_proc_wait(&proc, APR_NOWAIT); - if (waitret != APR_CHILD_NOTDONE) { - MPM_NOTE_CHILD_KILLED(i); - continue; - } - ++not_dead_yet; - switch (tries) { - case 1: /* 16ms */ - case 2: /* 82ms */ - case 3: /* 344ms */ - case 4: /* 16ms */ - break; - case 5: /* 82ms */ - case 6: /* 344ms */ - case 7: /* 1.4sec */ - /* ok, now it's being annoying */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, - 0, ap_server_conf, - "child process %ld still did not exit, sending a SIGTERM", - (long)pid); - kill(pid, SIGTERM); - break; - case 8: /* 6 sec */ - /* die child scum */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, - 0, ap_server_conf, - "child process %ld still did not exit, sending a SIGKILL", - (long)pid); -#ifndef BEOS - kill(pid, SIGKILL); -#else - /* sending a SIGKILL kills the entire team on BeOS, and as - * httpd thread is part of that team it removes any chance - * of ever doing a restart. To counter this I'm changing to - * use a kinder, gentler way of killing a specific thread - * that is just as effective. - */ - kill_thread(pid); -#endif - 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, - 0, ap_server_conf, - "could not make child process %ld exit, " - "attempting to continue anyway", (long)pid); - break; - } - } -#if APR_HAS_OTHER_CHILD - apr_proc_other_child_check(); -#endif - if (!not_dead_yet) { - /* nothing left to wait for */ - break; - } - } -} -#endif /* NEED_RECLAIM_CHILD_PROCESSES */ - -/* 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; - -void ap_wait_or_timeout(apr_wait_t *status, apr_proc_t *ret, apr_pool_t *p) -{ - apr_status_t rv; - - ++wait_or_timeout_counter; - if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) { - wait_or_timeout_counter = 0; -#if APR_HAS_OTHER_CHILD - apr_proc_probe_writable_fds(); -#endif - } - rv = apr_proc_wait_all_procs(ret, status, APR_NOWAIT, p); - if (APR_STATUS_IS_EINTR(rv)) { - ret->pid = -1; - return; - } - if (APR_STATUS_IS_CHILD_DONE(rv)) { - return; - } -#ifdef NEED_WAITPID - if ((ret = reap_children(status)) > 0) { - return; - } -#endif - apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL); - ret->pid = -1; - return; -} - -void ap_process_child_status(apr_proc_t *pid, apr_wait_t status) -{ - int signum = WTERMSIG(status); - const char *sigdesc = apr_signal_get_description(signum); - - /* 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, 0, ap_server_conf, - "Child %ld returned a Fatal error..." APR_EOL_STR - "Apache is exiting!", - (long)pid->pid); - exit(APEXIT_CHILDFATAL); - } - - if (WIFSIGNALED(status)) { - switch (signum) { - case SIGTERM: - case SIGHUP: - case SIGWINCH: - case SIGKILL: - break; - default: -#ifdef WCOREDUMP - if (WCOREDUMP(status)) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, - 0, ap_server_conf, - "child pid %ld exit signal %s (%d), " - "possible coredump in %s", - (long)pid->pid, sigdesc, signum, - ap_coredump_dir); - } - else -#endif - { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, - 0, ap_server_conf, - "child pid %ld exit signal %s (%d)", - (long)pid->pid, sigdesc, signum); - } - } - } -} - -#if defined(TCP_NODELAY) && !defined(MPE) && !defined(TPF) -void ap_sock_disable_nagle(apr_socket_t *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. - */ - apr_status_t status = apr_setsocketopt(s, APR_TCP_NODELAY, 1); - - if (status != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf, - "setsockopt: (TCP_NODELAY)"); - } -} -#endif - -AP_DECLARE(uid_t) ap_uname2id(const char *name) -{ - struct passwd *ent; - - if (name[0] == '#') - return (atoi(&name[1])); - - if (!(ent = getpwnam(name))) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%s: bad user name %s", ap_server_argv0, name); - exit(1); - } - return (ent->pw_uid); -} - -AP_DECLARE(gid_t) ap_gname2id(const char *name) -{ - struct group *ent; - - if (name[0] == '#') - return (atoi(&name[1])); - - if (!(ent = getgrnam(name))) { - ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%s: bad group name %s", ap_server_argv0, name); exit(1); - } - return (ent->gr_gid); -} - -#ifndef HAVE_INITGROUPS -int initgroups(const char *name, gid_t basegid) -{ -#if defined(QNX) || defined(MPE) || defined(BEOS) || defined(_OSD_POSIX) || defined(TPF) || defined(__TANDEM) || defined(OS2) || defined(WIN32) -/* QNX, MPE and BeOS do not appear to support supplementary groups. */ - return 0; -#else /* ndef QNX */ - gid_t groups[NGROUPS_MAX]; - struct group *g; - int index = 0; - - setgrent(); - - groups[index++] = basegid; - - while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) - if (g->gr_gid != basegid) { - char **names; - - for (names = g->gr_mem; *names != NULL; ++names) - if (!strcmp(*names, name)) - groups[index++] = g->gr_gid; - } - - endgrent(); - - return setgroups(index, groups); -#endif /* def QNX */ -} -#endif /* def NEED_INITGROUPS */ - - diff --git a/server/protocol.c b/server/protocol.c deleted file mode 100644 index 93db7c32d0..0000000000 --- a/server/protocol.c +++ /dev/null @@ -1,1176 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_protocol.c --- routines which directly communicate with the client. - * - * Code originally by Rob McCool; much redone by Robert S. Thau - * and the Apache Software Foundation. - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_buckets.h" -#include "apr_lib.h" -#include "apr_signal.h" - -#define APR_WANT_STDIO /* for sscanf */ -#define APR_WANT_STRFUNC -#define APR_WANT_MEMFUNC -#include "apr_want.h" - -#define CORE_PRIVATE -#include "util_filter.h" -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "http_request.h" -#include "http_vhost.h" -#include "http_log.h" /* For errors detected in basic auth common - * support code... */ -#include "util_date.h" /* For parseHTTPdate and BAD_DATE */ -#include "util_charset.h" -#include "util_ebcdic.h" - -#if APR_HAVE_STDARG_H -#include <stdarg.h> -#endif -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif - - -APR_HOOK_STRUCT( - APR_HOOK_LINK(post_read_request) - APR_HOOK_LINK(log_transaction) - APR_HOOK_LINK(http_method) - APR_HOOK_LINK(default_port) -) - -/* - * Builds the content-type that should be sent to the client from the - * content-type specified. The following rules are followed: - * - if type is NULL, type is set to ap_default_type(r) - * - if charset adding is disabled, stop processing and return type. - * - then, if there are no parameters on type, add the default charset - * - return type - */ -AP_DECLARE(const char *)ap_make_content_type(request_rec *r, const char *type) -{ - static const char *needcset[] = { - "text/plain", - "text/html", - NULL }; - const char **pcset; - core_dir_config *conf = - (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); - - if (!type) { - type = ap_default_type(r); - } - if (conf->add_default_charset != ADD_DEFAULT_CHARSET_ON) { - return type; - } - - if (ap_strcasestr(type, "charset=") != NULL) { - /* already has parameter, do nothing */ - /* XXX we don't check the validity */ - ; - } - else { - /* see if it makes sense to add the charset. At present, - * we only add it if the Content-type is one of needcset[] - */ - for (pcset = needcset; *pcset ; pcset++) { - if (ap_strcasestr(type, *pcset) != NULL) { - type = apr_pstrcat(r->pool, type, "; charset=", - conf->add_default_charset_name, NULL); - break; - } - } - } - return type; -} - -AP_DECLARE(void) ap_set_content_length(request_rec *r, apr_off_t clength) -{ - r->clength = clength; - apr_table_setn(r->headers_out, "Content-Length", - apr_psprintf(r->pool, "%" APR_OFF_T_FMT, clength)); -} - -/* - * Return the latest rational time from a request/mtime (modification time) - * pair. We return the mtime unless it's in the future, in which case we - * return the current time. We use the request time as a reference in order - * to limit the number of calls to time(). We don't check for futurosity - * unless the mtime is at least as new as the reference. - */ -AP_DECLARE(apr_time_t) ap_rationalize_mtime(request_rec *r, apr_time_t mtime) -{ - apr_time_t now; - - /* For all static responses, it's almost certain that the file was - * last modified before the beginning of the request. So there's - * no reason to call time(NULL) again. But if the response has been - * created on demand, then it might be newer than the time the request - * started. In this event we really have to call time(NULL) again - * so that we can give the clients the most accurate Last-Modified. If we - * were given a time in the future, we return the current time - the - * Last-Modified can't be in the future. - */ - now = (mtime < r->request_time) ? r->request_time : apr_time_now(); - return (mtime > now) ? now : mtime; -} - -/* Get a line of protocol input, including any continuation lines - * caused by MIME folding (or broken clients) if fold != 0, and place it - * in the buffer s, of size n bytes, without the ending newline. - * - * Returns -1 on error, or the length of s. - * - * Notes: Because the buffer uses 1 char for NUL, the most we can return is - * (n - 1) actual characters. - * - * If no LF is detected on the last line due to a dropped connection - * or a full buffer, that's considered an error. - */ -AP_CORE_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold) -{ - char *pos = s; - char *last_char; - char *beyond_buff = s + n; - const char *temp; - int retval; - int total = 0; - int looking_ahead = 0; - apr_size_t zero = 0; - apr_size_t length; - conn_rec *c = r->connection; - core_request_config *req_cfg; - apr_bucket_brigade *b; - apr_bucket *e; - - req_cfg = (core_request_config *) - ap_get_module_config(r->request_config, &core_module); - b = req_cfg->bb; - /* make sure it's empty unless we're folding */ - AP_DEBUG_ASSERT(fold || APR_BRIGADE_EMPTY(b)); - - while (1) { - if (APR_BRIGADE_EMPTY(b)) { - if ((retval = ap_get_brigade(c->input_filters, b, AP_MODE_BLOCKING, &zero)) != APR_SUCCESS || - APR_BRIGADE_EMPTY(b)) { - apr_brigade_destroy(b); - return -1; - } - } - e = APR_BRIGADE_FIRST(b); - if (e->length == 0) { - apr_bucket_delete(e); - continue; - } - retval = apr_bucket_read(e, &temp, &length, APR_BLOCK_READ); - if (retval != APR_SUCCESS) { - apr_brigade_destroy(b); - ap_log_rerror(APLOG_MARK, APLOG_ERR, retval, r, "apr_bucket_read() failed"); - if (total) { - break; /* report previously-read data to caller, do ap_xlate_proto_to_ascii() */ - } - else { - return -1; - } - } - - if ((looking_ahead) && (*temp != APR_ASCII_BLANK) && (*temp != APR_ASCII_TAB)) { - /* can't fold because next line isn't indented, - * so return what we have. lookahead brigade is - * stashed on req_cfg->bb - */ - AP_DEBUG_ASSERT(!APR_BRIGADE_EMPTY(req_cfg->bb)); - break; - } - last_char = pos + length - 1; - if (last_char < beyond_buff) { - memcpy(pos, temp, length); - apr_bucket_delete(e); - } - else { - /* input line was larger than the caller's buffer */ - apr_brigade_destroy(b); - - /* don't need to worry about req_cfg->bb being bogus. - * the request is about to die, and ErrorDocument - * redirects get a new req_cfg->bb - */ - - return -1; - } - - pos = last_char; /* Point at the last character */ - - if (*pos == APR_ASCII_LF) { /* Did we get a full line of input? */ - - if (pos > s && *(pos - 1) == APR_ASCII_CR) { - --pos; /* zap optional CR before LF */ - } - - /* - * Trim any extra trailing spaces or tabs except for the first - * space or tab at the beginning of a blank string. This makes - * it much easier to check field values for exact matches, and - * saves memory as well. Terminate string at end of line. - */ - while (pos > (s + 1) && - (*(pos - 1) == APR_ASCII_BLANK || *(pos - 1) == APR_ASCII_TAB)) { - --pos; /* trim extra trailing spaces or tabs */ - } - *pos = '\0'; /* zap end of string */ - total = pos - s; /* update total string length */ - - /* look ahead another line if line folding is desired - * and this line isn't empty - */ - if (fold && total) { - looking_ahead = 1; - } - else { - AP_DEBUG_ASSERT(APR_BRIGADE_EMPTY(req_cfg->bb)); - break; - } - } - else { - /* no LF yet...character mode client (telnet)...keep going - * bump past last character read, - * and set total in case we bail before finding a LF - */ - total = ++pos - s; - looking_ahead = 0; /* only appropriate right after LF */ - } - } - ap_xlate_proto_from_ascii(s, total); - return total; -} - -/* parse_uri: break apart the uri - * Side Effects: - * - sets r->args to rest after '?' (or NULL if no '?') - * - sets r->uri to request uri (without r->args part) - * - sets r->hostname (if not set already) from request (scheme://host:port) - */ -AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri) -{ - int status = HTTP_OK; - - r->unparsed_uri = apr_pstrdup(r->pool, uri); - - if (r->method_number == M_CONNECT) { - status = ap_parse_hostinfo_components(r->pool, uri, &r->parsed_uri); - } - else { - /* Simple syntax Errors in URLs are trapped by parse_uri_components(). */ - status = ap_parse_uri_components(r->pool, uri, &r->parsed_uri); - } - - if (ap_is_HTTP_SUCCESS(status)) { - /* if it has a scheme we may need to do absoluteURI vhost stuff */ - if (r->parsed_uri.scheme - && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))) { - r->hostname = r->parsed_uri.hostname; - } - else if (r->method_number == M_CONNECT) { - r->hostname = r->parsed_uri.hostname; - } - r->args = r->parsed_uri.query; - r->uri = r->parsed_uri.path ? r->parsed_uri.path - : apr_pstrdup(r->pool, "/"); -#if defined(OS2) || defined(WIN32) - /* Handle path translations for OS/2 and plug security hole. - * This will prevent "http://www.wherever.com/..\..\/" from - * returning a directory for the root drive. - */ - { - char *x; - - for (x = r->uri; (x = strchr(x, '\\')) != NULL; ) - *x = '/'; - } -#endif /* OS2 || WIN32 */ - } - else { - r->args = NULL; - r->hostname = NULL; - r->status = status; /* set error status */ - r->uri = apr_pstrdup(r->pool, uri); - } -} - -static int read_request_line(request_rec *r) -{ - char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* getline's two extra for \n\0 */ - const char *ll = l; - const char *uri; - const char *pro; - -#if 0 - conn_rec *conn = r->connection; -#endif - int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol */ - int len; - - /* Read past empty lines until we get a real request line, - * a read error, the connection closes (EOF), or we timeout. - * - * We skip empty lines because browsers have to tack a CRLF on to the end - * of POSTs to support old CERN webservers. But note that we may not - * have flushed any previous response completely to the client yet. - * We delay the flush as long as possible so that we can improve - * performance for clients that are pipelining requests. If a request - * is pipelined then we won't block during the (implicit) read() below. - * If the requests aren't pipelined, then the client is still waiting - * for the final buffer flush from us, and we will block in the implicit - * read(). B_SAFEREAD ensures that the BUFF layer flushes if it will - * have to block during a read. - */ - - while ((len = ap_getline(l, sizeof(l), r, 0)) <= 0) { - if (len < 0) { /* includes EOF */ - /* this is a hack to make sure that request time is set, - * it's not perfect, but it's better than nothing - */ - r->request_time = apr_time_now(); - return 0; - } - } - /* we've probably got something to do, ignore graceful restart requests */ - - /* XXX - sigwait doesn't work if the signal has been SIG_IGNed (under - * linux 2.0 w/ glibc 2.0, anyway), and this step isn't necessary when - * we're running a sigwait thread anyway. If/when unthreaded mode is - * put back in, we should make sure to ignore this signal iff a sigwait - * thread isn't used. - mvsk - -#ifdef SIGWINCH - apr_signal(SIGWINCH, SIG_IGN); -#endif - */ - - r->request_time = apr_time_now(); - r->the_request = apr_pstrdup(r->pool, l); - r->method = ap_getword_white(r->pool, &ll); - -#if 0 -/* XXX If we want to keep track of the Method, the protocol module should do - * it. That support isn't in the scoreboard yet. Hopefully next week - * sometime. rbb */ - ap_update_connection_status(AP_CHILD_THREAD_FROM_ID(conn->id), "Method", r->method); -#endif - uri = ap_getword_white(r->pool, &ll); - - /* Provide quick information about the request method as soon as known */ - - r->method_number = ap_method_number_of(r->method); - if (r->method_number == M_GET && r->method[0] == 'H') { - r->header_only = 1; - } - - ap_parse_uri(r, uri); - - /* ap_getline returns (size of max buffer - 1) if it fills up the - * buffer before finding the end-of-line. This is only going to - * happen if it exceeds the configured limit for a request-line. - */ - if (len > r->server->limit_req_line) { - r->status = HTTP_REQUEST_URI_TOO_LARGE; - r->proto_num = HTTP_VERSION(1,0); - r->protocol = apr_pstrdup(r->pool, "HTTP/1.0"); - return 0; - } - - if (ll[0]) { - r->assbackwards = 0; - pro = ll; - len = strlen(ll); - } else { - r->assbackwards = 1; - pro = "HTTP/0.9"; - len = 8; - } - r->protocol = apr_pstrndup(r->pool, pro, len); - - /* XXX ap_update_connection_status(conn->id, "Protocol", r->protocol); */ - - /* Avoid sscanf in the common case */ - if (len == 8 && - pro[0] == 'H' && pro[1] == 'T' && pro[2] == 'T' && pro[3] == 'P' && - pro[4] == '/' && apr_isdigit(pro[5]) && pro[6] == '.' && - apr_isdigit(pro[7])) { - r->proto_num = HTTP_VERSION(pro[5] - '0', pro[7] - '0'); - } else if (2 == sscanf(r->protocol, "HTTP/%u.%u", &major, &minor) - && minor < HTTP_VERSION(1,0)) /* don't allow HTTP/0.1000 */ - r->proto_num = HTTP_VERSION(major, minor); - else - r->proto_num = HTTP_VERSION(1,0); - - return 1; -} - -static void get_mime_headers(request_rec *r) -{ - char field[DEFAULT_LIMIT_REQUEST_FIELDSIZE + 2]; /* getline's two extra */ - char *value; - char *copy; - int len; - int fields_read = 0; - apr_table_t *tmp_headers; - - /* We'll use apr_table_overlap later to merge these into r->headers_in. */ - tmp_headers = apr_table_make(r->pool, 50); - - /* - * Read header lines until we get the empty separator line, a read error, - * the connection closes (EOF), reach the server limit, or we timeout. - */ - while ((len = ap_getline(field, sizeof(field), r, 1)) > 0) { - - if (r->server->limit_req_fields && - (++fields_read > r->server->limit_req_fields)) { - r->status = HTTP_BAD_REQUEST; - apr_table_setn(r->notes, "error-notes", - "The number of request header fields exceeds " - "this server's limit.<P>\n"); - return; - } - /* ap_getline returns (size of max buffer - 1) if it fills up the - * buffer before finding the end-of-line. This is only going to - * happen if it exceeds the configured limit for a field size. - */ - if (len > r->server->limit_req_fieldsize) { - r->status = HTTP_BAD_REQUEST; - apr_table_setn(r->notes, "error-notes", - apr_pstrcat(r->pool, - "Size of a request header field " - "exceeds server limit.<P>\n" - "<PRE>\n", - ap_escape_html(r->pool, field), - "</PRE>\n", NULL)); - return; - } - copy = apr_palloc(r->pool, len + 1); - memcpy(copy, field, len + 1); - - if (!(value = strchr(copy, ':'))) { /* Find the colon separator */ - r->status = HTTP_BAD_REQUEST; /* or abort the bad request */ - apr_table_setn(r->notes, "error-notes", - apr_pstrcat(r->pool, - "Request header field is missing " - "colon separator.<P>\n" - "<PRE>\n", - ap_escape_html(r->pool, copy), - "</PRE>\n", NULL)); - return; - } - - *value = '\0'; - ++value; - while (*value == ' ' || *value == '\t') { - ++value; /* Skip to start of value */ - } - - apr_table_addn(tmp_headers, copy, value); - } - - apr_table_overlap(r->headers_in, tmp_headers, APR_OVERLAP_TABLES_MERGE); -} - -request_rec *ap_read_request(conn_rec *conn) -{ - request_rec *r; - apr_pool_t *p; - const char *expect; - int access_status, keptalive; - - apr_pool_create(&p, conn->pool); - r = apr_pcalloc(p, sizeof(request_rec)); - r->pool = p; - r->connection = conn; - r->server = conn->base_server; - - keptalive = conn->keepalive == 1; - conn->keepalive = 0; - - r->user = NULL; - r->ap_auth_type = NULL; - - r->allowed_methods = ap_make_method_list(p, 2); - - r->headers_in = apr_table_make(r->pool, 50); - r->subprocess_env = apr_table_make(r->pool, 50); - r->headers_out = apr_table_make(r->pool, 12); - r->err_headers_out = apr_table_make(r->pool, 5); - r->notes = apr_table_make(r->pool, 5); - - r->request_config = ap_create_request_config(r->pool); - ap_run_create_request(r); - r->per_dir_config = r->server->lookup_defaults; - - r->sent_bodyct = 0; /* bytect isn't for body */ - - r->read_length = 0; - r->read_body = REQUEST_NO_BODY; - - r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */ - r->the_request = NULL; - r->output_filters = conn->output_filters; - r->input_filters = conn->input_filters; - - apr_setsocketopt(conn->client_socket, APR_SO_TIMEOUT, - (int)(keptalive - ? r->server->keep_alive_timeout * APR_USEC_PER_SEC - : r->server->timeout * APR_USEC_PER_SEC)); - - ap_add_output_filter("BYTERANGE", NULL, r, r->connection); - ap_add_output_filter("CONTENT_LENGTH", NULL, r, r->connection); - ap_add_output_filter("HTTP_HEADER", NULL, r, r->connection); - - /* Get the request... */ - if (!read_request_line(r)) { - if (r->status == HTTP_REQUEST_URI_TOO_LARGE) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "request failed: URI too long"); - ap_send_error_response(r, 0); - ap_run_log_transaction(r); - return r; - } - return NULL; - } - if (keptalive) { - apr_setsocketopt(r->connection->client_socket, APR_SO_TIMEOUT, - (int)(r->server->timeout * APR_USEC_PER_SEC)); - } - if (!r->assbackwards) { - get_mime_headers(r); - if (r->status != HTTP_REQUEST_TIME_OUT) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "request failed: error reading the headers"); - ap_send_error_response(r, 0); - ap_run_log_transaction(r); - return r; - } - } - else { - if (r->header_only) { - /* - * Client asked for headers only with HTTP/0.9, which doesn't send - * headers! Have to dink things just to make sure the error message - * comes through... - */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "client sent invalid HTTP/0.9 request: HEAD %s", - r->uri); - r->header_only = 0; - r->status = HTTP_BAD_REQUEST; - ap_send_error_response(r, 0); - ap_run_log_transaction(r); - return r; - } - } - - r->status = HTTP_OK; /* Until further notice. */ - - /* update what we think the virtual host is based on the headers we've - * now read. may update status. - */ - ap_update_vhost_from_headers(r); - - /* we may have switched to another server */ - r->per_dir_config = r->server->lookup_defaults; - - if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) || - ((r->proto_num == HTTP_VERSION(1,1)) && - !apr_table_get(r->headers_in, "Host"))) { - /* - * Client sent us an HTTP/1.1 or later request without telling us the - * hostname, either with a full URL or a Host: header. We therefore - * need to (as per the 1.1 spec) send an error. As a special case, - * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain - * a Host: header, and the server MUST respond with 400 if it doesn't. - */ - r->status = HTTP_BAD_REQUEST; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "client sent HTTP/1.1 request without hostname " - "(see RFC2616 section 14.23): %s", r->uri); - } - if (r->status != HTTP_OK) { - ap_send_error_response(r, 0); - ap_run_log_transaction(r); - return r; - } - if (((expect = apr_table_get(r->headers_in, "Expect")) != NULL) && - (expect[0] != '\0')) { - /* - * The Expect header field was added to HTTP/1.1 after RFC 2068 - * as a means to signal when a 100 response is desired and, - * unfortunately, to signal a poor man's mandatory extension that - * the server must understand or return 417 Expectation Failed. - */ - if (strcasecmp(expect, "100-continue") == 0) { - r->expecting_100 = 1; - } - else { - r->status = HTTP_EXPECTATION_FAILED; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r, - "client sent an unrecognized expectation value of " - "Expect: %s", expect); - ap_send_error_response(r, 0); - (void) ap_discard_request_body(r); - ap_run_log_transaction(r); - return r; - } - } - - if ((access_status = ap_run_post_read_request(r))) { - ap_die(access_status, r); - ap_run_log_transaction(r); - return NULL; - } - - return r; -} - -/* - * A couple of other functions which initialize some of the fields of - * a request structure, as appropriate for adjuncts of one kind or another - * to a request in progress. Best here, rather than elsewhere, since - * *someone* has to set the protocol-specific fields... - */ - -void ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r) -{ - rnew->the_request = r->the_request; /* Keep original request-line */ - - rnew->assbackwards = 1; /* Don't send headers from this. */ - rnew->no_local_copy = 1; /* Don't try to send HTTP_NOT_MODIFIED for a - * fragment. */ - rnew->method = "GET"; - rnew->method_number = M_GET; - rnew->protocol = "INCLUDED"; - - rnew->status = HTTP_OK; - - rnew->headers_in = r->headers_in; - rnew->subprocess_env = apr_table_copy(rnew->pool, r->subprocess_env); - rnew->headers_out = apr_table_make(rnew->pool, 5); - rnew->err_headers_out = apr_table_make(rnew->pool, 5); - rnew->notes = apr_table_make(rnew->pool, 5); - - rnew->expecting_100 = r->expecting_100; - rnew->read_length = r->read_length; - rnew->read_body = REQUEST_NO_BODY; - - rnew->main = (request_rec *) r; -} - -static void end_output_stream(request_rec *r) -{ - apr_bucket_brigade *bb; - apr_bucket *b; - - bb = apr_brigade_create(r->pool); - b = apr_bucket_eos_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(r->output_filters, bb); -} - -void ap_finalize_sub_req_protocol(request_rec *sub) -{ - end_output_stream(sub); -} - -/* finalize_request_protocol is called at completion of sending the - * response. Its sole purpose is to send the terminating protocol - * information for any wrappers around the response message body - * (i.e., transfer encodings). It should have been named finalize_response. - */ -AP_DECLARE(void) ap_finalize_request_protocol(request_rec *r) -{ - while (r->next) { - r = r->next; - } - /* tell the filter chain there is no more content coming */ - if (!r->eos_sent) { - end_output_stream(r); - } -} - -/* - * Support for the Basic authentication protocol, and a bit for Digest. - */ - -AP_DECLARE(void) ap_note_auth_failure(request_rec *r) -{ - if (!strcasecmp(ap_auth_type(r), "Basic")) - ap_note_basic_auth_failure(r); - else if (!strcasecmp(ap_auth_type(r), "Digest")) - ap_note_digest_auth_failure(r); -} - -AP_DECLARE(void) ap_note_basic_auth_failure(request_rec *r) -{ - if (strcasecmp(ap_auth_type(r), "Basic")) - ap_note_auth_failure(r); - else - apr_table_setn(r->err_headers_out, - (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate" : "WWW-Authenticate", - apr_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r), "\"", - NULL)); -} - -AP_DECLARE(void) ap_note_digest_auth_failure(request_rec *r) -{ - apr_table_setn(r->err_headers_out, - (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate" : "WWW-Authenticate", - apr_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%llx\"", - ap_auth_name(r), r->request_time)); -} - -AP_DECLARE(int) ap_get_basic_auth_pw(request_rec *r, const char **pw) -{ - const char *auth_line = apr_table_get(r->headers_in, - (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authorization" - : "Authorization"); - const char *t; - - if (!(t = ap_auth_type(r)) || strcasecmp(t, "Basic")) - return DECLINED; - - if (!ap_auth_name(r)) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, - 0, r, "need AuthName: %s", r->uri); - return HTTP_INTERNAL_SERVER_ERROR; - } - - if (!auth_line) { - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - - if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) { - /* Client tried to authenticate using wrong auth scheme */ - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "client used wrong authentication scheme: %s", r->uri); - ap_note_basic_auth_failure(r); - return HTTP_UNAUTHORIZED; - } - - while (*auth_line== ' ' || *auth_line== '\t') { - auth_line++; - } - - t = ap_pbase64decode(r->pool, auth_line); - /* Note that this allocation has to be made from r->connection->pool - * because it has the lifetime of the connection. The other allocations - * are temporary and can be tossed away any time. - */ - r->user = ap_getword_nulls (r->pool, &t, ':'); - r->ap_auth_type = "Basic"; - - *pw = t; - - return OK; -} - -struct content_length_ctx { - apr_bucket_brigade *saved; - int compute_len; - apr_size_t curr_len; -}; - -/* This filter computes the content length, but it also computes the number - * of bytes sent to the client. This means that this filter will always run - * through all of the buckets in all brigades - */ -AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_length_filter(ap_filter_t *f, - apr_bucket_brigade *b) -{ - request_rec *r = f->r; - struct content_length_ctx *ctx; - apr_status_t rv; - apr_bucket *e; - int send_it = 0; - - ctx = f->ctx; - if (!ctx) { /* first time through */ - f->ctx = ctx = apr_pcalloc(r->pool, sizeof(struct content_length_ctx)); - } - - APR_BRIGADE_FOREACH(e, b) { - const char *ignored; - apr_size_t length; - - if (APR_BUCKET_IS_EOS(e) || APR_BUCKET_IS_FLUSH(e)) { - send_it = 1; - } - if (e->length == -1) { /* if length unknown */ - rv = apr_bucket_read(e, &ignored, &length, APR_BLOCK_READ); - if (rv != APR_SUCCESS) { - return rv; - } - } - else { - length = e->length; - } - ctx->curr_len += length; - r->bytes_sent += length; - } - - if ((ctx->curr_len < AP_MIN_BYTES_TO_WRITE) && !send_it) { - return ap_save_brigade(f, &ctx->saved, &b); - } - - /* We will compute a content length if: - * The protocol is < 1.1 - * and We can not chunk - * and this is a keepalive request. - * or We already have all the data - * This is a bit confusing, because we will always buffer up - * to AP_MIN_BYTES_TO_WRITE, so if we get all the data while - * we are buffering that much data, we set the c-l. - */ - if ((r->proto_num < HTTP_VERSION(1,1) - && (!ap_find_last_token(f->r->pool, - apr_table_get(r->headers_out, - "Transfer-Encoding"), - "chunked") - && (f->r->connection->keepalive))) - || (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(b)))) { - ctx->compute_len = 1; - } - else { - ctx->compute_len = 0; - } - - if (ctx->compute_len) { - /* save the brigade; we can't pass any data to the next - * filter until we have the entire content length - */ - if (!send_it) { - ap_save_brigade(f, &ctx->saved, &b); - return APR_SUCCESS; - } - ap_set_content_length(r, r->bytes_sent); - } - if (ctx->saved) { - APR_BRIGADE_CONCAT(ctx->saved, b); - apr_brigade_destroy(b); - b = ctx->saved; - ctx->saved = NULL; - } - - ctx->curr_len = 0; - return ap_pass_brigade(f->next, b); -} - -/* - * Send the body of a response to the client. - */ -AP_DECLARE(apr_status_t) ap_send_fd(apr_file_t *fd, request_rec *r, apr_off_t offset, - apr_size_t len, apr_size_t *nbytes) -{ - apr_bucket_brigade *bb = NULL; - apr_bucket *b; - apr_status_t rv; - - bb = apr_brigade_create(r->pool); - b = apr_bucket_file_create(fd, offset, len); - APR_BRIGADE_INSERT_TAIL(bb, b); - - rv = ap_pass_brigade(r->output_filters, bb); - if (rv != APR_SUCCESS) { - *nbytes = 0; /* no way to tell how many were actually sent */ - } - else { - *nbytes = len; - } - - return rv; -} - -#if APR_HAS_MMAP -/* send data from an in-memory buffer */ -AP_DECLARE(size_t) ap_send_mmap(apr_mmap_t *mm, request_rec *r, size_t offset, - size_t length) -{ - apr_bucket_brigade *bb = NULL; - apr_bucket *b; - - bb = apr_brigade_create(r->pool); - b = apr_bucket_mmap_create(mm, offset, length); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_pass_brigade(r->output_filters, bb); - - return mm->size; /* XXX - change API to report apr_status_t? */ -} -#endif /* APR_HAS_MMAP */ - -typedef struct { - apr_bucket_brigade *bb; -} old_write_filter_ctx; - -AP_CORE_DECLARE_NONSTD(apr_status_t) ap_old_write_filter( - ap_filter_t *f, apr_bucket_brigade *bb) -{ - old_write_filter_ctx *ctx = f->ctx; - - AP_DEBUG_ASSERT(ctx); - - if (ctx->bb != 0) { - /* whatever is coming down the pipe (we don't care), we - * can simply insert our buffered data at the front and - * pass the whole bundle down the chain. - */ - APR_BRIGADE_CONCAT(ctx->bb, bb); - } - - return ap_pass_brigade(f->next, ctx->bb); -} - -static apr_status_t buffer_output(request_rec *r, - const char *str, apr_size_t len) -{ - ap_filter_t *f; - old_write_filter_ctx *ctx; - - if (len == 0) - return APR_SUCCESS; - - /* future optimization: record some flags in the request_rec to - * say whether we've added our filter, and whether it is first. - */ - - /* this will typically exit on the first test */ - for (f = r->output_filters; f != NULL; f = f->next) - if (strcmp("OLD_WRITE", f->frec->name) == 0) - break; - if (f == NULL) { - /* our filter hasn't been added yet */ - ctx = apr_pcalloc(r->pool, sizeof(*ctx)); - ap_add_output_filter("OLD_WRITE", ctx, r, r->connection); - f = r->output_filters; - } - - /* if the first filter is not our buffering filter, then we have to - * deliver the content through the normal filter chain */ - if (f != r->output_filters) { - apr_bucket_brigade *bb = apr_brigade_create(r->pool); - apr_bucket *b = apr_bucket_transient_create(str, len); - APR_BRIGADE_INSERT_TAIL(bb, b); - - return ap_pass_brigade(r->output_filters, bb); - } - - /* grab the context from our filter */ - ctx = r->output_filters->ctx; - - if (ctx->bb == NULL) { - ctx->bb = apr_brigade_create(r->pool); - } - - ap_fwrite(f->next, ctx->bb, str, len); - - return APR_SUCCESS; -} - -AP_DECLARE(int) ap_rputc(int c, request_rec *r) -{ - char c2 = (char)c; - - if (r->connection->aborted) { - return -1; - } - - if (buffer_output(r, &c2, 1) != APR_SUCCESS) - return -1; - - return c; -} - -AP_DECLARE(int) ap_rputs(const char *str, request_rec *r) -{ - apr_size_t len; - - if (r->connection->aborted) - return -1; - - if (buffer_output(r, str, len = strlen(str)) != APR_SUCCESS) - return -1; - - return len; -} - -AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r) -{ - if (r->connection->aborted) - return -1; - - if (buffer_output(r, buf, nbyte) != APR_SUCCESS) - return -1; - - return nbyte; -} - -AP_DECLARE(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va) -{ - char buf[4096]; - apr_size_t written; - - if (r->connection->aborted) - return -1; - - /* ### fix this mechanism to allow more than 4K of output */ - written = apr_vsnprintf(buf, sizeof(buf), fmt, va); - if (buffer_output(r, buf, written) != APR_SUCCESS) - return -1; - - return written; -} - -AP_DECLARE_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt, ...) -{ - va_list va; - int n; - - if (r->connection->aborted) - return -1; - - va_start(va, fmt); - n = ap_vrprintf(r, fmt, va); - va_end(va); - - return n; -} - -AP_DECLARE_NONSTD(int) ap_rvputs(request_rec *r, ...) -{ - va_list va; - const char *s; - apr_size_t len; - apr_size_t written = 0; - - if (r->connection->aborted) - return -1; - - /* ### TODO: if the total output is large, put all the strings - ### into a single brigade, rather than flushing each time we - ### fill the buffer */ - va_start(va, r); - while (1) { - s = va_arg(va, const char *); - if (s == NULL) - break; - - len = strlen(s); - if (buffer_output(r, s, len) != APR_SUCCESS) { - return -1; - } - - written += len; - } - va_end(va); - - return written; -} - -AP_DECLARE(int) ap_rflush(request_rec *r) -{ - apr_bucket_brigade *bb; - apr_bucket *b; - - bb = apr_brigade_create(r->pool); - b = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) - return -1; - return 0; -} - -/* - * This function sets the Last-Modified output header field to the value - * of the mtime field in the request structure - rationalized to keep it from - * being in the future. - */ -AP_DECLARE(void) ap_set_last_modified(request_rec *r) -{ - apr_time_t mod_time = ap_rationalize_mtime(r, r->mtime); - char *datestr = apr_palloc(r->pool, APR_RFC822_DATE_LEN); - apr_rfc822_date(datestr, mod_time); - apr_table_setn(r->headers_out, "Last-Modified", datestr); -} - -AP_IMPLEMENT_HOOK_RUN_ALL(int,post_read_request, - (request_rec *r),(r),OK,DECLINED) -AP_IMPLEMENT_HOOK_RUN_ALL(int,log_transaction, - (request_rec *r),(r),OK,DECLINED) -AP_IMPLEMENT_HOOK_RUN_FIRST(const char *,http_method, - (const request_rec *r),(r),NULL) -AP_IMPLEMENT_HOOK_RUN_FIRST(unsigned short,default_port, - (const request_rec *r),(r),0) diff --git a/server/request.c b/server/request.c deleted file mode 100644 index b015def039..0000000000 --- a/server/request.c +++ /dev/null @@ -1,1133 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_request.c: functions to get and process requests - * - * Rob McCool 3/21/93 - * - * Thoroughly revamped by rst for Apache. NB this file reads - * best from the bottom up. - * - */ - -#include "apr_strings.h" -#include "apr_file_io.h" -#include "apr_fnmatch.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_request.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_main.h" -#include "util_filter.h" -#include "util_charset.h" - -#include "mod_core.h" - -#if APR_HAVE_STDARG_H -#include <stdarg.h> -#endif - -APR_HOOK_STRUCT( - APR_HOOK_LINK(translate_name) - APR_HOOK_LINK(check_user_id) - APR_HOOK_LINK(fixups) - APR_HOOK_LINK(type_checker) - APR_HOOK_LINK(access_checker) - APR_HOOK_LINK(auth_checker) - APR_HOOK_LINK(insert_filter) - APR_HOOK_LINK(create_request) -) - -AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name, - (request_rec *r),(r),DECLINED) -AP_IMPLEMENT_HOOK_RUN_FIRST(int,check_user_id, - (request_rec *r),(r),DECLINED) -AP_IMPLEMENT_HOOK_RUN_ALL(int,fixups, - (request_rec *r),(r),OK,DECLINED) -AP_IMPLEMENT_HOOK_RUN_FIRST(int,type_checker, - (request_rec *r),(r),DECLINED) -AP_IMPLEMENT_HOOK_RUN_ALL(int,access_checker, - (request_rec *r),(r),OK,DECLINED) -AP_IMPLEMENT_HOOK_RUN_FIRST(int,auth_checker, - (request_rec *r),(r),DECLINED) -AP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r)) -AP_IMPLEMENT_HOOK_RUN_ALL(int,create_request,(request_rec *r),(r),OK,DECLINED) - -/***************************************************************** - * - * Getting and checking directory configuration. Also checks the - * FollowSymlinks and FollowSymOwner stuff, since this is really the - * only place that can happen (barring a new mid_dir_walk callout). - * - * We can't do it as an access_checker module function which gets - * called with the final per_dir_config, since we could have a directory - * with FollowSymLinks disabled, which contains a symlink to another - * with a .htaccess file which turns FollowSymLinks back on --- and - * access in such a case must be denied. So, whatever it is that - * checks FollowSymLinks needs to know the state of the options as - * they change, all the way down. - */ - -/* - * We don't want people able to serve up pipes, or unix sockets, or other - * scary things. Note that symlink tests are performed later. - */ -static int check_safe_file(request_rec *r) -{ - - if (r->finfo.filetype == 0 /* doesn't exist */ - || r->finfo.filetype == APR_DIR - || r->finfo.filetype == APR_REG - || r->finfo.filetype == APR_LNK) { - return OK; - } - - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "object is not a file, directory or symlink: %s", - r->filename); - return HTTP_FORBIDDEN; -} - - -static int check_symlinks(char *d, int opts, apr_pool_t *p) -{ -#if defined(OS2) - /* OS/2 doesn't have symlinks */ - return OK; -#else - apr_finfo_t lfi, fi; - char *lastp; - int res; - - if (opts & OPT_SYM_LINKS) - return OK; - - /* - * Strip trailing '/', if any, off what we're checking; trailing slashes - * make some systems follow symlinks to directories even in lstat(). - * After we've done the lstat, put it back. Also, don't bother checking - * '/' at all... - * - * Note that we don't have to worry about multiple slashes here because of - * no2slash() below... - */ - - lastp = d + strlen(d) - 1; - if (lastp == d) - return OK; /* Root directory, '/' */ - - if (*lastp == '/') - *lastp = '\0'; - else - lastp = NULL; - - res = apr_lstat(&lfi, d, APR_FINFO_TYPE | APR_FINFO_OWNER, p); - - if (lastp) - *lastp = '/'; - - /* - * Note that we don't reject accesses to nonexistent files (multiviews or - * the like may cons up a way to run the transaction anyway)... - */ - - if ((res != APR_SUCCESS && res != APR_INCOMPLETE) - || (lfi.filetype != APR_LNK)) - return OK; - - /* OK, it's a symlink. May still be OK with OPT_SYM_OWNER */ - - if (!(opts & OPT_SYM_OWNER)) - return HTTP_FORBIDDEN; - - /* OPT_SYM_OWNER only works if we can get the owner from the file */ - - if (res != APR_SUCCESS) - return HTTP_FORBIDDEN; - - if (apr_stat(&fi, d, APR_FINFO_OWNER, p) != APR_SUCCESS) - return HTTP_FORBIDDEN; - - /* TODO: replace with an apr_compare_users() fn */ - return (fi.user == lfi.user) ? OK : HTTP_FORBIDDEN; - -#endif -} - -/* Dealing with the file system to get PATH_INFO - */ -static int get_path_info(request_rec *r) -{ - char *cp; - char *path = r->filename; - char *end = &path[strlen(path)]; - char *last_cp = NULL; - int rv; -#if defined(HAVE_DRIVE_LETTERS) || defined(HAVE_UNC_PATHS) - char bStripSlash=1; -#endif - - if (r->finfo.filetype) { - /* assume path_info already set */ - return OK; - } - -#ifdef HAVE_DRIVE_LETTERS - /* If the directory is x:\, then we don't want to strip - * the trailing slash since x: is not a valid directory. - */ - if (strlen(path) == 3 && path[1] == ':' && path[2] == '/') - bStripSlash = 0; -#endif - -#ifdef HAVE_UNC_PATHS - /* If UNC name == //machine/share/, do not - * advance over the trailing slash. Any other - * UNC name is OK to strip the slash. - */ - cp = end; - if (path[0] == '/' && path[1] == '/' && - path[2] != '/' && cp[-1] == '/') { - char *p; - int iCount=0; - p = path; - while ((p = strchr(p,'/')) != NULL) { - p++; - iCount++; - } - - if (iCount == 4) - bStripSlash = 0; - } -#endif - -#if defined(HAVE_DRIVE_LETTERS) || defined(HAVE_UNC_PATHS) - if (bStripSlash) -#endif - /* Advance over trailing slashes ... NOT part of filename - * if file is not a UNC name (Win32 only). - */ - for (cp = end; cp > path && cp[-1] == '/'; --cp) - continue; - - while (cp > path) { - - /* See if the pathname ending here exists... */ - *cp = '\0'; - - /* ### We no longer need the test ap_os_is_filename_valid() here - * since apr_stat isn't a posix thing - it's apr_stat's responsibility - * to handle whatever path string arrives at it's door - by platform - * and volume restrictions as applicable... - * TODO: This code becomes even simpler if apr_stat grows - * an APR_PATHINCOMPLETE result to indicate that we are staring at - * an partial virtual root. Only OS2/Win32/Netware need apply it :-) - */ - rv = apr_stat(&r->finfo, path, APR_FINFO_MIN, r->pool); - - if (cp != end) - *cp = '/'; - - if (rv == APR_SUCCESS || rv == APR_INCOMPLETE) { - /* - * Aha! Found something. If it was a directory, we will search - * contents of that directory for a multi_match, so the PATH_INFO - * argument starts with the component after that. - */ - if (r->finfo.filetype == APR_DIR && last_cp) { - r->finfo.filetype = APR_NOFILE; /* No such file... */ - cp = last_cp; - } - - r->path_info = apr_pstrdup(r->pool, cp); - *cp = '\0'; - return OK; - } - - if (APR_STATUS_IS_ENOENT(rv) || APR_STATUS_IS_ENOTDIR(rv)) { - last_cp = cp; - - while (--cp > path && *cp != '/') - continue; - - while (cp > path && cp[-1] == '/') - --cp; - } - else { - if (APR_STATUS_IS_EACCES(rv)) - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "access to %s denied", r->uri); - else - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "access to %s failed", r->uri); - return HTTP_FORBIDDEN; - } - } - return OK; -} - -AP_DECLARE(int) directory_walk(request_rec *r) -{ - core_server_config *sconf = ap_get_module_config(r->server->module_config, - &core_module); - ap_conf_vector_t *per_dir_defaults = r->server->lookup_defaults; - ap_conf_vector_t **sec = (ap_conf_vector_t **) sconf->sec->elts; - int num_sec = sconf->sec->nelts; - char *test_filename; - char *test_dirname; - int res; - unsigned i, num_dirs; - int j, test_filename_len; -#if defined(HAVE_UNC_PATHS) || defined(NETWARE) - unsigned iStart = 1; -#endif - ap_conf_vector_t *entry_config; - ap_conf_vector_t *this_conf; - core_dir_config *entry_core; - - /* - * Are we dealing with a file? If not, we can (hopefuly) safely assume we - * have a handler that doesn't require one, but for safety's sake, and so - * we have something find_types() can get something out of, fake one. But - * don't run through the directory entries. - */ - - if (r->filename == NULL) { - r->filename = apr_pstrdup(r->pool, r->uri); - r->finfo.filetype = APR_NOFILE; - r->per_dir_config = per_dir_defaults; - - return OK; - } - - /* - * Go down the directory hierarchy. Where we have to check for symlinks, - * do so. Where a .htaccess file has permission to override anything, - * try to find one. If either of these things fails, we could poke - * around, see why, and adjust the lookup_rec accordingly --- this might - * save us a call to get_path_info (with the attendant stat()s); however, - * for the moment, that's not worth the trouble. - * - * Fake filenames (i.e. proxy:) only match Directory sections. - */ - - if (!ap_os_is_path_absolute(r->filename)) - { - const char *entry_dir; - - for (j = 0; j < num_sec; ++j) { - - entry_config = sec[j]; - entry_core = ap_get_module_config(entry_config, &core_module); - entry_dir = entry_core->d; - - this_conf = NULL; - if (entry_core->r) { - if (!ap_regexec(entry_core->r, r->filename, 0, NULL, 0)) - this_conf = entry_config; - } - else if (entry_core->d_is_fnmatch) { - if (!apr_fnmatch(entry_dir, r->filename, 0)) - this_conf = entry_config; - } - else if (!strncmp(r->filename, entry_dir, strlen(entry_dir))) - this_conf = entry_config; - - if (this_conf) - per_dir_defaults = ap_merge_per_dir_configs(r->pool, - per_dir_defaults, - this_conf); - } - - r->per_dir_config = per_dir_defaults; - - return OK; - } - - /* XXX This needs to be rolled into APR, the APR function will not - * be allowed to fold the case of any non-existant segment of the path: - */ - r->filename = ap_os_case_canonical_filename(r->pool, r->filename); - - /* TODO This is rather silly right here, we should simply be setting - * filename and path_info at the end of our directory_walk - */ - res = get_path_info(r); - if (res != OK) { - return res; - } - - /* XXX This becomes moot, and will already happen above for elements - * that actually exist: - */ - r->filename = ap_os_canonical_filename(r->pool, r->filename); - - test_filename = apr_pstrdup(r->pool, r->filename); - - /* XXX This becomes mute, since the APR canonical parsing will handle - * 2slash and dot directory issues: - */ - ap_no2slash(test_filename); - num_dirs = ap_count_dirs(test_filename); - - /* XXX This needs to be rolled into APR: */ - if ((res = check_safe_file(r))) { - return res; - } - - test_filename_len = strlen(test_filename); - if (test_filename[test_filename_len - 1] == '/') - --num_dirs; - - if (r->finfo.filetype == APR_DIR) - ++num_dirs; - - /* - * We will use test_dirname as scratch space while we build directory - * names during the walk. Profiling shows directory_walk to be a busy - * function so we try to avoid allocating lots of extra memory here. - * We need 2 extra bytes, one for trailing \0 and one because - * make_dirstr_prefix will add potentially one extra /. - */ - test_dirname = apr_palloc(r->pool, test_filename_len + 2); - - /* XXX These exception cases go away if apr_stat() returns the - * APR_PATHINCOMPLETE status, so we skip hard filesystem testing - * of the initial 'pseudo' elements: - */ - -#if defined(HAVE_UNC_PATHS) - /* If the name is a UNC name, then do not perform any true file test - * against the machine name (start at //machine/share/) - * This is optimized to use the normal walk (skips the redundant '/' root) - */ - if (num_dirs > 3 && test_filename[0] == '/' && test_filename[1] == '/') - iStart = 4; -#endif - -#if defined(NETWARE) - /* If the name is a fully qualified volume name, then do not perform any - * true file test on the machine name (start at machine/share:/) - * XXX: The implementation eludes me at this moment... - * Does this make sense? Please test! - */ - if (num_dirs > 1 && strchr(test_filename, '/') < strchr(test_filename, ':')) - iStart = 2; -#endif - -#if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE) - /* Should match <Directory> sections starting from '/', not 'e:/' - * (for example). WIN32/OS2/NETWARE do not have a single root directory, - * they have one for each filesystem. Traditionally, Apache has treated - * <Directory /> permissions as the base for the whole server, and this - * tradition should probably be preserved. - * - * NOTE: MUST SYNC WITH ap_make_dirstr_prefix() CHANGE IN src/main/util.c - */ - if (test_filename[0] == '/') - i = 1; - else - i = 0; -#else - /* Normal File Systems are rooted at / */ - i = 1; -#endif /* def HAVE_DRIVE_LETTERS || NETWARE */ - - /* j keeps track of which section we're on, see core_reorder_directories */ - j = 0; - for (; i <= num_dirs; ++i) { - int overrides_here; - core_dir_config *core_dir = ap_get_module_config(per_dir_defaults, - &core_module); - - /* - * XXX: this could be made faster by only copying the next component - * rather than copying the entire thing all over. - */ - ap_make_dirstr_prefix(test_dirname, test_filename, i); - - /* - * Do symlink checks first, because they are done with the - * permissions appropriate to the *parent* directory... - */ - -#if defined(HAVE_UNC_PATHS) || defined(NETWARE) - /* Test only legal names against the real filesystem */ - if (i >= iStart) -#endif - if ((res = check_symlinks(test_dirname, core_dir->opts, r->pool))) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Symbolic link not allowed: %s", test_dirname); - return res; - } - - /* - * Begin *this* level by looking for matching <Directory> sections - * from access.conf. - */ - - for (; j < num_sec; ++j) { - char *entry_dir; - - entry_config = sec[j]; - entry_core = ap_get_module_config(entry_config, &core_module); - entry_dir = entry_core->d; - - if (entry_core->r - || !ap_os_is_path_absolute(entry_dir) -#if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE) - /* To account for the top-level "/" directory when i == 0 - * XXX: The net test may be wrong... may fail ap_os_is_path_absolute - */ - || (entry_core->d_components > 1 - && entry_core->d_components > i) -#else - || entry_core->d_components > i -#endif /* def HAVE_DRIVE_LETTERS || NETWARE */ - ) - break; - - this_conf = NULL; - if (entry_core->d_is_fnmatch) { - if (!apr_fnmatch(entry_dir, test_dirname, FNM_PATHNAME)) { - this_conf = entry_config; - } - } - else if (!strcmp(test_dirname, entry_dir)) - this_conf = entry_config; - - if (this_conf) { - per_dir_defaults = ap_merge_per_dir_configs(r->pool, - per_dir_defaults, - this_conf); - core_dir = ap_get_module_config(per_dir_defaults, - &core_module); - } -#if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE) - /* So that other top-level directory sections (e.g. "e:/") aren't - * skipped when i == 0 - * XXX: I don't get you here, Tim... That's a level 1 section, but - * we are at level 0. Did you mean fast-forward to the next? - */ - else if (!i) - break; -#endif /* def HAVE_DRIVE_LETTERS || NETWARE */ - } - overrides_here = core_dir->override; - - /* If .htaccess files are enabled, check for one. */ - -#if defined(HAVE_UNC_PATHS) || defined(NETWARE) - /* Test only legal names against the real filesystem */ - if (i >= iStart) -#endif - if (overrides_here) { - ap_conf_vector_t *htaccess_conf = NULL; - - res = ap_parse_htaccess(&htaccess_conf, r, overrides_here, - apr_pstrdup(r->pool, test_dirname), - sconf->access_name); - if (res) - return res; - - if (htaccess_conf) { - per_dir_defaults = ap_merge_per_dir_configs(r->pool, - per_dir_defaults, - htaccess_conf); - r->per_dir_config = per_dir_defaults; - } - } - } - - /* - * There's two types of IS_SPECIAL sections (see http_core.c), and we've - * already handled the proxy:-style stuff. Now we'll deal with the - * regexes. - */ - for (; j < num_sec; ++j) { - - entry_config = sec[j]; - entry_core = ap_get_module_config(entry_config, &core_module); - - if (entry_core->r) { - if (!ap_regexec(entry_core->r, test_dirname, 0, NULL, REG_NOTEOL)) { - per_dir_defaults = ap_merge_per_dir_configs(r->pool, - per_dir_defaults, - entry_config); - } - } - } - r->per_dir_config = per_dir_defaults; - - /* - * Symlink permissions are determined by the parent. If the request is - * for a directory then applying the symlink test here would use the - * permissions of the directory as opposed to its parent. Consider a - * symlink pointing to a dir with a .htaccess disallowing symlinks. If - * you access /symlink (or /symlink/) you would get a 403 without this - * S_ISDIR test. But if you accessed /symlink/index.html, for example, - * you would *not* get the 403. - */ - if (r->finfo.filetype != APR_DIR - && (res = check_symlinks(r->filename, ap_allow_options(r), r->pool))) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Symbolic link not allowed: %s", r->filename); - return res; - } - return OK; /* Can only "fail" if access denied by the - * symlink goop. */ -} - -AP_DECLARE(int) location_walk(request_rec *r) -{ - core_server_config *sconf = ap_get_module_config(r->server->module_config, - &core_module); - ap_conf_vector_t *per_dir_defaults = r->per_dir_config; - ap_conf_vector_t **url = (ap_conf_vector_t **) sconf->sec_url->elts; - int len, num_url = sconf->sec_url->nelts; - char *test_location; - ap_conf_vector_t *this_conf; - ap_conf_vector_t *entry_config; - core_dir_config *entry_core; - char *entry_url; - int j; - - if (!num_url) { - return OK; - } - - /* Location and LocationMatch differ on their behaviour w.r.t. multiple - * slashes. Location matches multiple slashes with a single slash, - * LocationMatch doesn't. An exception, for backwards brokenness is - * absoluteURIs... in which case neither match multiple slashes. - */ - if (r->uri[0] != '/') { - test_location = r->uri; - } - else { - test_location = apr_pstrdup(r->pool, r->uri); - ap_no2slash(test_location); - } - - /* Go through the location entries, and check for matches. */ - - /* we apply the directive sections in some order; - * should really try them with the most general first. - */ - for (j = 0; j < num_url; ++j) { - - entry_config = url[j]; - - entry_core = ap_get_module_config(entry_config, &core_module); - entry_url = entry_core->d; - - len = strlen(entry_url); - - this_conf = NULL; - - if (entry_core->r) { - if (!ap_regexec(entry_core->r, r->uri, 0, NULL, 0)) - this_conf = entry_config; - } - else if (entry_core->d_is_fnmatch) { - if (!apr_fnmatch(entry_url, test_location, FNM_PATHNAME)) { - this_conf = entry_config; - } - } - else if (!strncmp(test_location, entry_url, len) && - (entry_url[len - 1] == '/' || - test_location[len] == '/' || test_location[len] == '\0')) - this_conf = entry_config; - - if (this_conf) - per_dir_defaults = ap_merge_per_dir_configs(r->pool, - per_dir_defaults, - this_conf); - } - r->per_dir_config = per_dir_defaults; - - return OK; -} - -AP_DECLARE(int) file_walk(request_rec *r) -{ - core_dir_config *conf = ap_get_module_config(r->per_dir_config, - &core_module); - ap_conf_vector_t *per_dir_defaults = r->per_dir_config; - ap_conf_vector_t **file = (ap_conf_vector_t **) conf->sec->elts; - int num_files = conf->sec->nelts; - char *test_file; - - /* get the basename */ - test_file = strrchr(r->filename, '/'); - if (test_file == NULL) { - test_file = r->filename; - } - else { - ++test_file; - } - - /* Go through the file entries, and check for matches. */ - - if (num_files) { - ap_conf_vector_t *this_conf; - ap_conf_vector_t *entry_config; - core_dir_config *entry_core; - char *entry_file; - int j; - - /* we apply the directive sections in some order; - * should really try them with the most general first. - */ - for (j = 0; j < num_files; ++j) { - - entry_config = file[j]; - - entry_core = ap_get_module_config(entry_config, &core_module); - entry_file = entry_core->d; - - this_conf = NULL; - - if (entry_core->r) { - if (!ap_regexec(entry_core->r, test_file, 0, NULL, 0)) - this_conf = entry_config; - } - else if (entry_core->d_is_fnmatch) { - if (!apr_fnmatch(entry_file, test_file, FNM_PATHNAME)) { - this_conf = entry_config; - } - } - else if (!strcmp(test_file, entry_file)) { - this_conf = entry_config; - } - - if (this_conf) - per_dir_defaults = ap_merge_per_dir_configs(r->pool, - per_dir_defaults, - this_conf); - } - r->per_dir_config = per_dir_defaults; - } - return OK; -} - -/***************************************************************** - * - * The sub_request mechanism. - * - * Fns to look up a relative URI from, e.g., a map file or SSI document. - * These do all access checks, etc., but don't actually run the transaction - * ... use run_sub_req below for that. Also, be sure to use destroy_sub_req - * as appropriate if you're likely to be creating more than a few of these. - * (An early Apache version didn't destroy the sub_reqs used in directory - * indexing. The result, when indexing a directory with 800-odd files in - * it, was massively excessive storage allocation). - * - * Note more manipulation of protocol-specific vars in the request - * structure... - */ - -static request_rec *make_sub_request(const request_rec *r) -{ - apr_pool_t *rrp; - request_rec *rr; - - apr_pool_create(&rrp, r->pool); - rr = apr_pcalloc(rrp, sizeof(request_rec)); - rr->pool = rrp; - return rr; -} - -AP_CORE_DECLARE_NONSTD(apr_status_t) ap_sub_req_output_filter(ap_filter_t *f, - apr_bucket_brigade *bb) -{ - apr_bucket *e = APR_BRIGADE_LAST(bb); - - if (APR_BUCKET_IS_EOS(e)) { - apr_bucket_delete(e); - } - ap_pass_brigade(f->next, bb); - return APR_SUCCESS; -} - - -AP_DECLARE(int) ap_some_auth_required(request_rec *r) -{ - /* Is there a require line configured for the type of *this* req? */ - - const apr_array_header_t *reqs_arr = ap_requires(r); - require_line *reqs; - int i; - - if (!reqs_arr) - return 0; - - reqs = (require_line *) reqs_arr->elts; - - for (i = 0; i < reqs_arr->nelts; ++i) - if (reqs[i].method_mask & (1 << r->method_number)) - return 1; - - return 0; -} - -AP_DECLARE(request_rec *) ap_sub_req_method_uri(const char *method, - const char *new_file, - const request_rec *r, - ap_filter_t *next_filter) -{ - request_rec *rnew; - int res; - char *udir; - - rnew = make_sub_request(r); - rnew->hostname = r->hostname; - rnew->request_time = r->request_time; - rnew->connection = r->connection; - rnew->server = r->server; - - rnew->request_config = ap_create_request_config(rnew->pool); - - rnew->htaccess = r->htaccess; - rnew->per_dir_config = r->server->lookup_defaults; - rnew->allowed_methods = ap_make_method_list(rnew->pool, 2); - - /* make a copy of the allowed-methods list */ - ap_copy_method_list(rnew->allowed_methods, r->allowed_methods); - - /* start with the same set of output filters */ - if (next_filter) { - rnew->output_filters = next_filter; - } - else { - rnew->output_filters = r->output_filters; - } - ap_add_output_filter("SUBREQ_CORE", NULL, rnew, rnew->connection); - - /* no input filters for a subrequest */ - - ap_set_sub_req_protocol(rnew, r); - - /* We have to run this after ap_set_sub_req_protocol, or the r->main - * pointer won't be setup - */ - ap_run_create_request(rnew); - - /* would be nicer to pass "method" to ap_set_sub_req_protocol */ - rnew->method = method; - rnew->method_number = ap_method_number_of(method); - - if (new_file[0] == '/') - ap_parse_uri(rnew, new_file); - else { - udir = ap_make_dirstr_parent(rnew->pool, r->uri); - udir = ap_escape_uri(rnew->pool, udir); /* re-escape it */ - ap_parse_uri(rnew, ap_make_full_path(rnew->pool, udir, new_file)); - } - - res = ap_unescape_url(rnew->uri); - if (res) { - rnew->status = res; - return rnew; - } - - ap_getparents(rnew->uri); - - if ((res = location_walk(rnew))) { - rnew->status = res; - return rnew; - } - - res = ap_run_translate_name(rnew); - if (res) { - rnew->status = res; - return rnew; - } - - /* - * We could be clever at this point, and avoid calling directory_walk, - * etc. However, we'd need to test that the old and new filenames contain - * the same directory components, so it would require duplicating the - * start of translate_name. Instead we rely on the cache of .htaccess - * results. - * - * NB: directory_walk() clears the per_dir_config, so we don't inherit - * from location_walk() above - */ - - if ((res = directory_walk(rnew)) - || (res = file_walk(rnew)) - || (res = location_walk(rnew)) - || ((ap_satisfies(rnew) == SATISFY_ALL - || ap_satisfies(rnew) == SATISFY_NOSPEC) - ? ((res = ap_run_access_checker(rnew)) - || (ap_some_auth_required(rnew) - && ((res = ap_run_check_user_id(rnew)) - || (res = ap_run_auth_checker(rnew))))) - : ((res = ap_run_access_checker(rnew)) - && (!ap_some_auth_required(rnew) - || ((res = ap_run_check_user_id(rnew)) - || (res = ap_run_auth_checker(rnew))))) - ) - || (res = ap_run_type_checker(rnew)) - || (res = ap_run_fixups(rnew)) - ) { - rnew->status = res; - } - return rnew; -} - -AP_DECLARE(request_rec *) ap_sub_req_lookup_uri(const char *new_file, - const request_rec *r, - ap_filter_t *next_filter) -{ - return ap_sub_req_method_uri("GET", new_file, r, next_filter); -} - -AP_DECLARE(request_rec *) ap_sub_req_lookup_file(const char *new_file, - const request_rec *r, - ap_filter_t *next_filter) -{ - request_rec *rnew; - int res; - char *fdir; - - rnew = make_sub_request(r); - rnew->hostname = r->hostname; - rnew->request_time = r->request_time; - rnew->connection = r->connection; - rnew->server = r->server; - - rnew->request_config = ap_create_request_config(rnew->pool); - - rnew->htaccess = r->htaccess; - rnew->chunked = r->chunked; - rnew->allowed_methods = ap_make_method_list(rnew->pool, 2); - - /* make a copy of the allowed-methods list */ - ap_copy_method_list(rnew->allowed_methods, r->allowed_methods); - - /* start with the same set of output filters */ - if (next_filter) { - rnew->output_filters = next_filter; - } - else { - rnew->output_filters = r->output_filters; - } - ap_add_output_filter("SUBREQ_CORE", NULL, rnew, rnew->connection); - - /* no input filters for a subrequest */ - - ap_set_sub_req_protocol(rnew, r); - - /* We have to run this after ap_set_sub_req_protocol, or the r->main - * pointer won't be setup - */ - ap_run_create_request(rnew); - - fdir = ap_make_dirstr_parent(rnew->pool, r->filename); - - /* - * Check for a special case... if there are no '/' characters in new_file - * at all, then we are looking at a relative lookup in the same - * directory. That means we won't have to redo directory_walk, and we may - * not even have to redo access checks. - */ - - if (ap_strchr_c(new_file, '/') == NULL) { - char *udir = ap_make_dirstr_parent(rnew->pool, r->uri); - apr_status_t rv; - - rnew->uri = ap_make_full_path(rnew->pool, udir, new_file); - rnew->filename = ap_make_full_path(rnew->pool, fdir, new_file); - ap_parse_uri(rnew, rnew->uri); /* fill in parsed_uri values */ - - if (((rv = apr_stat(&rnew->finfo, rnew->filename, - APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS) - && (rv != APR_INCOMPLETE)) { - rnew->finfo.filetype = 0; - } - - if ((res = check_safe_file(rnew))) { - rnew->status = res; - return rnew; - } - - rnew->per_dir_config = r->per_dir_config; - - /* - * no matter what, if it's a subdirectory, we need to re-run - * directory_walk - */ - if (rnew->finfo.filetype == APR_DIR) { - res = directory_walk(rnew); - if (!res) { - res = file_walk(rnew); - } - } - else { - if ((res = check_symlinks(rnew->filename, ap_allow_options(rnew), - rnew->pool))) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, rnew, - "Symbolic link not allowed: %s", rnew->filename); - rnew->status = res; - return rnew; - } - /* - * do a file_walk, if it doesn't change the per_dir_config then - * we know that we don't have to redo all the access checks - */ - if ((res = file_walk(rnew))) { - rnew->status = res; - return rnew; - } - if (rnew->per_dir_config == r->per_dir_config) { - if ((res = ap_run_type_checker(rnew)) || (res = ap_run_fixups(rnew))) { - rnew->status = res; - } - return rnew; - } - } - } - else { - /* XXX: @@@: What should be done with the parsed_uri values? */ - ap_parse_uri(rnew, new_file); /* fill in parsed_uri values */ - /* - * XXX: this should be set properly like it is in the same-dir case - * but it's actually sometimes to impossible to do it... because the - * file may not have a uri associated with it -djg - */ - rnew->uri = "INTERNALLY GENERATED file-relative req"; - rnew->filename = ((ap_os_is_path_absolute(new_file)) ? - apr_pstrdup(rnew->pool, new_file) : - ap_make_full_path(rnew->pool, fdir, new_file)); - rnew->per_dir_config = r->server->lookup_defaults; - res = directory_walk(rnew); - if (!res) { - res = file_walk(rnew); - } - } - - if (res - || ((ap_satisfies(rnew) == SATISFY_ALL - || ap_satisfies(rnew) == SATISFY_NOSPEC) - ? ((res = ap_run_access_checker(rnew)) - || (ap_some_auth_required(rnew) - && ((res = ap_run_check_user_id(rnew)) - || (res = ap_run_auth_checker(rnew))))) - : ((res = ap_run_access_checker(rnew)) - && (!ap_some_auth_required(rnew) - || ((res = ap_run_check_user_id(rnew)) - || (res = ap_run_auth_checker(rnew))))) - ) - || (res = ap_run_type_checker(rnew)) - || (res = ap_run_fixups(rnew)) - ) { - rnew->status = res; - } - return rnew; -} - -AP_DECLARE(int) ap_run_sub_req(request_rec *r) -{ - int retval; - - /* see comments in process_request_internal() */ - ap_run_insert_filter(r); - retval = ap_invoke_handler(r); - ap_finalize_sub_req_protocol(r); - return retval; -} - -AP_DECLARE(void) ap_destroy_sub_req(request_rec *r) -{ - /* Reclaim the space */ - apr_pool_destroy(r->pool); -} - -/* - * Function to set the r->mtime field to the specified value if it's later - * than what's already there. - */ -AP_DECLARE(void) ap_update_mtime(request_rec *r, apr_time_t dependency_mtime) -{ - if (r->mtime < dependency_mtime) { - r->mtime = dependency_mtime; - } -} - -/* - * Is it the initial main request, which we only get *once* per HTTP request? - */ -AP_DECLARE(int) ap_is_initial_req(request_rec *r) -{ - return - (r->main == NULL) /* otherwise, this is a sub-request */ - && - (r->prev == NULL); /* otherwise, this is an internal redirect */ -} - diff --git a/server/rfc1413.c b/server/rfc1413.c deleted file mode 100644 index 40d221bc10..0000000000 --- a/server/rfc1413.c +++ /dev/null @@ -1,288 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* TODO - put timeouts back in */ -/* - * rfc1413() speaks a common subset of the RFC 1413, AUTH, TAP and IDENT - * protocols. The code queries an RFC 1413 etc. compatible daemon on a remote - * host to look up the owner of a connection. The information should not be - * used for authentication purposes. This routine intercepts alarm signals. - * - * Diagnostics are reported through syslog(3). - * - * Author: Wietse Venema, Eindhoven University of Technology, - * The Netherlands. - */ - -/* Some small additions for Apache --- ditch the "sccsid" var if - * compiling with gcc (it *has* changed), include ap_config.h for the - * prototypes it defines on at least one system (SunlOSs) which has - * them missing from the standard header files, and one minor change - * below (extra parens around assign "if (foo = bar) ..." to shut up - * gcc -Wall). - */ - -/* Rewritten by David Robinson */ - -#include "apr.h" -#include "apr_network_io.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STDIO -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" /* for server_rec, conn_rec, etc. */ -#include "http_log.h" /* for aplog_error */ -#include "rfc1413.h" -#include "http_main.h" /* set_callback_and_alarm */ -#include "util_ebcdic.h" - -/* Local stuff. */ -/* Semi-well-known port */ -#define RFC1413_PORT 113 -/* maximum allowed length of userid */ -#define RFC1413_USERLEN 512 -/* rough limit on the amount of data we accept. */ -#define RFC1413_MAXDATA 1000 - -#ifndef RFC1413_TIMEOUT -#define RFC1413_TIMEOUT 30 -#endif -#define FROM_UNKNOWN "unknown" - -int ap_rfc1413_timeout = RFC1413_TIMEOUT; /* Global so it can be changed */ - -static apr_status_t rfc1413_connect(apr_socket_t **newsock, conn_rec *conn, - server_rec *srv) -{ - apr_status_t rv; - apr_sockaddr_t *localsa, *destsa; - - if ((rv = apr_sockaddr_info_get(&localsa, conn->local_ip, APR_UNSPEC, - 0, /* ephemeral port */ - 0, conn->pool)) != APR_SUCCESS) { - /* This should not fail since we have a numeric address string - * as the host. */ - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv, - "rfc1413: apr_sockaddr_info_get(%s) failed", - conn->local_ip); - return rv; - } - - if ((rv = apr_sockaddr_info_get(&destsa, conn->remote_ip, - localsa->sa.sin.sin_family, /* has to match */ - RFC1413_PORT, 0, conn->pool)) != APR_SUCCESS) { - /* This should not fail since we have a numeric address string - * as the host. */ - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv, - "rfc1413: apr_sockaddr_info_get(%s) failed", - conn->remote_ip); - return rv; - } - - if ((rv = apr_socket_create(newsock, - localsa->sa.sin.sin_family, /* has to match */ - SOCK_STREAM, conn->pool)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv, - "rfc1413: error creating query socket"); - return rv; - } - - if ((rv = apr_setsocketopt(*newsock, APR_SO_TIMEOUT, - (apr_int32_t)(ap_rfc1413_timeout - * APR_USEC_PER_SEC))) - != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv, - "rfc1413: error setting query socket timeout"); - apr_socket_close(*newsock); - return rv; - } - -/* - * Bind the local and remote ends of the query socket to the same - * IP addresses as the connection under investigation. We go - * through all this trouble because the local or remote system - * might have more than one network address. The RFC1413 etc. - * client sends only port numbers; the server takes the IP - * addresses from the query socket. - */ - - if ((rv = apr_bind(*newsock, localsa)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv, - "rfc1413: Error binding query socket to local port"); - apr_socket_close(*newsock); - return rv; - } - -/* - * errors from connect usually imply the remote machine doesn't support - * the service; don't log such an error - */ - if ((rv = apr_connect(*newsock, destsa)) != APR_SUCCESS) { - apr_socket_close(*newsock); - return rv; - } - - return APR_SUCCESS; -} - -static apr_status_t rfc1413_query(apr_socket_t *sock, conn_rec *conn, - server_rec *srv) -{ - apr_port_t rmt_port, our_port; - apr_port_t sav_rmt_port, sav_our_port; - apr_size_t i; - char *cp; - char buffer[RFC1413_MAXDATA + 1]; - char user[RFC1413_USERLEN + 1]; /* XXX */ - apr_size_t buflen; - apr_sockaddr_t *localsa; - - apr_socket_addr_get(&localsa, APR_LOCAL, sock); - apr_sockaddr_port_get(&sav_our_port, localsa); - sav_rmt_port = RFC1413_PORT; - - /* send the data */ - buflen = apr_snprintf(buffer, sizeof(buffer), "%hu,%hu\r\n", sav_rmt_port, - sav_our_port); - ap_xlate_proto_to_ascii(buffer, buflen); - - /* send query to server. Handle short write. */ - i = 0; - while (i < buflen) { - apr_size_t j = strlen(buffer + i); - apr_status_t status; - status = apr_send(sock, buffer+i, &j); - if (status != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, status, srv, - "write: rfc1413: error sending request"); - return status; - } - else if (j > 0) { - i+=j; - } - } - - /* - * Read response from server. - the response should be newline - * terminated according to rfc - make sure it doesn't stomp its - * way out of the buffer. - */ - - i = 0; - memset(buffer, '\0', sizeof(buffer)); - /* - * Note that the strchr function below checks for \012 instead of '\n' - * this allows it to work on both ASCII and EBCDIC machines. - */ - while((cp = strchr(buffer, '\012')) == NULL && i < sizeof(buffer) - 1) { - apr_size_t j = sizeof(buffer) - 1 - i; - apr_status_t status; - status = apr_recv(sock, buffer+i, &j); - if (status != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_CRIT, status, srv, - "read: rfc1413: error reading response"); - return status; - } - else if (j > 0) { - i+=j; - } - else if (status == APR_SUCCESS && j == 0) { - /* Oops... we ran out of data before finding newline */ - return APR_EINVAL; - } - } - -/* RFC1413_USERLEN = 512 */ - ap_xlate_proto_from_ascii(buffer, i); - if (sscanf(buffer, "%hu , %hu : USERID :%*[^:]:%512s", &rmt_port, &our_port, - user) != 3 || sav_rmt_port != rmt_port - || sav_our_port != our_port) - return APR_EINVAL; - - /* - * Strip trailing carriage return. It is part of the - * protocol, not part of the data. - */ - - if ((cp = strchr(user, '\r'))) - *cp = '\0'; - - conn->remote_logname = apr_pstrdup(conn->pool, user); - - return APR_SUCCESS; -} - -char *ap_rfc1413(conn_rec *conn, server_rec *srv) -{ - apr_socket_t *sock; - apr_status_t rv; - - rv = rfc1413_connect(&sock, conn, srv); - if (rv == APR_SUCCESS) { - rv = rfc1413_query(sock, conn, srv); - apr_socket_close(sock); - } - if (rv != APR_SUCCESS) { - conn->remote_logname = FROM_UNKNOWN; - } - return conn->remote_logname; -} diff --git a/server/scoreboard.c b/server/scoreboard.c deleted file mode 100644 index d93a84aaec..0000000000 --- a/server/scoreboard.c +++ /dev/null @@ -1,340 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_portable.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#include "ap_config.h" -#include "httpd.h" -#include "http_log.h" -#include "http_main.h" -#include "http_core.h" -#include "http_config.h" -#include "ap_mpm.h" - -#include "mpm.h" -#include "scoreboard.h" - -AP_DECLARE_DATA scoreboard *ap_scoreboard_image = NULL; -AP_DECLARE_DATA const char *ap_scoreboard_fname=NULL; -AP_DECLARE_DATA int ap_extended_status = 0; -AP_DECLARE_DATA apr_time_t ap_restart_time = 0; - -#if APR_HAS_SHARED_MEMORY -#include "apr_shmem.h" -static apr_shmem_t *scoreboard_shm = NULL; -#endif -/* - * ToDo: - * This function should be renamed to cleanup_shared - * and it should handle cleaning up a scoreboard shared - * between processes using any form of IPC (file, shared memory - * segment, etc.). Leave it as is now because it is being used - * by various MPMs. - */ -static apr_status_t ap_cleanup_shared_mem(void *d) -{ -#if APR_HAS_SHARED_MEMORY - apr_shm_free(scoreboard_shm, ap_scoreboard_image); - ap_scoreboard_image = NULL; - apr_shm_destroy(scoreboard_shm); -#endif - return APR_SUCCESS; -} - -/* ToDo: This function should be made to handle setting up - * a scoreboard shared between processes using any IPC technique, - * not just a shared memory segment - */ -static void setup_shared(apr_pool_t *p) -{ -#if APR_HAS_SHARED_MEMORY - char buf[512]; - char errmsg[120]; - const char *fname; - apr_status_t rv; - - fname = ap_server_root_relative(p, ap_scoreboard_fname); - rv = apr_shm_init(&scoreboard_shm, SCOREBOARD_SIZE, fname, p); - if (rv != APR_SUCCESS) { - apr_snprintf(buf, sizeof(buf), "%s: could not open(create) scoreboard: %s", - ap_server_argv0, apr_strerror(rv, errmsg, sizeof errmsg)); - fprintf(stderr, "%s\n", buf); - exit(APEXIT_INIT); - } - ap_scoreboard_image = apr_shm_malloc(scoreboard_shm, SCOREBOARD_SIZE); - if (ap_scoreboard_image == NULL) { - apr_snprintf(buf, sizeof(buf), "%s: cannot allocate scoreboard", - ap_server_argv0); - perror(buf); /* o.k. since MM sets errno */ - apr_shm_destroy(scoreboard_shm); - exit(APEXIT_INIT); - } - ap_scoreboard_image->global.running_generation = 0; -#endif -} - -AP_DECLARE(void) reopen_scoreboard(apr_pool_t *p) -{ -} - -/* ap_cleanup_scoreboard - * - */ -apr_status_t ap_cleanup_scoreboard(void *d) { - if (ap_scoreboard_image == NULL) - return APR_SUCCESS; - if (ap_scoreboard_image->global.sb_type == SB_SHARED) { - ap_cleanup_shared_mem(NULL); - } - else { - free(ap_scoreboard_image); - ap_scoreboard_image = NULL; - } - return APR_SUCCESS; -} - -/* ap_create_scoreboard(apr_pool_t*, ap_scoreboard_e t) - * - * Create or reinit an existing scoreboard. The MPM can control whether - * the scoreboard is shared across multiple processes or not - */ -AP_DECLARE(void) ap_create_scoreboard(apr_pool_t *p, ap_scoreboard_e sb_type) -{ - int running_gen = 0; - if (ap_scoreboard_image) - running_gen = ap_scoreboard_image->global.running_generation; - if (ap_scoreboard_image == NULL) { - if (sb_type == SB_SHARED) { - setup_shared(p); - } - else { - /* A simple malloc will suffice */ - char buf[512]; - ap_scoreboard_image = (scoreboard *) malloc(SCOREBOARD_SIZE); - if (ap_scoreboard_image == NULL) { - apr_snprintf(buf, sizeof(buf), "%s: cannot allocate scoreboard", - ap_server_argv0); - perror(buf); /* o.k. since MM sets errno */ - exit(APEXIT_INIT); - } - } - } - memset(ap_scoreboard_image, 0, SCOREBOARD_SIZE); - ap_scoreboard_image->global.sb_type = sb_type; - ap_scoreboard_image->global.running_generation = running_gen; - ap_restart_time = apr_time_now(); - apr_pool_cleanup_register(p, NULL, ap_cleanup_scoreboard, apr_pool_cleanup_null); -} - -/* 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. - */ - -void ap_sync_scoreboard_image(void) -{ -} - -AP_DECLARE(int) ap_exists_scoreboard_image(void) -{ - return (ap_scoreboard_image ? 1 : 0); -} - -static APR_INLINE void put_scoreboard_info(int child_num, int thread_num, - short_score *new_score_rec) -{ - /* XXX - needs to be fixed to account for threads */ -#ifdef SCOREBOARD_FILE - lseek(scoreboard_fd, (long) child_num * sizeof(short_score), 0); - force_write(scoreboard_fd, new_score_rec, sizeof(short_score)); -#endif -} - -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 -} - -AP_DECLARE(void) ap_increment_counts(int child_num, int thread_num, request_rec *r) -{ - short_score *ss; - - ss = &ap_scoreboard_image->servers[child_num][thread_num]; - -#ifdef HAVE_TIMES - times(&ss->times); -#endif - ss->access_count++; - ss->my_access_count++; - ss->conn_count++; - ss->bytes_served += r->bytes_sent; - ss->my_bytes_served += r->bytes_sent; - ss->conn_bytes += r->bytes_sent; - - put_scoreboard_info(child_num, thread_num, ss); -} - -AP_DECLARE(int) find_child_by_pid(apr_proc_t *pid) -{ - int i; - int max_daemons_limit; - - ap_mpm_query(AP_MPMQ_MAX_DAEMONS, &max_daemons_limit); - - for (i = 0; i < max_daemons_limit; ++i) - if (ap_scoreboard_image->parent[i].pid == pid->pid) - return i; - - return -1; -} - -int ap_update_child_status(int child_num, int thread_num, int status, request_rec *r) -{ - int old_status; - short_score *ss; - parent_score *ps; - - if (child_num < 0) - return -1; - - ss = &ap_scoreboard_image->servers[child_num][thread_num]; - old_status = ss->status; - ss->status = status; - - ps = &ap_scoreboard_image->parent[child_num]; - - if ((status == SERVER_READY || status == SERVER_ACCEPTING) - && old_status == SERVER_STARTING) { - ss->thread_num = child_num * HARD_SERVER_LIMIT + thread_num; - ps->worker_threads = ap_threads_per_child; - } - - if (ap_extended_status) { - 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; - apr_cpystrn(ss->client, ap_get_remote_host(c, r->per_dir_config, - REMOTE_NOLOOKUP, NULL), sizeof(ss->client)); - if (r->the_request == NULL) { - apr_cpystrn(ss->request, "NULL", sizeof(ss->request)); - } else if (r->parsed_uri.password == NULL) { - apr_cpystrn(ss->request, r->the_request, sizeof(ss->request)); - } else { - /* Don't reveal the password in the server-status view */ - apr_cpystrn(ss->request, apr_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; - } - } - - put_scoreboard_info(child_num, thread_num, ss); - return old_status; -} - -void ap_time_process_request(int child_num, int thread_num, int status) -{ - short_score *ss; - - if (child_num < 0) - return; - - ss = &ap_scoreboard_image->servers[child_num][thread_num]; - - if (status == START_PREQUEST) { - ss->start_time = apr_time_now(); - } - else if (status == STOP_PREQUEST) { - ss->stop_time = apr_time_now(); - } - put_scoreboard_info(child_num, thread_num, ss); -} - diff --git a/server/util.c b/server/util.c deleted file mode 100644 index 7ff05caa6e..0000000000 --- a/server/util.c +++ /dev/null @@ -1,1907 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * util.c: string utility things - * - * 3/21/93 Rob McCool - * 1995-96 Many changes by the Apache Software Foundation - * - */ - -/* Debugging aid: - * #define DEBUG to trace all cfg_open*()/cfg_closefile() calls - * #define DEBUG_CFG_LINES to trace every line read from the config files - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STDIO -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_UNISTD_H -#include <unistd.h> -#endif -#if APR_HAVE_NETDB_H -#include <netdb.h> /* for gethostbyname() */ -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "apr_base64.h" -#include "httpd.h" -#include "http_main.h" -#include "http_log.h" -#include "http_protocol.h" -#include "http_config.h" -#include "util_ebcdic.h" - -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#ifdef HAVE_GRP_H -#include <grp.h> -#endif - -/* A bunch of functions in util.c scan strings looking for certain characters. - * To make that more efficient we encode a lookup table. The test_char_table - * is generated automatically by gen_test_char.c. - */ -#include "test_char.h" - -/* we assume the folks using this ensure 0 <= c < 256... which means - * you need a cast to (unsigned char) first, you can't just plug a - * char in here and get it to work, because if char is signed then it - * will first be sign extended. - */ -#define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f)) - -/* - * Examine a field value (such as a media-/content-type) string and return - * it sans any parameters; e.g., strip off any ';charset=foo' and the like. - */ -AP_DECLARE(char *) ap_field_noparam(apr_pool_t *p, const char *intype) -{ - const char *semi; - - if (intype == NULL) return NULL; - - semi = ap_strchr_c(intype, ';'); - if (semi == NULL) { - return apr_pstrdup(p, intype); - } - else { - while ((semi > intype) && apr_isspace(semi[-1])) { - semi--; - } - return apr_pstrndup(p, intype, semi - intype); - } -} - -AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt, int gmt) -{ - apr_size_t retcode; - char ts[MAX_STRING_LEN]; - char tf[MAX_STRING_LEN]; - apr_exploded_time_t xt; - - if (gmt) { - const char *f; - char *strp; - - apr_explode_gmt(&xt, t); - /* Convert %Z to "GMT" and %z to "+0000"; - * on hosts that do not have a time zone string in struct tm, - * strftime must assume its argument is local time. - */ - for(strp = tf, f = fmt; strp < tf + sizeof(tf) - 6 && (*strp = *f) - ; f++, strp++) { - if (*f != '%') continue; - switch (f[1]) { - case '%': - *++strp = *++f; - break; - case 'Z': - *strp++ = 'G'; - *strp++ = 'M'; - *strp = 'T'; - f++; - break; - case 'z': /* common extension */ - *strp++ = '+'; - *strp++ = '0'; - *strp++ = '0'; - *strp++ = '0'; - *strp = '0'; - f++; - break; - } - } - *strp = '\0'; - fmt = tf; - } - else { - apr_explode_localtime(&xt, t); - } - - /* check return code? */ - apr_strftime(ts, &retcode, MAX_STRING_LEN, fmt, &xt); - ts[MAX_STRING_LEN - 1] = '\0'; - return apr_pstrdup(p, ts); -} - -/* Roy owes Rob beer. */ -/* Rob owes Roy dinner. */ - -/* These legacy comments would make a lot more sense if Roy hadn't - * replaced the old later_than() routine with util_date.c. - * - * Well, okay, they still wouldn't make any sense. - */ - -/* Match = 0, NoMatch = 1, Abort = -1 - * Based loosely on sections of wildmat.c by Rich Salz - * Hmmm... shouldn't this really go component by component? - */ -AP_DECLARE(int) ap_strcmp_match(const char *str, const char *exp) -{ - int x, y; - - for (x = 0, y = 0; exp[y]; ++y, ++x) { - if ((!str[x]) && (exp[y] != '*')) - return -1; - if (exp[y] == '*') { - while (exp[++y] == '*'); - if (!exp[y]) - return 0; - while (str[x]) { - int ret; - if ((ret = ap_strcmp_match(&str[x++], &exp[y])) != 1) - return ret; - } - return -1; - } - else if ((exp[y] != '?') && (str[x] != exp[y])) - return 1; - } - return (str[x] != '\0'); -} - -AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *exp) -{ - int x, y; - - for (x = 0, y = 0; exp[y]; ++y, ++x) { - if ((!str[x]) && (exp[y] != '*')) - return -1; - if (exp[y] == '*') { - while (exp[++y] == '*'); - if (!exp[y]) - return 0; - while (str[x]) { - int ret; - if ((ret = ap_strcasecmp_match(&str[x++], &exp[y])) != 1) - return ret; - } - return -1; - } - else if ((exp[y] != '?') && (apr_tolower(str[x]) != apr_tolower(exp[y]))) - return 1; - } - return (str[x] != '\0'); -} - -AP_DECLARE(int) ap_is_matchexp(const char *str) -{ - register int x; - - for (x = 0; str[x]; x++) - if ((str[x] == '*') || (str[x] == '?')) - return 1; - return 0; -} - -/* - * Here's a pool-based interface to POSIX regex's regcomp(). - * Note that we return regex_t instead of being passed one. - * The reason is that if you use an already-used regex_t structure, - * the memory that you've already allocated gets forgotten, and - * regfree() doesn't clear it. So we don't allow it. - */ - -static apr_status_t regex_cleanup(void *preg) -{ - regfree((regex_t *) preg); - return APR_SUCCESS; -} - -AP_DECLARE(regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern, - int cflags) -{ - regex_t *preg = apr_palloc(p, sizeof(regex_t)); - - if (regcomp(preg, pattern, cflags)) { - return NULL; - } - - apr_pool_cleanup_register(p, (void *) preg, regex_cleanup, regex_cleanup); - - return preg; -} - -AP_DECLARE(void) ap_pregfree(apr_pool_t *p, regex_t * reg) -{ - regfree(reg); - apr_pool_cleanup_kill(p, (void *) reg, regex_cleanup); -} - -/* - * Similar to standard strstr() but we ignore case in this version. - * Based on the strstr() implementation further below. - */ -AP_DECLARE(char *) ap_strcasestr(const char *s1, const char *s2) -{ - char *p1, *p2; - if (*s2 == '\0') { - /* an empty s2 */ - return((char *)s1); - } - while(1) { - for ( ; (*s1 != '\0') && (apr_tolower(*s1) != apr_tolower(*s2)); s1++); - if (*s1 == '\0') return(NULL); - /* found first character of s2, see if the rest matches */ - p1 = (char *)s1; - p2 = (char *)s2; - while (apr_tolower(*++p1) == apr_tolower(*++p2)) { - if (*p1 == '\0') { - /* both strings ended together */ - return((char *)s1); - } - } - if (*p2 == '\0') { - /* second string ended, a match */ - break; - } - /* didn't find a match here, try starting at next character in s1 */ - s1++; - } - return((char *)s1); -} - -/* - * Returns an offsetted pointer in bigstring immediately after - * prefix. Returns bigstring if bigstring doesn't start with - * prefix or if prefix is longer than bigstring while still matching. - * NOTE: pointer returned is relative to bigstring, so we - * can use standard pointer comparisons in the calling function - * (eg: test if ap_stripprefix(a,b) == a) - */ -AP_DECLARE(const char *) ap_stripprefix(const char *bigstring, - const char *prefix) -{ - const char *p1; - - if (*prefix == '\0') - return bigstring; - - p1 = bigstring; - while (*p1 && *prefix) { - if (*p1++ != *prefix++) - return bigstring; - } - if (*prefix == '\0') - return p1; - - /* hit the end of bigstring! */ - return bigstring; -} - -/* - * Apache stub function for the regex libraries regexec() to make sure the - * whole regex(3) API is available through the Apache (exported) namespace. - * This is especially important for the DSO situations of modules. - * DO NOT MAKE A MACRO OUT OF THIS FUNCTION! - */ -AP_DECLARE(int) ap_regexec(regex_t *preg, const char *string, - size_t nmatch, regmatch_t pmatch[], int eflags) -{ - return regexec(preg, string, nmatch, pmatch, eflags); -} - -AP_DECLARE(size_t) ap_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) -{ - return regerror(errcode, preg, errbuf, errbuf_size); -} - - -/* This function substitutes for $0-$9, filling in regular expression - * submatches. Pass it the same nmatch and pmatch arguments that you - * passed ap_regexec(). pmatch should not be greater than the maximum number - * of subexpressions - i.e. one more than the re_nsub member of regex_t. - * - * input should be the string with the $-expressions, source should be the - * string that was matched against. - * - * It returns the substituted string, or NULL on error. - * - * Parts of this code are based on Henry Spencer's regsub(), from his - * AT&T V8 regexp package. - */ - -AP_DECLARE(char *) ap_pregsub(apr_pool_t *p, const char *input, const char *source, - size_t nmatch, regmatch_t pmatch[]) -{ - const char *src = input; - char *dest, *dst; - char c; - size_t no; - int len; - - if (!source) - return NULL; - if (!nmatch) - return apr_pstrdup(p, src); - - /* First pass, find the size */ - - len = 0; - - while ((c = *src++) != '\0') { - if (c == '&') - no = 0; - else if (c == '$' && apr_isdigit(*src)) - no = *src++ - '0'; - else - no = 10; - - if (no > 9) { /* Ordinary character. */ - if (c == '\\' && (*src == '$' || *src == '&')) - c = *src++; - len++; - } - else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { - len += pmatch[no].rm_eo - pmatch[no].rm_so; - } - - } - - dest = dst = apr_pcalloc(p, len + 1); - - /* Now actually fill in the string */ - - src = input; - - while ((c = *src++) != '\0') { - if (c == '&') - no = 0; - else if (c == '$' && apr_isdigit(*src)) - no = *src++ - '0'; - else - no = 10; - - if (no > 9) { /* Ordinary character. */ - if (c == '\\' && (*src == '$' || *src == '&')) - c = *src++; - *dst++ = c; - } - else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { - len = pmatch[no].rm_eo - pmatch[no].rm_so; - memcpy(dst, source + pmatch[no].rm_so, len); - dst += len; - } - - } - *dst = '\0'; - - return dest; -} - -/* - * Parse .. so we don't compromise security - */ -AP_DECLARE(void) ap_getparents(char *name) -{ - int l, w; - - /* Four paseses, as per RFC 1808 */ - /* a) remove ./ path segments */ - - for (l = 0, w = 0; name[l] != '\0';) { - if (name[l] == '.' && name[l + 1] == '/' && (l == 0 || name[l - 1] == '/')) - l += 2; - else - name[w++] = name[l++]; - } - - /* b) remove trailing . path, segment */ - if (w == 1 && name[0] == '.') - w--; - else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/') - w--; - name[w] = '\0'; - - /* c) remove all xx/../ segments. (including leading ../ and /../) */ - l = 0; - - while (name[l] != '\0') { - if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' && - (l == 0 || name[l - 1] == '/')) { - register int m = l + 3, n; - - l = l - 2; - if (l >= 0) { - while (l >= 0 && name[l] != '/') - l--; - l++; - } - else - l = 0; - n = l; - while ((name[n] = name[m])) - (++n, ++m); - } - else - ++l; - } - - /* d) remove trailing xx/.. segment. */ - if (l == 2 && name[0] == '.' && name[1] == '.') - name[0] = '\0'; - else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.' && name[l - 3] == '/') { - l = l - 4; - if (l >= 0) { - while (l >= 0 && name[l] != '/') - l--; - l++; - } - else - l = 0; - name[l] = '\0'; - } -} - -AP_DECLARE(void) ap_no2slash(char *name) -{ - char *d, *s; - - s = d = name; - -#ifdef HAVE_UNC_PATHS - /* Check for UNC names. Leave leading two slashes. */ - if (s[0] == '/' && s[1] == '/') - *d++ = *s++; -#endif - - while (*s) { - if ((*d++ = *s) == '/') { - do { - ++s; - } while (*s == '/'); - } - else { - ++s; - } - } - *d = '\0'; -} - - -/* - * copy at most n leading directories of s into d - * d should be at least as large as s plus 1 extra byte - * assumes n > 0 - * the return value is the ever useful pointer to the trailing \0 of d - * - * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments, - * so that if n == 0, "/" is returned in d with n == 1 - * and s == "e:/test.html", "e:/" is returned in d - * *** See also directory_walk in modules/http/http_request.c - - * examples: - * /a/b, 0 ==> / (true for all platforms) - * /a/b, 1 ==> / - * /a/b, 2 ==> /a/ - * /a/b, 3 ==> /a/b/ - * /a/b, 4 ==> /a/b/ - * - * c:/a/b 0 ==> / - * c:/a/b 1 ==> c:/ - * c:/a/b 2 ==> c:/a/ - * c:/a/b 3 ==> c:/a/b - * c:/a/b 4 ==> c:/a/b - */ -AP_DECLARE(char *) ap_make_dirstr_prefix(char *d, const char *s, int n) -{ - if (n < 1) { - *d = '/'; - *++d = '\0'; - return (d); - } - - for (;;) { - if (*s == '\0' || (*s == '/' && (--n) == 0)) { - *d = '/'; - break; - } - *d++ = *s++; - } - *++d = 0; - return (d); -} - - -/* - * return the parent directory name including trailing / of the file s - */ -AP_DECLARE(char *) ap_make_dirstr_parent(apr_pool_t *p, const char *s) -{ - const char *last_slash = ap_strrchr_c(s, '/'); - char *d; - int l; - - if (last_slash == NULL) { - /* XXX: well this is really broken if this happens */ - return (apr_pstrdup(p, "/")); - } - l = (last_slash - s) + 1; - d = apr_palloc(p, l + 1); - memcpy(d, s, l); - d[l] = 0; - return (d); -} - - -AP_DECLARE(int) ap_count_dirs(const char *path) -{ - register int x, n; - - for (x = 0, n = 0; path[x]; x++) - if (path[x] == '/') - n++; - return n; -} - -AP_DECLARE(char *) ap_getword_nc(apr_pool_t *atrans, char **line, char stop) -{ - return ap_getword(atrans, (const char **) line, stop); -} - -AP_DECLARE(char *) ap_getword(apr_pool_t *atrans, const char **line, char stop) -{ - const char *pos = ap_strchr_c(*line, stop); - char *res; - - if (!pos) { - res = apr_pstrdup(atrans, *line); - *line += strlen(*line); - return res; - } - - res = apr_pstrndup(atrans, *line, pos - *line); - - while (*pos == stop) { - ++pos; - } - - *line = pos; - - return res; -} - -AP_DECLARE(char *) ap_getword_white_nc(apr_pool_t *atrans, char **line) -{ - return ap_getword_white(atrans, (const char **) line); -} - -AP_DECLARE(char *) ap_getword_white(apr_pool_t *atrans, const char **line) -{ - int pos = -1, x; - char *res; - - for (x = 0; (*line)[x]; x++) { - if (apr_isspace((*line)[x])) { - pos = x; - break; - } - } - - if (pos == -1) { - res = apr_pstrdup(atrans, *line); - *line += strlen(*line); - return res; - } - - res = apr_palloc(atrans, pos + 1); - apr_cpystrn(res, *line, pos + 1); - - while (apr_isspace((*line)[pos])) - ++pos; - - *line += pos; - - return res; -} - -AP_DECLARE(char *) ap_getword_nulls_nc(apr_pool_t *atrans, char **line, char stop) -{ - return ap_getword_nulls(atrans, (const char **) line, stop); -} - -AP_DECLARE(char *) ap_getword_nulls(apr_pool_t *atrans, const char **line, char stop) -{ - const char *pos = ap_strchr_c(*line, stop); - char *res; - - if (!pos) { - res = apr_pstrdup(atrans, *line); - *line += strlen(*line); - return res; - } - - res = apr_pstrndup(atrans, *line, pos - *line); - - ++pos; - - *line = pos; - - return res; -} - -/* Get a word, (new) config-file style --- quoted strings and backslashes - * all honored - */ - -static char *substring_conf(apr_pool_t *p, const char *start, int len, char quote) -{ - char *result = apr_palloc(p, len + 2); - char *resp = result; - int i; - - for (i = 0; i < len; ++i) { - if (start[i] == '\\' && (start[i + 1] == '\\' - || (quote && start[i + 1] == quote))) - *resp++ = start[++i]; - else - *resp++ = start[i]; - } - - *resp++ = '\0'; -#if RESOLVE_ENV_PER_TOKEN - return ap_resolve_env(p,result); -#else - return result; -#endif -} - -AP_DECLARE(char *) ap_getword_conf_nc(apr_pool_t *p, char **line) -{ - return ap_getword_conf(p, (const char **) line); -} - -AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line) -{ - const char *str = *line, *strend; - char *res; - char quote; - - while (*str && apr_isspace(*str)) - ++str; - - if (!*str) { - *line = str; - return ""; - } - - if ((quote = *str) == '"' || quote == '\'') { - strend = str + 1; - while (*strend && *strend != quote) { - if (*strend == '\\' && strend[1] && strend[1] == quote) - strend += 2; - else - ++strend; - } - res = substring_conf(p, str + 1, strend - str - 1, quote); - - if (*strend == quote) - ++strend; - } - else { - strend = str; - while (*strend && !apr_isspace(*strend)) - ++strend; - - res = substring_conf(p, str, strend - str, 0); - } - - while (*strend && apr_isspace(*strend)) - ++strend; - *line = strend; - return res; -} - -/* Check a string for any ${ENV} environment variable - * construct and replace each them by the value of - * that environment variable, if it exists. If the - * environment value does not exist, leave the ${ENV} - * construct alone; it means something else. - */ -AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word) -{ - char tmp[ MAX_STRING_LEN ]; - const char *s, *e; - tmp[0] = '\0'; - - if (!(s=ap_strchr_c(word,'$'))) - return word; - - do { - /* XXX - relies on strncat() to add '\0' - */ - strncat(tmp,word,s - word); - if ((s[1] == '{') && (e=ap_strchr_c(s,'}'))) { - const char *e2 = e; - word = e + 1; - e = getenv(s+2); - if (e) { - strcat(tmp,e); - } else { - strncat(tmp, s, e2-s); - strcat(tmp,"}"); - } - } else { - /* ignore invalid strings */ - word = s+1; - strcat(tmp,"$"); - }; - } while ((s=ap_strchr_c(word,'$'))); - strcat(tmp,word); - - return apr_pstrdup(p,tmp); -} -AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp) -{ -#ifdef DEBUG - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, - "Done with config file %s", cfp->name); -#endif - return (cfp->close == NULL) ? 0 : cfp->close(cfp->param); -} - -static apr_status_t cfg_close(void *param) -{ - apr_file_t *cfp = (apr_file_t *) param; - return (apr_file_close(cfp)); -} - -static int cfg_getch(void *param) -{ - char ch; - apr_file_t *cfp = (apr_file_t *) param; - if (apr_file_getc(&ch, cfp) == APR_SUCCESS) - return ch; - return (int)EOF; -} - -static void *cfg_getstr(void *buf, size_t bufsiz, void *param) -{ - apr_file_t *cfp = (apr_file_t *) param; - apr_status_t rv; - rv = apr_file_gets(buf, bufsiz, cfp); - if (rv == APR_SUCCESS || (rv == APR_EOF && strcmp(buf, ""))) - return buf; - return NULL; -} - -/* Open a ap_configfile_t as FILE, return open ap_configfile_t struct pointer */ -AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg, apr_pool_t *p, const char *name) -{ - ap_configfile_t *new_cfg; - apr_file_t *file = NULL; - apr_finfo_t finfo; - apr_status_t status; -#ifdef DEBUG - char buf[120]; -#endif - - if (name == NULL) { - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL, - "Internal error: pcfg_openfile() called with NULL filename"); - return APR_EBADF; - } - - /* ### We no longer need the test ap_os_is_filename_valid() here - * The directory was already walked on a segment by segment basis, - * so we should never be called with a bad path element, and device - * names as access file names never posed as security threats, since - * it was the admin's choice to assign the .htaccess file's name. - */ - - status = apr_file_open(&file, name, APR_READ | APR_BUFFERED, APR_OS_DEFAULT, p); -#ifdef DEBUG - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, NULL, - "Opening config file %s (%s)", - name, (status != APR_SUCCESS) ? - apr_strerror(status, buf, sizeof(buf)) : "successful"); -#endif - if (status != APR_SUCCESS) - return status; - - status = apr_file_info_get(&finfo, APR_FINFO_TYPE, file); - if (status != APR_SUCCESS) - return status; - - if (finfo.filetype != APR_REG && -#if defined(WIN32) || defined(OS2) - !(strcasecmp(name, "nul") == 0 || - (strlen(name) >= 4 && - strcasecmp(name + strlen(name) - 4, "/nul") == 0))) { -#else - strcmp(name, "/dev/null") != 0) { -#endif /* WIN32 || OS2 */ - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL, - "Access to file %s denied by server: not a regular file", - name); - apr_file_close(file); - return APR_EBADF; - } - - new_cfg = apr_palloc(p, sizeof(*new_cfg)); - new_cfg->param = file; - new_cfg->name = apr_pstrdup(p, name); - new_cfg->getch = (int (*)(void *)) cfg_getch; - new_cfg->getstr = (void *(*)(void *, size_t, void *)) cfg_getstr; - new_cfg->close = (int (*)(void *)) cfg_close; - new_cfg->line_number = 0; - *ret_cfg = new_cfg; - return APR_SUCCESS; -} - - -/* Allocate a ap_configfile_t handle with user defined functions and params */ -AP_DECLARE(ap_configfile_t *) ap_pcfg_open_custom(apr_pool_t *p, const char *descr, - void *param, - int(*getch)(void *param), - void *(*getstr) (void *buf, size_t bufsiz, void *param), - int(*close_func)(void *param)) -{ - ap_configfile_t *new_cfg = apr_palloc(p, sizeof(*new_cfg)); -#ifdef DEBUG - ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, 0, NULL, "Opening config handler %s", descr); -#endif - new_cfg->param = param; - new_cfg->name = descr; - new_cfg->getch = getch; - new_cfg->getstr = getstr; - new_cfg->close = close_func; - new_cfg->line_number = 0; - return new_cfg; -} - -/* Read one character from a configfile_t */ -AP_DECLARE(int) ap_cfg_getc(ap_configfile_t *cfp) -{ - register int ch = cfp->getch(cfp->param); - if (ch == LF) - ++cfp->line_number; - return ch; -} - -/* Read one line from open ap_configfile_t, strip LF, increase line number */ -/* If custom handler does not define a getstr() function, read char by char */ -AP_DECLARE(int) ap_cfg_getline(char *buf, size_t bufsize, ap_configfile_t *cfp) -{ - /* If a "get string" function is defined, use it */ - if (cfp->getstr != NULL) { - char *src, *dst; - char *cp; - char *cbuf = buf; - size_t cbufsize = bufsize; - - while (1) { - ++cfp->line_number; - if (cfp->getstr(cbuf, cbufsize, cfp->param) == NULL) - return 1; - - /* - * check for line continuation, - * i.e. match [^\\]\\[\r]\n only - */ - cp = cbuf; - while (cp < cbuf+cbufsize && *cp != '\0') - cp++; - if (cp > cbuf && cp[-1] == LF) { - cp--; - if (cp > cbuf && cp[-1] == CR) - cp--; - if (cp > cbuf && cp[-1] == '\\') { - cp--; - if (!(cp > cbuf && cp[-1] == '\\')) { - /* - * line continuation requested - - * then remove backslash and continue - */ - cbufsize -= (cp-cbuf); - cbuf = cp; - continue; - } - else { - /* - * no real continuation because escaped - - * then just remove escape character - */ - for ( ; cp < cbuf+cbufsize && *cp != '\0'; cp++) - cp[0] = cp[1]; - } - } - } - break; - } - - /* - * Leading and trailing white space is eliminated completely - */ - src = buf; - while (apr_isspace(*src)) - ++src; - /* blast trailing whitespace */ - dst = &src[strlen(src)]; - while (--dst >= src && apr_isspace(*dst)) - *dst = '\0'; - /* Zap leading whitespace by shifting */ - if (src != buf) - for (dst = buf; (*dst++ = *src++) != '\0'; ) - ; - -#ifdef DEBUG_CFG_LINES - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Read config: %s", buf); -#endif - return 0; - } else { - /* No "get string" function defined; read character by character */ - register int c; - register size_t i = 0; - - buf[0] = '\0'; - /* skip leading whitespace */ - do { - c = cfp->getch(cfp->param); - } while (c == '\t' || c == ' '); - - if (c == EOF) - return 1; - - if(bufsize < 2) { - /* too small, assume caller is crazy */ - return 1; - } - - while (1) { - if ((c == '\t') || (c == ' ')) { - buf[i++] = ' '; - while ((c == '\t') || (c == ' ')) - c = cfp->getch(cfp->param); - } - if (c == CR) { - /* silently ignore CR (_assume_ that a LF follows) */ - c = cfp->getch(cfp->param); - } - if (c == LF) { - /* increase line number and return on LF */ - ++cfp->line_number; - } - if (c == EOF || c == 0x4 || c == LF || i >= (bufsize - 2)) { - /* - * check for line continuation - */ - if (i > 0 && buf[i-1] == '\\') { - i--; - if (!(i > 0 && buf[i-1] == '\\')) { - /* line is continued */ - c = cfp->getch(cfp->param); - continue; - } - /* else nothing needs be done because - * then the backslash is escaped and - * we just strip to a single one - */ - } - /* blast trailing whitespace */ - while (i > 0 && apr_isspace(buf[i - 1])) - --i; - buf[i] = '\0'; -#ifdef DEBUG_CFG_LINES - ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Read config: %s", buf); -#endif - return 0; - } - buf[i] = c; - ++i; - c = cfp->getch(cfp->param); - } - } -} - -/* Size an HTTP header field list item, as separated by a comma. - * The return value is a pointer to the beginning of the non-empty list item - * within the original string (or NULL if there is none) and the address - * of field is shifted to the next non-comma, non-whitespace character. - * len is the length of the item excluding any beginning whitespace. - */ -AP_DECLARE(const char *) ap_size_list_item(const char **field, int *len) -{ - const unsigned char *ptr = (const unsigned char *)*field; - const unsigned char *token; - int in_qpair, in_qstr, in_com; - - /* Find first non-comma, non-whitespace byte */ - - while (*ptr == ',' || apr_isspace(*ptr)) - ++ptr; - - token = ptr; - - /* Find the end of this item, skipping over dead bits */ - - for (in_qpair = in_qstr = in_com = 0; - *ptr && (in_qpair || in_qstr || in_com || *ptr != ','); - ++ptr) { - - if (in_qpair) { - in_qpair = 0; - } - else { - switch (*ptr) { - case '\\': in_qpair = 1; /* quoted-pair */ - break; - case '"' : if (!in_com) /* quoted string delim */ - in_qstr = !in_qstr; - break; - case '(' : if (!in_qstr) /* comment (may nest) */ - ++in_com; - break; - case ')' : if (in_com) /* end comment */ - --in_com; - break; - default : break; - } - } - } - - if ((*len = (ptr - token)) == 0) { - *field = (const char *)ptr; - return NULL; - } - - /* Advance field pointer to the next non-comma, non-white byte */ - - while (*ptr == ',' || apr_isspace(*ptr)) - ++ptr; - - *field = (const char *)ptr; - return (const char *)token; -} - -/* Retrieve an HTTP header field list item, as separated by a comma, - * while stripping insignificant whitespace and lowercasing anything not in - * a quoted string or comment. The return value is a new string containing - * the converted list item (or NULL if none) and the address pointed to by - * field is shifted to the next non-comma, non-whitespace. - */ -AP_DECLARE(char *) ap_get_list_item(apr_pool_t *p, const char **field) -{ - const char *tok_start; - const unsigned char *ptr; - unsigned char *pos; - char *token; - int addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0, tok_len = 0; - - /* Find the beginning and maximum length of the list item so that - * we can allocate a buffer for the new string and reset the field. - */ - if ((tok_start = ap_size_list_item(field, &tok_len)) == NULL) { - return NULL; - } - token = apr_palloc(p, tok_len + 1); - - /* Scan the token again, but this time copy only the good bytes. - * We skip extra whitespace and any whitespace around a '=', '/', - * or ';' and lowercase normal characters not within a comment, - * quoted-string or quoted-pair. - */ - for (ptr = (const unsigned char *)tok_start, pos = (unsigned char *)token; - *ptr && (in_qpair || in_qstr || in_com || *ptr != ','); - ++ptr) { - - if (in_qpair) { - in_qpair = 0; - *pos++ = *ptr; - } - else { - switch (*ptr) { - case '\\': in_qpair = 1; - if (addspace == 1) - *pos++ = ' '; - *pos++ = *ptr; - addspace = 0; - break; - case '"' : if (!in_com) - in_qstr = !in_qstr; - if (addspace == 1) - *pos++ = ' '; - *pos++ = *ptr; - addspace = 0; - break; - case '(' : if (!in_qstr) - ++in_com; - if (addspace == 1) - *pos++ = ' '; - *pos++ = *ptr; - addspace = 0; - break; - case ')' : if (in_com) - --in_com; - *pos++ = *ptr; - addspace = 0; - break; - case ' ' : - case '\t': if (addspace) - break; - if (in_com || in_qstr) - *pos++ = *ptr; - else - addspace = 1; - break; - case '=' : - case '/' : - case ';' : if (!(in_com || in_qstr)) - addspace = -1; - *pos++ = *ptr; - break; - default : if (addspace == 1) - *pos++ = ' '; - *pos++ = (in_com || in_qstr) ? *ptr - : apr_tolower(*ptr); - addspace = 0; - break; - } - } - } - *pos = '\0'; - - return token; -} - -/* Find an item in canonical form (lowercase, no extra spaces) within - * an HTTP field value list. Returns 1 if found, 0 if not found. - * This would be much more efficient if we stored header fields as - * an array of list items as they are received instead of a plain string. - */ -AP_DECLARE(int) ap_find_list_item(apr_pool_t *p, const char *line, const char *tok) -{ - const unsigned char *pos; - const unsigned char *ptr = (const unsigned char *)line; - int good = 0, addspace = 0, in_qpair = 0, in_qstr = 0, in_com = 0; - - if (!line || !tok) - return 0; - - do { /* loop for each item in line's list */ - - /* Find first non-comma, non-whitespace byte */ - - while (*ptr == ',' || apr_isspace(*ptr)) - ++ptr; - - if (*ptr) - good = 1; /* until proven otherwise for this item */ - else - break; /* no items left and nothing good found */ - - /* We skip extra whitespace and any whitespace around a '=', '/', - * or ';' and lowercase normal characters not within a comment, - * quoted-string or quoted-pair. - */ - for (pos = (const unsigned char *)tok; - *ptr && (in_qpair || in_qstr || in_com || *ptr != ','); - ++ptr) { - - if (in_qpair) { - in_qpair = 0; - if (good) - good = (*pos++ == *ptr); - } - else { - switch (*ptr) { - case '\\': in_qpair = 1; - if (addspace == 1) - good = good && (*pos++ == ' '); - good = good && (*pos++ == *ptr); - addspace = 0; - break; - case '"' : if (!in_com) - in_qstr = !in_qstr; - if (addspace == 1) - good = good && (*pos++ == ' '); - good = good && (*pos++ == *ptr); - addspace = 0; - break; - case '(' : if (!in_qstr) - ++in_com; - if (addspace == 1) - good = good && (*pos++ == ' '); - good = good && (*pos++ == *ptr); - addspace = 0; - break; - case ')' : if (in_com) - --in_com; - good = good && (*pos++ == *ptr); - addspace = 0; - break; - case ' ' : - case '\t': if (addspace || !good) - break; - if (in_com || in_qstr) - good = (*pos++ == *ptr); - else - addspace = 1; - break; - case '=' : - case '/' : - case ';' : if (!(in_com || in_qstr)) - addspace = -1; - good = good && (*pos++ == *ptr); - break; - default : if (!good) - break; - if (addspace == 1) - good = (*pos++ == ' '); - if (in_com || in_qstr) - good = good && (*pos++ == *ptr); - else - good = good && (*pos++ == apr_tolower(*ptr)); - addspace = 0; - break; - } - } - } - if (good && *pos) - good = 0; /* not good if only a prefix was matched */ - - } while (*ptr && !good); - - return good; -} - - -/* Retrieve a token, spacing over it and returning a pointer to - * the first non-white byte afterwards. Note that these tokens - * are delimited by semis and commas; and can also be delimited - * by whitespace at the caller's option. - */ - -AP_DECLARE(char *) ap_get_token(apr_pool_t *p, const char **accept_line, int accept_white) -{ - const char *ptr = *accept_line; - const char *tok_start; - char *token; - int tok_len; - - /* Find first non-white byte */ - - while (*ptr && apr_isspace(*ptr)) - ++ptr; - - tok_start = ptr; - - /* find token end, skipping over quoted strings. - * (comments are already gone). - */ - - while (*ptr && (accept_white || !apr_isspace(*ptr)) - && *ptr != ';' && *ptr != ',') { - if (*ptr++ == '"') - while (*ptr) - if (*ptr++ == '"') - break; - } - - tok_len = ptr - tok_start; - token = apr_pstrndup(p, tok_start, tok_len); - - /* Advance accept_line pointer to the next non-white byte */ - - while (*ptr && apr_isspace(*ptr)) - ++ptr; - - *accept_line = ptr; - return token; -} - - -/* find http tokens, see the definition of token from RFC2068 */ -AP_DECLARE(int) ap_find_token(apr_pool_t *p, const char *line, const char *tok) -{ - const unsigned char *start_token; - const unsigned char *s; - - if (!line) - return 0; - - s = (const unsigned char *)line; - for (;;) { - /* find start of token, skip all stop characters, note NUL - * isn't a token stop, so we don't need to test for it - */ - while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) { - ++s; - } - if (!*s) { - return 0; - } - start_token = s; - /* find end of the token */ - while (*s && !TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) { - ++s; - } - if (!strncasecmp((const char *)start_token, (const char *)tok, s - start_token)) { - return 1; - } - if (!*s) { - return 0; - } - } -} - - -AP_DECLARE(int) ap_find_last_token(apr_pool_t *p, const char *line, const char *tok) -{ - int llen, tlen, lidx; - - if (!line) - return 0; - - llen = strlen(line); - tlen = strlen(tok); - lidx = llen - tlen; - - if ((lidx < 0) || - ((lidx > 0) && !(apr_isspace(line[lidx - 1]) || line[lidx - 1] == ','))) - return 0; - - return (strncasecmp(&line[lidx], tok, tlen) == 0); -} - -AP_DECLARE(char *) ap_escape_shell_cmd(apr_pool_t *p, const char *str) -{ - char *cmd; - unsigned char *d; - const unsigned char *s; - - cmd = apr_palloc(p, 2 * strlen(str) + 1); /* Be safe */ - d = (unsigned char *)cmd; - s = (const unsigned char *)str; - for (; *s; ++s) { - -#if defined(OS2) || defined(WIN32) - /* Don't allow '&' in parameters under OS/2. */ - /* This can be used to send commands to the shell. */ - if (*s == '&') { - *d++ = ' '; - continue; - } -#endif - - if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) { - *d++ = '\\'; - } - *d++ = *s; - } - *d = '\0'; - - return cmd; -} - -static char x2c(const char *what) -{ - register char digit; - -#if !APR_CHARSET_EBCDIC - digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); - digit *= 16; - digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); -#else /*APR_CHARSET_EBCDIC*/ - char xstr[5]; - xstr[0]='0'; - xstr[1]='x'; - xstr[2]=what[0]; - xstr[3]=what[1]; - xstr[4]='\0'; - digit = apr_xlate_conv_byte(ap_hdrs_from_ascii, 0xFF & strtol(xstr, NULL, 16)); -#endif /*APR_CHARSET_EBCDIC*/ - return (digit); -} - -/* - * Unescapes a URL. - * Returns 0 on success, non-zero on error - * Failure is due to - * bad % escape returns HTTP_BAD_REQUEST - * - * decoding %00 -> \0 - * decoding %2f -> / (a special character) - * returns HTTP_NOT_FOUND - */ -AP_DECLARE(int) ap_unescape_url(char *url) -{ - register int badesc, badpath; - char *x, *y; - - badesc = 0; - badpath = 0; - /* Initial scan for first '%'. Don't bother writing values before - * seeing a '%' */ - y = strchr(url, '%'); - if (y == NULL) { - return OK; - } - for (x = y; *y; ++x, ++y) { - if (*y != '%') - *x = *y; - else { - if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) { - badesc = 1; - *x = '%'; - } - else { - *x = x2c(y + 1); - y += 2; - if (*x == '/' || *x == '\0') - badpath = 1; - } - } - } - *x = '\0'; - if (badesc) - return HTTP_BAD_REQUEST; - else if (badpath) - return HTTP_NOT_FOUND; - else - return OK; -} - -AP_DECLARE(char *) ap_construct_server(apr_pool_t *p, const char *hostname, - apr_port_t port, const request_rec *r) -{ - if (ap_is_default_port(port, r)) - return apr_pstrdup(p, hostname); - else { - return apr_psprintf(p, "%s:%u", hostname, port); - } -} - -/* c2x takes an unsigned, and expects the caller has guaranteed that - * 0 <= what < 256... which usually means that you have to cast to - * unsigned char first, because (unsigned)(char)(x) first goes through - * signed extension to an int before the unsigned cast. - * - * The reason for this assumption is to assist gcc code generation -- - * the unsigned char -> unsigned extension is already done earlier in - * both uses of this code, so there's no need to waste time doing it - * again. - */ -static const char c2x_table[] = "0123456789abcdef"; - -static APR_INLINE unsigned char *c2x(unsigned what, unsigned char *where) -{ -#if APR_CHARSET_EBCDIC - what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what); -#endif /*APR_CHARSET_EBCDIC*/ - *where++ = '%'; - *where++ = c2x_table[what >> 4]; - *where++ = c2x_table[what & 0xf]; - return where; -} - -/* - * escape_path_segment() escapes a path segment, as defined in RFC 1808. This - * routine is (should be) OS independent. - * - * os_escape_path() converts an OS path to a URL, in an OS dependent way. In all - * cases if a ':' occurs before the first '/' in the URL, the URL should be - * prefixed with "./" (or the ':' escaped). In the case of Unix, this means - * leaving '/' alone, but otherwise doing what escape_path_segment() does. For - * efficiency reasons, we don't use escape_path_segment(), which is provided for - * reference. Again, RFC 1808 is where this stuff is defined. - * - * If partial is set, os_escape_path() assumes that the path will be appended to - * something with a '/' in it (and thus does not prefix "./"). - */ - -AP_DECLARE(char *) ap_escape_path_segment(apr_pool_t *p, const char *segment) -{ - char *copy = apr_palloc(p, 3 * strlen(segment) + 1); - const unsigned char *s = (const unsigned char *)segment; - unsigned char *d = (unsigned char *)copy; - unsigned c; - - while ((c = *s)) { - if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) { - d = c2x(c, d); - } - else { - *d++ = c; - } - ++s; - } - *d = '\0'; - return copy; -} - -AP_DECLARE(char *) ap_os_escape_path(apr_pool_t *p, const char *path, int partial) -{ - char *copy = apr_palloc(p, 3 * strlen(path) + 3); - const unsigned char *s = (const unsigned char *)path; - unsigned char *d = (unsigned char *)copy; - unsigned c; - - if (!partial) { - const char *colon = ap_strchr_c(path, ':'); - const char *slash = ap_strchr_c(path, '/'); - - if (colon && (!slash || colon < slash)) { - *d++ = '.'; - *d++ = '/'; - } - } - while ((c = *s)) { - if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) { - d = c2x(c, d); - } - else { - *d++ = c; - } - ++s; - } - *d = '\0'; - return copy; -} - -/* ap_escape_uri is now a macro for os_escape_path */ - -AP_DECLARE(char *) ap_escape_html(apr_pool_t *p, const char *s) -{ - int i, j; - char *x; - - /* first, count the number of extra characters */ - for (i = 0, j = 0; s[i] != '\0'; i++) - if (s[i] == '<' || s[i] == '>') - j += 3; - else if (s[i] == '&') - j += 4; - - if (j == 0) - return apr_pstrndup(p, s, i); - - x = apr_palloc(p, i + j + 1); - for (i = 0, j = 0; s[i] != '\0'; i++, j++) - if (s[i] == '<') { - memcpy(&x[j], "<", 4); - j += 3; - } - else if (s[i] == '>') { - memcpy(&x[j], ">", 4); - j += 3; - } - else if (s[i] == '&') { - memcpy(&x[j], "&", 5); - j += 4; - } - else - x[j] = s[i]; - - x[j] = '\0'; - return x; -} - -AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path) -{ - apr_finfo_t finfo; - - if (apr_stat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS) - return 0; /* in error condition, just return no */ - - return (finfo.filetype == APR_DIR); -} - -AP_DECLARE(int) ap_is_rdirectory(apr_pool_t *p, const char *path) -{ - apr_finfo_t finfo; - - if (apr_lstat(&finfo, path, APR_FINFO_TYPE, p) != APR_SUCCESS) - return 0; /* in error condition, just return no */ - - return (finfo.filetype == APR_DIR); -} - -AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1, - const char *src2) -{ - register int x; - - x = strlen(src1); - if (x == 0) - return apr_pstrcat(a, "/", src2, NULL); - - if (src1[x - 1] != '/') - return apr_pstrcat(a, src1, "/", src2, NULL); - else - return apr_pstrcat(a, src1, src2, NULL); -} - -/* - * Check for an absoluteURI syntax (see section 3.2 in RFC2068). - */ -AP_DECLARE(int) ap_is_url(const char *u) -{ - register int x; - - for (x = 0; u[x] != ':'; x++) { - if ((!u[x]) || - ((!apr_isalpha(u[x])) && (!apr_isdigit(u[x])) && - (u[x] != '+') && (u[x] != '-') && (u[x] != '.'))) { - return 0; - } - } - - return (x ? 1 : 0); /* If the first character is ':', it's broken, too */ -} - -AP_DECLARE(int) ap_ind(const char *s, char c) -{ - const char *p = ap_strchr_c(s, c); - - if (p == NULL) - return -1; - return p - s; -} - -AP_DECLARE(int) ap_rind(const char *s, char c) -{ - const char *p = ap_strrchr_c(s, c); - - if (p == NULL) - return -1; - return p - s; -} - -AP_DECLARE(void) ap_str_tolower(char *str) -{ - while (*str) { - *str = apr_tolower(*str); - ++str; - } -} - -static char *find_fqdn(apr_pool_t *a, struct hostent *p) -{ - int x; - - if (!strchr(p->h_name, '.')) { - for (x = 0; p->h_aliases[x]; ++x) { - if (strchr(p->h_aliases[x], '.') && - (!strncasecmp(p->h_aliases[x], p->h_name, strlen(p->h_name)))) - return apr_pstrdup(a, p->h_aliases[x]); - } - return NULL; - } - return apr_pstrdup(a, (void *) p->h_name); -} - -char *ap_get_local_host(apr_pool_t *a) -{ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - char str[MAXHOSTNAMELEN + 1]; - char *server_hostname = NULL; - struct hostent *p; - -#ifdef BEOS_R5 - if (gethostname(str, sizeof(str) - 1) == 0) -#else - if (gethostname(str, sizeof(str) - 1) != 0) -#endif - { - ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_WARNING, 0, a, - "%s: gethostname() failed to determine ServerName", - ap_server_argv0); - } - else - { - str[sizeof(str) - 1] = '\0'; - if ((!(p = gethostbyname(str))) - || (!(server_hostname = find_fqdn(a, p)))) { - /* Recovery - return the default servername by IP: */ - if (p && p->h_addr_list[0]) { - apr_snprintf(str, sizeof(str), "%pA", p->h_addr_list[0]); - server_hostname = apr_pstrdup(a, str); - /* We will drop through to report the IP-named server */ - } - } - else { - /* Since we found a fdqn, return it with no logged message. */ - return server_hostname; - } - } - - if (!server_hostname) - server_hostname = apr_pstrdup(a, "127.0.0.1"); - - ap_log_perror(APLOG_MARK, APLOG_ALERT|APLOG_NOERRNO|APLOG_STARTUP, 0, a, - "%s: Could not determine the server's fully qualified " - "domain name, using %s for ServerName", - ap_server_argv0, server_hostname); - - return server_hostname; -} - -/* simple 'pool' alloc()ing glue to apr_base64.c - */ -AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded) -{ - char *decoded; - int l; - - decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded)); - l = apr_base64_decode(decoded, bufcoded); - decoded[l] = '\0'; /* make binary sequence into string */ - - return decoded; -} - -AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string) -{ - char *encoded; - int l = strlen(string); - - encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(l)); - l = apr_base64_encode(encoded, string, l); - encoded[l] = '\0'; /* make binary sequence into string */ - - return encoded; -} - -/* we want to downcase the type/subtype for comparison purposes - * but nothing else because ;parameter=foo values are case sensitive. - * XXX: in truth we want to downcase parameter names... but really, - * apache has never handled parameters and such correctly. You - * also need to compress spaces and such to be able to compare - * properly. -djg - */ -AP_DECLARE(void) ap_content_type_tolower(char *str) -{ - char *semi; - - semi = strchr(str, ';'); - if (semi) { - *semi = '\0'; - } - while (*str) { - *str = apr_tolower(*str); - ++str; - } - if (semi) { - *semi = ';'; - } -} - -/* - * Given a string, replace any bare " with \" . - */ -AP_DECLARE(char *) ap_escape_quotes (apr_pool_t *p, const char *instring) -{ - int newlen = 0; - const char *inchr = instring; - char *outchr, *outstring; - - /* - * Look through the input string, jogging the length of the output - * string up by an extra byte each time we find an unescaped ". - */ - while (*inchr != '\0') { - newlen++; - if (*inchr == '"') { - newlen++; - } - /* - * If we find a slosh, and it's not the last byte in the string, - * it's escaping something - advance past both bytes. - */ - if ((*inchr == '\\') && (inchr[1] != '\0')) { - inchr++; - newlen++; - } - inchr++; - } - outstring = apr_palloc(p, newlen + 1); - inchr = instring; - outchr = outstring; - /* - * Now copy the input string to the output string, inserting a slosh - * in front of every " that doesn't already have one. - */ - while (*inchr != '\0') { - if ((*inchr == '\\') && (inchr[1] != '\0')) { - *outchr++ = *inchr++; - *outchr++ = *inchr++; - } - if (*inchr == '"') { - *outchr++ = '\\'; - } - if (*inchr != '\0') { - *outchr++ = *inchr++; - } - } - *outchr = '\0'; - return outstring; -} diff --git a/server/util_cfgtree.c b/server/util_cfgtree.c deleted file mode 100644 index b8fcad6c9c..0000000000 --- a/server/util_cfgtree.c +++ /dev/null @@ -1,89 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#define CORE_PRIVATE -#include "util_cfgtree.h" -#include <stdlib.h> - -ap_directive_t *ap_add_node(ap_directive_t **parent, ap_directive_t *current, - ap_directive_t *toadd, int child) -{ - if (current == NULL) { - /* we just started a new parent */ - if (*parent != NULL) { - (*parent)->first_child = toadd; - toadd->parent = *parent; - } - if (child) { - /* First item in config file or container is a container */ - *parent = toadd; - return NULL; - } - return toadd; - } - current->next = toadd; - toadd->parent = *parent; - if (child) { - /* switch parents, navigate into child */ - *parent = toadd; - return NULL; - } - return toadd; -} - - diff --git a/server/util_charset.c b/server/util_charset.c deleted file mode 100644 index f1833b94d6..0000000000 --- a/server/util_charset.c +++ /dev/null @@ -1,99 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "ap_config.h" - -#ifdef APACHE_XLATE - -#include "httpd.h" -#include "http_log.h" -#include "http_core.h" -#include "util_charset.h" - -/* ap_hdrs_to_ascii, ap_hdrs_from_ascii - * - * These are the translation handles used to translate between the network - * format of protocol headers and the local machine format. - * - * For an EBCDIC machine, these are valid handles which are set up at - * initialization to translate between ISO-8859-1 and the code page of - * the source code. - * - * For an ASCII machine, these remain NULL so that when they are stored - * in the BUFF via ap_bsetop(BO_RXLATE) it ensures that no translation is - * performed. - */ - -apr_xlate_t *ap_hdrs_to_ascii, *ap_hdrs_from_ascii; - -/* ap_locale_to_ascii, ap_locale_from_ascii - * - * These handles are used for the translation of content, unless a - * configuration module overrides them. - * - * For an EBCDIC machine, these are valid handles which are set up at - * initialization to translate between ISO-8859-1 and the code page of - * the httpd process's locale. - * - * For an ASCII machine, these remain NULL so that no translation is - * performed (unless a configuration module does something, of course). - */ - -apr_xlate_t *ap_locale_to_ascii, *ap_locale_from_ascii; - -#endif /*APACHE_XLATE*/ diff --git a/server/util_date.c b/server/util_date.c deleted file mode 100644 index 89ceaa5d8d..0000000000 --- a/server/util_date.c +++ /dev/null @@ -1,306 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * util_date.c: date parsing utility routines - * These routines are (hopefully) platform independent. - * - * 27 Oct 1996 Roy Fielding - * Extracted (with many modifications) from mod_proxy.c and - * tested with over 50,000 randomly chosen valid date strings - * and several hundred variations of invalid date strings. - * - */ - -#include "apr.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_CTYPE_H -#include <ctype.h> -#endif - -#define CORE_PRIVATE - -#include "ap_config.h" -#include "util_date.h" - -/* - * Compare a string to a mask - * Mask characters (arbitrary maximum is 256 characters, just in case): - * @ - uppercase letter - * $ - lowercase letter - * & - hex digit - * # - digit - * ~ - digit or space - * * - swallow remaining characters - * <x> - exact match for any other character - */ -AP_DECLARE(int) ap_checkmask(const char *data, const char *mask) -{ - int i; - char d; - - for (i = 0; i < 256; i++) { - d = data[i]; - switch (mask[i]) { - case '\0': - return (d == '\0'); - - case '*': - return 1; - - case '@': - if (!apr_isupper(d)) - return 0; - break; - case '$': - if (!apr_islower(d)) - return 0; - break; - case '#': - if (!apr_isdigit(d)) - return 0; - break; - case '&': - if (!apr_isxdigit(d)) - return 0; - break; - case '~': - if ((d != ' ') && !apr_isdigit(d)) - return 0; - break; - default: - if (mask[i] != d) - return 0; - break; - } - } - return 0; /* We only get here if mask is corrupted (exceeds 256) */ -} - - -/* - * Parses an HTTP date in one of three standard forms: - * - * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 - * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 - * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format - * - * and returns the time_t number of seconds since 1 Jan 1970 GMT, or - * 0 if this would be out of range or if the date is invalid. - * - * The restricted HTTP syntax is - * - * HTTP-date = rfc1123-date | rfc850-date | asctime-date - * - * rfc1123-date = wkday "," SP date1 SP time SP "GMT" - * rfc850-date = weekday "," SP date2 SP time SP "GMT" - * asctime-date = wkday SP date3 SP time SP 4DIGIT - * - * date1 = 2DIGIT SP month SP 4DIGIT - * ; day month year (e.g., 02 Jun 1982) - * date2 = 2DIGIT "-" month "-" 2DIGIT - * ; day-month-year (e.g., 02-Jun-82) - * date3 = month SP ( 2DIGIT | ( SP 1DIGIT )) - * ; month day (e.g., Jun 2) - * - * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT - * ; 00:00:00 - 23:59:59 - * - * wkday = "Mon" | "Tue" | "Wed" - * | "Thu" | "Fri" | "Sat" | "Sun" - * - * weekday = "Monday" | "Tuesday" | "Wednesday" - * | "Thursday" | "Friday" | "Saturday" | "Sunday" - * - * month = "Jan" | "Feb" | "Mar" | "Apr" - * | "May" | "Jun" | "Jul" | "Aug" - * | "Sep" | "Oct" | "Nov" | "Dec" - * - * However, for the sake of robustness (and Netscapeness), we ignore the - * weekday and anything after the time field (including the timezone). - * - * This routine is intended to be very fast; 10x faster than using sscanf. - * - * Originally from Andrew Daviel <andrew@vancouver-webpages.com>, 29 Jul 96 - * but many changes since then. - * - */ -AP_DECLARE(apr_time_t) ap_parseHTTPdate(const char *date) -{ - apr_exploded_time_t ds; - apr_time_t result; - int mint, mon; - const char *monstr, *timstr; - static const int months[12] = - { - ('J' << 16) | ('a' << 8) | 'n', ('F' << 16) | ('e' << 8) | 'b', - ('M' << 16) | ('a' << 8) | 'r', ('A' << 16) | ('p' << 8) | 'r', - ('M' << 16) | ('a' << 8) | 'y', ('J' << 16) | ('u' << 8) | 'n', - ('J' << 16) | ('u' << 8) | 'l', ('A' << 16) | ('u' << 8) | 'g', - ('S' << 16) | ('e' << 8) | 'p', ('O' << 16) | ('c' << 8) | 't', - ('N' << 16) | ('o' << 8) | 'v', ('D' << 16) | ('e' << 8) | 'c'}; - - if (!date) - return BAD_DATE; - - while (*date && apr_isspace(*date)) /* Find first non-whitespace char */ - ++date; - - if (*date == '\0') - return BAD_DATE; - - if ((date = strchr(date, ' ')) == NULL) /* Find space after weekday */ - return BAD_DATE; - - ++date; /* Now pointing to first char after space, which should be */ - /* start of the actual date information for all 3 formats. */ - - if (ap_checkmask(date, "## @$$ #### ##:##:## *")) { /* RFC 1123 format */ - ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100; - if (ds.tm_year < 0) - return BAD_DATE; - - ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0'); - - ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); - - monstr = date + 3; - timstr = date + 12; - } - else if (ap_checkmask(date, "##-@$$-## ##:##:## *")) { /* RFC 850 format */ - ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0'); - if (ds.tm_year < 70) - ds.tm_year += 100; - - ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0'); - - monstr = date + 3; - timstr = date + 10; - } - else if (ap_checkmask(date, "@$$ ~# ##:##:## ####*")) { /* asctime format */ - ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100; - if (ds.tm_year < 0) - return BAD_DATE; - - ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0'); - - if (date[4] == ' ') - ds.tm_mday = 0; - else - ds.tm_mday = (date[4] - '0') * 10; - - ds.tm_mday += (date[5] - '0'); - - monstr = date; - timstr = date + 7; - } - else - return BAD_DATE; - - if (ds.tm_mday <= 0 || ds.tm_mday > 31) - return BAD_DATE; - - ds.tm_hour = ((timstr[0] - '0') * 10) + (timstr[1] - '0'); - ds.tm_min = ((timstr[3] - '0') * 10) + (timstr[4] - '0'); - ds.tm_sec = ((timstr[6] - '0') * 10) + (timstr[7] - '0'); - - if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61)) - return BAD_DATE; - - mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2]; - for (mon = 0; mon < 12; mon++) - if (mint == months[mon]) - break; - if (mon == 12) - return BAD_DATE; - - if ((ds.tm_mday == 31) && (mon == 3 || mon == 5 || mon == 8 || mon == 10)) - return BAD_DATE; - - /* February gets special check for leapyear */ - - if ((mon == 1) && - ((ds.tm_mday > 29) - || ((ds.tm_mday == 29) - && ((ds.tm_year & 3) - || (((ds.tm_year % 100) == 0) - && (((ds.tm_year % 400) != 100))))))) - return BAD_DATE; - - ds.tm_mon = mon; - - /* ap_mplode_time uses tm_usec and tm_gmtoff fields, but they haven't - * been set yet. - * It should be safe to just zero out these values. - * tm_usec is the number of microseconds into the second. HTTP only - * cares about second granularity. - * tm_gmtoff is the number of seconds off of GMT the time is. By - * definition all times going through this function are in GMT, so this - * is zero. - */ - ds.tm_usec = 0; - ds.tm_gmtoff = 0; - if (apr_implode_time(&result, &ds) != APR_SUCCESS) - return BAD_DATE; - - return result; -} diff --git a/server/util_debug.c b/server/util_debug.c deleted file mode 100644 index f41f697d2d..0000000000 --- a/server/util_debug.c +++ /dev/null @@ -1,120 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_config.h" - -#ifdef AP_DEBUG - -/* get rid of the macros we defined in httpd.h */ -#undef strchr -#undef strrchr -#undef strstr - -char *ap_strchr(char *s, int c) -{ - return strchr(s,c); -} -const char *ap_strchr_c(const char *s, int c) -{ - return strchr(s,c); -} -char *ap_strrchr(char *s, int c) -{ - return strrchr(s,c); -} -const char *ap_strrchr_c(const char *s, int c) -{ - return strrchr(s,c); -} -char *ap_strstr(char *s, char *c) -{ - return strstr(s,c); -} -const char *ap_strstr_c(const char *s, const char *c) -{ - return strstr(s,c); -} - - -AP_DECLARE(void *) ap_get_module_config(const ap_conf_vector_t *cv, - const module *m) -{ - return ((void **)cv)[m->module_index]; -} - -/** - * Generic accessors for other modules to set at their own module-specific - * data - * @param conf_vector The vector in which the modules configuration is stored. - * usually r->per_dir_config or s->module_config - * @param m The module to set the data for. - * @param val The module-specific data to set - * @deffunc void ap_set_module_config(ap_conf_vector_t *cv, const module *m, void *val) - */ -AP_DECLARE(void) ap_set_module_config(ap_conf_vector_t *cv, const module *m, - void *val) -{ - ((void **)cv)[m->module_index] = val; -} - - -#endif /* AP_DEBUG */ diff --git a/server/util_ebcdic.c b/server/util_ebcdic.c deleted file mode 100644 index 75a1b7dd3d..0000000000 --- a/server/util_ebcdic.c +++ /dev/null @@ -1,168 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "ap_config.h" - -#if APR_CHARSET_EBCDIC - -#include "apr_strings.h" -#include "httpd.h" -#include "http_log.h" -#include "http_core.h" -#include "util_ebcdic.h" - -apr_status_t ap_init_ebcdic(apr_pool_t *pool) -{ - apr_status_t rv; - char buf[80]; - - rv = apr_xlate_open(&ap_hdrs_to_ascii, "ISO8859-1", APR_DEFAULT_CHARSET, pool); - if (rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "apr_xlate_open() failed"); - return rv; - } - - rv = apr_xlate_open(&ap_hdrs_from_ascii, APR_DEFAULT_CHARSET, "ISO8859-1", pool); - if (rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "apr_xlate_open() failed"); - return rv; - } - - rv = apr_xlate_open(&ap_locale_to_ascii, "ISO8859-1", APR_LOCALE_CHARSET, pool); - if (rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "apr_xlate_open() failed"); - return rv; - } - - rv = apr_xlate_open(&ap_locale_from_ascii, APR_LOCALE_CHARSET, "ISO8859-1", pool); - if (rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "apr_xlate_open() failed"); - return rv; - } - - rv = apr_MD5InitEBCDIC(ap_hdrs_to_ascii); - if (rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "apr_MD5InitEBCDIC() failed"); - return rv; - } - - rv = apr_base64init_ebcdic(ap_hdrs_to_ascii, ap_hdrs_from_ascii); - if (rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "apr_base64init_ebcdic() failed"); - return rv; - } - - rv = apr_SHA1InitEBCDIC(ap_hdrs_to_ascii); - if (rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "apr_SHA1InitEBCDIC() failed"); - return rv; - } - - return APR_SUCCESS; -} - -void ap_xlate_proto_to_ascii(char *buffer, apr_size_t len) -{ - apr_size_t inbytes_left, outbytes_left; - - inbytes_left = outbytes_left = len; - apr_xlate_conv_buffer(ap_hdrs_to_ascii, buffer, &inbytes_left, - buffer, &outbytes_left); -} - -void ap_xlate_proto_from_ascii(char *buffer, apr_size_t len) -{ - apr_size_t inbytes_left, outbytes_left; - - inbytes_left = outbytes_left = len; - apr_xlate_conv_buffer(ap_hdrs_from_ascii, buffer, &inbytes_left, - buffer, &outbytes_left); -} - -int ap_rvputs_proto_in_ascii(request_rec *r, ...) -{ - va_list va; - const char *s; - char *ascii_s; - apr_size_t len; - apr_size_t written = 0; - - va_start(va, r); - while (1) { - s = va_arg(va, const char *); - if (s == NULL) - break; - len = strlen(s); - ascii_s = apr_pstrndup(r->pool, s, len); - ap_xlate_proto_to_ascii(ascii_s, len); - if (ap_rputs(ascii_s, r) < 0) - return -1; - written += len; - } - va_end(va); - - return written; -} -#endif /* APR_CHARSET_EBCDIC */ diff --git a/server/util_filter.c b/server/util_filter.c deleted file mode 100644 index 2291919eb9..0000000000 --- a/server/util_filter.c +++ /dev/null @@ -1,305 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "httpd.h" -#include "http_log.h" -#include "util_filter.h" - -/* ### make this visible for direct manipulation? - * ### use a hash table - */ -static ap_filter_rec_t *registered_output_filters = NULL; -static ap_filter_rec_t *registered_input_filters = NULL; - -/* NOTE: Apache's current design doesn't allow a pool to be passed thu, - so we depend on a global to hold the correct pool -*/ -#define FILTER_POOL apr_global_hook_pool -#include "apr_hooks.h" /* for apr_global_hook_pool */ - -/* -** This macro returns true/false if a given filter should be inserted BEFORE -** another filter. This will happen when one of: 1) there isn't another -** filter; 2) that filter has a higher filter type (class); 3) that filter -** corresponds to a different request. -*/ -#define INSERT_BEFORE(f, before_this) ((before_this) == NULL \ - || (before_this)->frec->ftype > (f)->frec->ftype \ - || (before_this)->r != (f)->r) - - -static apr_status_t filter_cleanup(void *ctx) -{ - registered_output_filters = NULL; - registered_input_filters = NULL; - return APR_SUCCESS; -} - -static void register_filter(const char *name, - ap_filter_func filter_func, - ap_filter_type ftype, - ap_filter_rec_t **reg_filter_list) -{ - ap_filter_rec_t *frec = apr_palloc(FILTER_POOL, sizeof(*frec)); - - frec->name = name; - frec->filter_func = filter_func; - frec->ftype = ftype; - - frec->next = *reg_filter_list; - *reg_filter_list = frec; - - apr_pool_cleanup_register(FILTER_POOL, NULL, filter_cleanup, apr_pool_cleanup_null); -} - -AP_DECLARE(void) ap_register_input_filter(const char *name, - ap_in_filter_func filter_func, - ap_filter_type ftype) -{ - ap_filter_func f; - f.in_func = filter_func; - register_filter(name, f, ftype, ®istered_input_filters); -} - -AP_DECLARE(void) ap_register_output_filter(const char *name, - ap_out_filter_func filter_func, - ap_filter_type ftype) -{ - ap_filter_func f; - f.out_func = filter_func; - register_filter(name, f, ftype, ®istered_output_filters); -} - -static ap_filter_t *add_any_filter(const char *name, void *ctx, - request_rec *r, conn_rec *c, - ap_filter_rec_t *frec, - ap_filter_t **r_filters, - ap_filter_t **c_filters) -{ - for (; frec != NULL; frec = frec->next) { - if (!strcasecmp(name, frec->name)) { - apr_pool_t *p = r ? r->pool : c->pool; - ap_filter_t *f = apr_pcalloc(p, sizeof(*f)); - ap_filter_t **outf = r ? r_filters : c_filters; - - f->frec = frec; - f->ctx = ctx; - f->r = r; - f->c = c; - - if (INSERT_BEFORE(f, *outf)) { - f->next = *outf; - *outf = f; - } - else { - ap_filter_t *fscan = *outf; - while (!INSERT_BEFORE(f, fscan->next)) - fscan = fscan->next; - f->next = fscan->next; - fscan->next = f; - } - - return f; - } - } - - ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, NULL, - "an unknown filter was not added: %s", name); - return NULL; -} - -AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx, - request_rec *r, conn_rec *c) -{ - return add_any_filter(name, ctx, r, c, registered_input_filters, - r ? &r->input_filters : NULL, &c->input_filters); -} - -AP_DECLARE(ap_filter_t *) ap_add_output_filter(const char *name, void *ctx, - request_rec *r, conn_rec *c) -{ - return add_any_filter(name, ctx, r, c, registered_output_filters, - r ? &r->output_filters : NULL, &c->output_filters); -} - -AP_DECLARE(void) ap_remove_output_filter(ap_filter_t *f) -{ - ap_filter_t *curr; - - curr = f->r ? f->r->output_filters : f->c->output_filters; - - if (curr == f) { - if (f->r) { - f->r->output_filters = f->r->output_filters->next; - } - else { - f->c->output_filters = f->c->output_filters->next; - } - return; - } - - while (curr->next != f) { - curr = curr->next; - if (curr == NULL) { - return; - } - } - curr->next = f->next; -} - -/* - * Read data from the next filter in the filter stack. Data should be - * modified in the bucket brigade that is passed in. The core allocates the - * bucket brigade, modules that wish to replace large chunks of data or to - * save data off to the side should probably create their own temporary - * brigade especially for that use. - */ -AP_DECLARE(apr_status_t) ap_get_brigade(ap_filter_t *next, apr_bucket_brigade *bb, - ap_input_mode_t mode, apr_size_t *readbytes) -{ - if (next) { - return next->frec->filter_func.in_func(next, bb, mode, readbytes); - } - return AP_NOBODY_READ; -} - -/* Pass the buckets to the next filter in the filter stack. If the - * current filter is a handler, we should get NULL passed in instead of - * the current filter. At that point, we can just call the first filter in - * the stack, or r->output_filters. - */ -AP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *next, apr_bucket_brigade *bb) -{ - if (next) { - apr_bucket *e; - if ((e = APR_BRIGADE_LAST(bb)) && APR_BUCKET_IS_EOS(e) && next->r) { - /* This is only safe because HTTP_HEADER filter is always in - * the filter stack. This ensures that there is ALWAYS a - * request-based filter that we can attach this to. If the - * HTTP_FILTER is removed, and another filter is not put in its - * place, then handlers like mod_cgi, which attach their own - * EOS bucket to the brigade will be broken, because we will - * get two EOS buckets on the same request. - */ - next->r->eos_sent = 1; - } - return next->frec->filter_func.out_func(next, bb); - } - return AP_NOBODY_WROTE; -} - -AP_DECLARE(apr_status_t) ap_save_brigade(ap_filter_t *f, apr_bucket_brigade **saveto, - apr_bucket_brigade **b) -{ - apr_bucket *e; - apr_pool_t *p = f->r ? f->r->pool : f->c->pool; - apr_status_t rv; - - /* If have never stored any data in the filter, then we had better - * create an empty bucket brigade so that we can concat. - */ - if (!(*saveto)) { - *saveto = apr_brigade_create(p); - } - - APR_RING_FOREACH(e, &(*b)->list, apr_bucket, link) { - rv = apr_bucket_setaside(e); - if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { - return rv; - } - } - APR_BRIGADE_CONCAT(*saveto, *b); - return APR_SUCCESS; -} - -AP_DECLARE_NONSTD(apr_status_t) ap_filter_flush(apr_bucket_brigade *bb, void *ctx) -{ - ap_filter_t *f = ctx; - - return ap_pass_brigade(f, bb); -} - -AP_DECLARE(apr_status_t) ap_fflush(ap_filter_t *f, apr_bucket_brigade *bb) -{ - apr_bucket *b; - - b = apr_bucket_flush_create(); - APR_BRIGADE_INSERT_TAIL(bb, b); - return ap_pass_brigade(f, bb); -} - -AP_DECLARE_NONSTD(int) ap_fputstrs(ap_filter_t *f, apr_bucket_brigade *bb, ...) -{ - va_list args; - int res; - - va_start(args, bb); - res = apr_brigade_vputstrs(bb, ap_filter_flush, f, args); - va_end(args); - return res; -} - -AP_DECLARE_NONSTD(int) ap_fprintf(ap_filter_t *f, apr_bucket_brigade *bb, const char *fmt, ...){ - va_list args; - int res; - - va_start(args, fmt); - res = apr_brigade_vprintf(bb, ap_filter_flush, f, fmt, args); - va_end(args); - return res; -} - diff --git a/server/util_md5.c b/server/util_md5.c deleted file mode 100644 index 9f19d62add..0000000000 --- a/server/util_md5.c +++ /dev/null @@ -1,215 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/************************************************************************ - * NCSA HTTPd Server - * Software Development Group - * National Center for Supercomputing Applications - * University of Illinois at Urbana-Champaign - * 605 E. Springfield, Champaign, IL 61820 - * httpd@ncsa.uiuc.edu - * - * Copyright (C) 1995, Board of Trustees of the University of Illinois - * - ************************************************************************ - * - * md5.c: NCSA HTTPd code which uses the md5c.c RSA Code - * - * Original Code Copyright (C) 1994, Jeff Hostetler, Spyglass, Inc. - * Portions of Content-MD5 code Copyright (C) 1993, 1994 by Carnegie Mellon - * University (see Copyright below). - * Portions of Content-MD5 code Copyright (C) 1991 Bell Communications - * Research, Inc. (Bellcore) (see Copyright below). - * Portions extracted from mpack, John G. Myers - jgm+@cmu.edu - * Content-MD5 Code contributed by Martin Hamilton (martin@net.lut.ac.uk) - * - */ - - - -/* md5.c --Module Interface to MD5. */ -/* Jeff Hostetler, Spyglass, Inc., 1994. */ - -#include "ap_config.h" -#include "apr_portable.h" -#include "apr_strings.h" -#include "httpd.h" -#include "util_md5.h" -#include "util_ebcdic.h" - -AP_DECLARE(char *) ap_md5_binary(apr_pool_t *p, const unsigned char *buf, int length) -{ - const char *hex = "0123456789abcdef"; - apr_md5_ctx_t my_md5; - unsigned char hash[MD5_DIGESTSIZE]; - char *r, result[33]; - int i; - - /* - * Take the MD5 hash of the string argument. - */ - - apr_md5_init(&my_md5); -#if APR_CHARSET_EBCDIC - apr_md5_set_xlate(&my_md5, ap_hdrs_to_ascii); -#endif - apr_md5_update(&my_md5, buf, (unsigned int)length); - apr_md5_final(hash, &my_md5); - - for (i = 0, r = result; i < MD5_DIGESTSIZE; i++) { - *r++ = hex[hash[i] >> 4]; - *r++ = hex[hash[i] & 0xF]; - } - *r = '\0'; - - return apr_pstrdup(p, result); -} - -AP_DECLARE(char *) ap_md5(apr_pool_t *p, const unsigned char *string) -{ - return ap_md5_binary(p, string, (int) strlen((char *)string)); -} - -/* these portions extracted from mpack, John G. Myers - jgm+@cmu.edu */ - -/* (C) Copyright 1993,1994 by Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify, distribute, and sell this software - * and its documentation for any purpose is hereby granted without - * fee, provided that the above copyright notice appear in all copies - * and that both that copyright notice and this permission notice - * appear in supporting documentation, and that the name of Carnegie - * Mellon University not be used in advertising or publicity - * pertaining to distribution of the software without specific, - * written prior permission. Carnegie Mellon University makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE - * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* - * Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore) - * - * Permission to use, copy, modify, and distribute this material - * for any purpose and without fee is hereby granted, provided - * that the above copyright notice and this permission notice - * appear in all copies, and that the name of Bellcore not be - * used in advertising or publicity pertaining to this - * material without the specific, prior written permission - * of an authorized representative of Bellcore. BELLCORE - * MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY - * OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS", - * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. - */ - -static char basis_64[] = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -AP_DECLARE(char *) ap_md5contextTo64(apr_pool_t *a, apr_md5_ctx_t *context) -{ - unsigned char digest[18]; - char *encodedDigest; - int i; - char *p; - - encodedDigest = (char *) apr_pcalloc(a, 25 * sizeof(char)); - - apr_md5_final(digest, context); - digest[sizeof(digest) - 1] = digest[sizeof(digest) - 2] = 0; - - p = encodedDigest; - for (i = 0; i < sizeof(digest); i += 3) { - *p++ = basis_64[digest[i] >> 2]; - *p++ = basis_64[((digest[i] & 0x3) << 4) | ((int) (digest[i + 1] & 0xF0) >> 4)]; - *p++ = basis_64[((digest[i + 1] & 0xF) << 2) | ((int) (digest[i + 2] & 0xC0) >> 6)]; - *p++ = basis_64[digest[i + 2] & 0x3F]; - } - *p-- = '\0'; - *p-- = '='; - *p-- = '='; - return encodedDigest; -} - -AP_DECLARE(char *) ap_md5digest(apr_pool_t *p, apr_file_t *infile) -{ - apr_md5_ctx_t context; - unsigned char buf[1000]; - long length = 0; - apr_size_t nbytes; - apr_off_t offset = 0L; - - apr_md5_init(&context); - nbytes = sizeof(buf); - while (apr_file_read(infile, buf, &nbytes) == APR_SUCCESS) { - length += nbytes; - apr_md5_update(&context, buf, nbytes); - } - apr_file_seek(infile, APR_SET, &offset); - return ap_md5contextTo64(p, &context); -} - diff --git a/server/util_script.c b/server/util_script.c deleted file mode 100644 index 875bec9c7a..0000000000 --- a/server/util_script.c +++ /dev/null @@ -1,652 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -#include "apr.h" -#include "apr_lib.h" -#include "apr_strings.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#if APR_HAVE_STDLIB_H -#include <stdlib.h> -#endif - -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_main.h" -#include "http_log.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_request.h" /* for sub_req_lookup_uri() */ -#include "util_script.h" -#include "util_date.h" /* For parseHTTPdate() */ -#include "util_ebcdic.h" - -#ifdef OS2 -#define INCL_DOS -#include <os2.h> -#endif - -/* - * Various utility functions which are common to a whole lot of - * script-type extensions mechanisms, and might as well be gathered - * in one place (if only to avoid creating inter-module dependancies - * where there don't have to be). - */ - -#define MALFORMED_MESSAGE "malformed header from script. Bad header=" -#define MALFORMED_HEADER_LENGTH_TO_SHOW 30 - -static char *http2env(apr_pool_t *a, char *w) -{ - char *res = apr_pstrcat(a, "HTTP_", w, NULL); - char *cp = res; - - while (*++cp) { - if (!apr_isalnum(*cp) && *cp != '_') { - *cp = '_'; - } - else { - *cp = apr_toupper(*cp); - } - } - - return res; -} - -AP_DECLARE(char **) ap_create_environment(apr_pool_t *p, apr_table_t *t) -{ - apr_array_header_t *env_arr = apr_table_elts(t); - apr_table_entry_t *elts = (apr_table_entry_t *) env_arr->elts; - char **env = (char **) apr_palloc(p, (env_arr->nelts + 2) * sizeof(char *)); - int i, j; - char *tz; - char *whack; - - j = 0; - if (!apr_table_get(t, "TZ")) { - tz = getenv("TZ"); - if (tz != NULL) { - env[j++] = apr_pstrcat(p, "TZ=", tz, NULL); - } - } - for (i = 0; i < env_arr->nelts; ++i) { - if (!elts[i].key) { - continue; - } - env[j] = apr_pstrcat(p, elts[i].key, "=", elts[i].val, NULL); - whack = env[j]; - if (apr_isdigit(*whack)) { - *whack++ = '_'; - } - while (*whack != '=') { - if (!apr_isalnum(*whack) && *whack != '_') { - *whack = '_'; - } - ++whack; - } - ++j; - } - - env[j] = NULL; - return env; -} - -AP_DECLARE(void) ap_add_common_vars(request_rec *r) -{ - apr_table_t *e; - server_rec *s = r->server; - conn_rec *c = r->connection; - const char *rem_logname; - char *env_path; -#if defined(WIN32) || defined(OS2) - char *env_temp; -#endif - const char *host; - apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in); - apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts; - int i; - apr_port_t rport; - apr_sockaddr_t *remotesa; - - /* use a temporary apr_table_t which we'll overlap onto - * r->subprocess_env later - */ - e = apr_table_make(r->pool, 25 + hdrs_arr->nelts); - - /* First, add environment vars from headers... this is as per - * CGI specs, though other sorts of scripting interfaces see - * the same vars... - */ - - for (i = 0; i < hdrs_arr->nelts; ++i) { - if (!hdrs[i].key) { - continue; - } - - /* A few headers are special cased --- Authorization to prevent - * rogue scripts from capturing passwords; content-type and -length - * for no particular reason. - */ - - if (!strcasecmp(hdrs[i].key, "Content-type")) { - apr_table_addn(e, "CONTENT_TYPE", hdrs[i].val); - } - else if (!strcasecmp(hdrs[i].key, "Content-length")) { - apr_table_addn(e, "CONTENT_LENGTH", hdrs[i].val); - } - /* - * You really don't want to disable this check, since it leaves you - * wide open to CGIs stealing passwords and people viewing them - * in the environment with "ps -e". But, if you must... - */ -#ifndef SECURITY_HOLE_PASS_AUTHORIZATION - else if (!strcasecmp(hdrs[i].key, "Authorization") - || !strcasecmp(hdrs[i].key, "Proxy-Authorization")) { - continue; - } -#endif - else { - apr_table_addn(e, http2env(r->pool, hdrs[i].key), hdrs[i].val); - } - } - - if (!(env_path = getenv("PATH"))) { - env_path = DEFAULT_PATH; - } - apr_table_addn(e, "PATH", apr_pstrdup(r->pool, env_path)); - -#ifdef WIN32 - if (env_temp = getenv("SystemRoot")) { - apr_table_addn(e, "SystemRoot", env_temp); - } - if (env_temp = getenv("COMSPEC")) { - apr_table_addn(e, "COMSPEC", env_temp); - } - if (env_temp = getenv("WINDIR")) { - apr_table_addn(e, "WINDIR", env_temp); - } -#endif - -#ifdef OS2 - if ((env_temp = getenv("COMSPEC")) != NULL) { - apr_table_addn(e, "COMSPEC", env_temp); - } - if ((env_temp = getenv("ETC")) != NULL) { - apr_table_addn(e, "ETC", env_temp); - } - if ((env_temp = getenv("DPATH")) != NULL) { - apr_table_addn(e, "DPATH", env_temp); - } - if ((env_temp = getenv("PERLLIB_PREFIX")) != NULL) { - apr_table_addn(e, "PERLLIB_PREFIX", env_temp); - } -#endif - - apr_table_addn(e, "SERVER_SIGNATURE", ap_psignature("", r)); - apr_table_addn(e, "SERVER_SOFTWARE", ap_get_server_version()); - apr_table_addn(e, "SERVER_NAME", ap_get_server_name(r)); - apr_table_addn(e, "SERVER_ADDR", r->connection->local_ip); /* Apache */ - apr_table_addn(e, "SERVER_PORT", - apr_psprintf(r->pool, "%u", ap_get_server_port(r))); - host = ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST, NULL); - if (host) { - apr_table_addn(e, "REMOTE_HOST", host); - } - apr_table_addn(e, "REMOTE_ADDR", c->remote_ip); - apr_table_addn(e, "DOCUMENT_ROOT", ap_document_root(r)); /* Apache */ - apr_table_addn(e, "SERVER_ADMIN", s->server_admin); /* Apache */ - apr_table_addn(e, "SCRIPT_FILENAME", r->filename); /* Apache */ - - apr_socket_addr_get(&remotesa, APR_REMOTE, c->client_socket); - apr_sockaddr_port_get(&rport, remotesa); - apr_table_addn(e, "REMOTE_PORT", apr_psprintf(r->pool, "%d", rport)); - - if (r->user) { - apr_table_addn(e, "REMOTE_USER", r->user); - } - if (r->ap_auth_type) { - apr_table_addn(e, "AUTH_TYPE", r->ap_auth_type); - } - rem_logname = ap_get_remote_logname(r); - if (rem_logname) { - apr_table_addn(e, "REMOTE_IDENT", apr_pstrdup(r->pool, rem_logname)); - } - - /* Apache custom error responses. If we have redirected set two new vars */ - - if (r->prev) { - if (r->prev->args) { - apr_table_addn(e, "REDIRECT_QUERY_STRING", r->prev->args); - } - if (r->prev->uri) { - apr_table_addn(e, "REDIRECT_URL", r->prev->uri); - } - } - - apr_table_overlap(r->subprocess_env, e, APR_OVERLAP_TABLES_SET); -} - -/* This "cute" little function comes about because the path info on - * filenames and URLs aren't always the same. So we take the two, - * and find as much of the two that match as possible. - */ - -AP_DECLARE(int) ap_find_path_info(const char *uri, const char *path_info) -{ - int lu = strlen(uri); - int lp = strlen(path_info); - - while (lu-- && lp-- && uri[lu] == path_info[lp]); - - if (lu == -1) { - lu = 0; - } - - while (uri[lu] != '\0' && uri[lu] != '/') { - lu++; - } - return lu; -} - -AP_DECLARE(void) ap_add_cgi_vars(request_rec *r) -{ - apr_table_t *e = r->subprocess_env; - - apr_table_setn(e, "GATEWAY_INTERFACE", "CGI/1.1"); - apr_table_setn(e, "SERVER_PROTOCOL", r->protocol); - apr_table_setn(e, "REQUEST_METHOD", r->method); - apr_table_setn(e, "QUERY_STRING", r->args ? r->args : ""); - apr_table_setn(e, "REQUEST_URI", r->unparsed_uri); - - /* Note that the code below special-cases scripts run from includes, - * because it "knows" that the sub_request has been hacked to have the - * args and path_info of the original request, and not any that may have - * come with the script URI in the include command. Ugh. - */ - - if (!strcmp(r->protocol, "INCLUDED")) { - apr_table_setn(e, "SCRIPT_NAME", r->uri); - if (r->path_info && *r->path_info) { - apr_table_setn(e, "PATH_INFO", r->path_info); - } - } - else if (!r->path_info || !*r->path_info) { - apr_table_setn(e, "SCRIPT_NAME", r->uri); - } - else { - int path_info_start = ap_find_path_info(r->uri, r->path_info); - - apr_table_setn(e, "SCRIPT_NAME", - apr_pstrndup(r->pool, r->uri, path_info_start)); - - apr_table_setn(e, "PATH_INFO", r->path_info); - } - - if (r->path_info && r->path_info[0]) { - /* - * To get PATH_TRANSLATED, treat PATH_INFO as a URI path. - * Need to re-escape it for this, since the entire URI was - * un-escaped before we determined where the PATH_INFO began. - */ - request_rec *pa_req; - - pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r, - NULL); - - if (pa_req->filename) { -#ifdef WIN32 - char buffer[HUGE_STRING_LEN]; -#endif - char *pt = apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info, - NULL); -#ifdef WIN32 - /* We need to make this a real Windows path name */ - GetFullPathName(pt, HUGE_STRING_LEN, buffer, NULL); - apr_table_setn(e, "PATH_TRANSLATED", apr_pstrdup(r->pool, buffer)); -#else - apr_table_setn(e, "PATH_TRANSLATED", pt); -#endif - } - ap_destroy_sub_req(pa_req); - } -} - - -static int set_cookie_doo_doo(void *v, const char *key, const char *val) -{ - apr_table_addn(v, key, val); - return 1; -} - -AP_DECLARE(int) ap_scan_script_header_err_core(request_rec *r, char *buffer, - int (*getsfunc) (char *, int, void *), - void *getsfunc_data) -{ - char x[MAX_STRING_LEN]; - char *w, *l; - int p; - int cgi_status = HTTP_OK; - apr_table_t *merge; - apr_table_t *cookie_table; - - if (buffer) { - *buffer = '\0'; - } - w = buffer ? buffer : x; - - /* temporary place to hold headers to merge in later */ - merge = apr_table_make(r->pool, 10); - - /* The HTTP specification says that it is legal to merge duplicate - * headers into one. Some browsers that support Cookies don't like - * merged headers and prefer that each Set-Cookie header is sent - * separately. Lets humour those browsers by not merging. - * Oh what a pain it is. - */ - cookie_table = apr_table_make(r->pool, 2); - apr_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out, "Set-Cookie", NULL); - - while (1) { - - if ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data) == 0) { - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Premature end of script headers: %s", r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Delete terminal (CR?)LF */ - - p = strlen(w); - /* Indeed, the host's '\n': - '\012' for UNIX; '\015' for MacOS; '\025' for OS/390 - -- whatever the script generates. - */ - if (p > 0 && w[p - 1] == '\n') { - if (p > 1 && w[p - 2] == CR) { - w[p - 2] = '\0'; - } - else { - w[p - 1] = '\0'; - } - } - - /* - * If we've finished reading the headers, check to make sure any - * HTTP/1.1 conditions are met. If so, we're done; normal processing - * will handle the script's output. If not, just return the error. - * The appropriate thing to do would be to send the script process a - * SIGPIPE to let it know we're ignoring it, close the channel to the - * script process, and *then* return the failed-to-meet-condition - * error. Otherwise we'd be waiting for the script to finish - * blithering before telling the client the output was no good. - * However, we don't have the information to do that, so we have to - * leave it to an upper layer. - */ - if (w[0] == '\0') { - int cond_status = OK; - - if ((cgi_status == HTTP_OK) && (r->method_number == M_GET)) { - cond_status = ap_meets_conditions(r); - } - apr_table_overlap(r->err_headers_out, merge, - APR_OVERLAP_TABLES_MERGE); - if (!apr_is_empty_table(cookie_table)) { - /* the cookies have already been copied to the cookie_table */ - apr_table_unset(r->err_headers_out, "Set-Cookie"); - r->err_headers_out = apr_table_overlay(r->pool, - r->err_headers_out, cookie_table); - } - return cond_status; - } - - /* if we see a bogus header don't ignore it. Shout and scream */ - -#if APR_CHARSET_EBCDIC - /* Chances are that we received an ASCII header text instead of - * the expected EBCDIC header lines. Try to auto-detect: - */ - if (!(l = strchr(w, ':'))) { - int maybeASCII = 0, maybeEBCDIC = 0; - unsigned char *cp, native; - apr_size_t inbytes_left, outbytes_left; - - for (cp = w; *cp != '\0'; ++cp) { - native = apr_xlate_conv_byte(ap_hdrs_from_ascii, *cp); - if (isprint(*cp) && !isprint(native)) - ++maybeEBCDIC; - if (!isprint(*cp) && isprint(native)) - ++maybeASCII; - } - if (maybeASCII > maybeEBCDIC) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->server, - "CGI Interface Error: Script headers apparently ASCII: (CGI = %s)", - r->filename); - inbytes_left = outbytes_left = cp - w; - apr_xlate_conv_buffer(ap_hdrs_from_ascii, - w, &inbytes_left, w, &outbytes_left); - } - } -#endif /*APR_CHARSET_EBCDIC*/ - if (!(l = strchr(w, ':'))) { - char malformed[(sizeof MALFORMED_MESSAGE) + 1 - + MALFORMED_HEADER_LENGTH_TO_SHOW]; - - strcpy(malformed, MALFORMED_MESSAGE); - strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW); - - if (!buffer) { - /* Soak up all the script output - may save an outright kill */ - while ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data)) { - continue; - } - } - - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "%s: %s", malformed, r->filename); - return HTTP_INTERNAL_SERVER_ERROR; - } - - *l++ = '\0'; - while (*l && apr_isspace(*l)) { - ++l; - } - - if (!strcasecmp(w, "Content-type")) { - char *tmp; - - /* Nuke trailing whitespace */ - - char *endp = l + strlen(l) - 1; - while (endp > l && apr_isspace(*endp)) { - *endp-- = '\0'; - } - - tmp = apr_pstrdup(r->pool, l); - ap_content_type_tolower(tmp); - r->content_type = tmp; - } - /* - * If the script returned a specific status, that's what - * we'll use - otherwise we assume 200 OK. - */ - else if (!strcasecmp(w, "Status")) { - r->status = cgi_status = atoi(l); - r->status_line = apr_pstrdup(r->pool, l); - } - else if (!strcasecmp(w, "Location")) { - apr_table_set(r->headers_out, w, l); - } - else if (!strcasecmp(w, "Content-Length")) { - apr_table_set(r->headers_out, w, l); - } - else if (!strcasecmp(w, "Transfer-Encoding")) { - apr_table_set(r->headers_out, w, l); - } - /* - * If the script gave us a Last-Modified header, we can't just - * pass it on blindly because of restrictions on future values. - */ - else if (!strcasecmp(w, "Last-Modified")) { - ap_update_mtime(r, ap_parseHTTPdate(l)); - ap_set_last_modified(r); - } - else if (!strcasecmp(w, "Set-Cookie")) { - apr_table_add(cookie_table, w, l); - } - else { - apr_table_add(merge, w, l); - } - } -} - -static int getsfunc_FILE(char *buf, int len, void *f) -{ - return apr_file_gets(buf, len, (apr_file_t *) f) == APR_SUCCESS; -} - -AP_DECLARE(int) ap_scan_script_header_err(request_rec *r, apr_file_t *f, - char *buffer) -{ - return ap_scan_script_header_err_core(r, buffer, getsfunc_FILE, f); -} - -struct vastrs { - va_list args; - int arg; - const char *curpos; -}; - -static int getsfunc_STRING(char *w, int len, void *pvastrs) -{ - struct vastrs *strs = (struct vastrs*) pvastrs; - const char *p; - int t; - - if (!strs->curpos || !*strs->curpos) - return 0; - p = ap_strchr_c(strs->curpos, '\n'); - if (p) - ++p; - else - p = ap_strchr_c(strs->curpos, '\0'); - t = p - strs->curpos; - if (t > len) - t = len; - strncpy (w, strs->curpos, t); - w[t] = '\0'; - if (!strs->curpos[t]) { - ++strs->arg; - strs->curpos = va_arg(strs->args, const char *); - } - else - strs->curpos += t; - return t; -} - -/* ap_scan_script_header_err_strs() accepts additional const char* args... - * each is treated as one or more header lines, and the first non-header - * character is returned to **arg, **data. (The first optional arg is - * counted as 0.) - */ -AP_DECLARE_NONSTD(int) ap_scan_script_header_err_strs(request_rec *r, - char *buffer, - const char **termch, - int *termarg, ...) -{ - struct vastrs strs; - int res; - - va_start(strs.args, termarg); - strs.arg = 0; - strs.curpos = va_arg(strs.args, char*); - res = ap_scan_script_header_err_core(r, buffer, getsfunc_STRING, (void *) &strs); - if (termch) - *termch = strs.curpos; - if (termarg) - *termarg = strs.arg; - va_end(strs.args); - return res; -} - -AP_DECLARE(void) ap_send_size(apr_ssize_t size, request_rec *r) -{ - /* XXX: this -1 thing is a gross hack */ - if (size == (apr_ssize_t)-1) { - ap_rputs(" -", r); - } - else if (!size) { - ap_rputs(" 0k", r); - } - else if (size < 1024) { - ap_rputs(" 1k", r); - } - else if (size < 1048576) { - ap_rprintf(r, "%4" APR_SSIZE_T_FMT "k", (size + 512) / 1024); - } - else if (size < 103809024) { - ap_rprintf(r, "%4.1fM", size / 1048576.0); - } - else { - ap_rprintf(r, "%4" APR_SSIZE_T_FMT "M", (size + 524288) / 1048576); - } -} - diff --git a/server/util_uri.c b/server/util_uri.c deleted file mode 100644 index 508c6f199c..0000000000 --- a/server/util_uri.c +++ /dev/null @@ -1,359 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * util_uri.c: URI related utility things - * - */ - -#include "apr.h" -#include "apr_strings.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#include "ap_config.h" -#include "httpd.h" -#include "http_log.h" -#include "util_uri.h" - -/* Some WWW schemes and their default ports; this is basically /etc/services */ -/* This will become global when the protocol abstraction comes */ -/* As the schemes are searched by a linear search, */ -/* they are sorted by their expected frequency */ -static schemes_t schemes[] = -{ - {"http", DEFAULT_HTTP_PORT}, - {"ftp", DEFAULT_FTP_PORT}, - {"https", DEFAULT_HTTPS_PORT}, - {"gopher", DEFAULT_GOPHER_PORT}, - {"wais", DEFAULT_WAIS_PORT}, - {"nntp", DEFAULT_NNTP_PORT}, - {"snews", DEFAULT_SNEWS_PORT}, - {"prospero", DEFAULT_PROSPERO_PORT}, - { NULL, 0xFFFF } /* unknown port */ -}; - - -AP_DECLARE(apr_port_t) ap_default_port_for_scheme(const char *scheme_str) -{ - schemes_t *scheme; - - for (scheme = schemes; scheme->name != NULL; ++scheme) - if (strcasecmp(scheme_str, scheme->name) == 0) - return scheme->default_port; - - return 0; -} - -AP_DECLARE(apr_port_t) ap_default_port_for_request(const request_rec *r) -{ - return (r->parsed_uri.scheme) - ? ap_default_port_for_scheme(r->parsed_uri.scheme) - : 0; -} - -/* Unparse a uri_components structure to an URI string. - * Optionally suppress the password for security reasons. - */ -AP_DECLARE(char *) ap_unparse_uri_components(apr_pool_t *p, const uri_components *uptr, unsigned flags) -{ - char *ret = ""; - - /* If suppressing the site part, omit both user name & scheme://hostname */ - if (!(flags & UNP_OMITSITEPART)) { - - /* Construct a "user:password@" string, honoring the passed UNP_ flags: */ - if (uptr->user||uptr->password) - ret = apr_pstrcat (p, - (uptr->user && !(flags & UNP_OMITUSER)) ? uptr->user : "", - (uptr->password && !(flags & UNP_OMITPASSWORD)) ? ":" : "", - (uptr->password && !(flags & UNP_OMITPASSWORD)) - ? ((flags & UNP_REVEALPASSWORD) ? uptr->password : "XXXXXXXX") - : "", - "@", NULL); - - /* Construct scheme://site string */ - if (uptr->hostname) { - int is_default_port; - - is_default_port = - (uptr->port_str == NULL || - uptr->port == 0 || - uptr->port == ap_default_port_for_scheme(uptr->scheme)); - - ret = apr_pstrcat (p, - uptr->scheme, "://", ret, - uptr->hostname ? uptr->hostname : "", - is_default_port ? "" : ":", - is_default_port ? "" : uptr->port_str, - NULL); - } - } - - /* Should we suppress all path info? */ - if (!(flags & UNP_OMITPATHINFO)) { - /* Append path, query and fragment strings: */ - ret = apr_pstrcat (p, - ret, - uptr->path ? uptr->path : "", - (uptr->query && !(flags & UNP_OMITQUERY)) ? "?" : "", - (uptr->query && !(flags & UNP_OMITQUERY)) ? uptr->query : "", - (uptr->fragment && !(flags & UNP_OMITQUERY)) ? "#" : NULL, - (uptr->fragment && !(flags & UNP_OMITQUERY)) ? uptr->fragment : NULL, - NULL); - } - return ret; -} - -/* Here is the hand-optimized parse_uri_components(). There are some wild - * tricks we could pull in assembly language that we don't pull here... like we - * can do word-at-time scans for delimiter characters using the same technique - * that fast memchr()s use. But that would be way non-portable. -djg - */ - -/* We have a apr_table_t that we can index by character and it tells us if the - * character is one of the interesting delimiters. Note that we even get - * compares for NUL for free -- it's just another delimiter. - */ - -#define T_COLON 0x01 /* ':' */ -#define T_SLASH 0x02 /* '/' */ -#define T_QUESTION 0x04 /* '?' */ -#define T_HASH 0x08 /* '#' */ -#define T_NUL 0x80 /* '\0' */ - -/* the uri_delims.h file is autogenerated by gen_uri_delims.c */ -#include "uri_delims.h" - -/* it works like this: - if (uri_delims[ch] & NOTEND_foobar) { - then we're not at a delimiter for foobar - } -*/ - -/* Note that we optimize the scheme scanning here, we cheat and let the - * compiler know that it doesn't have to do the & masking. - */ -#define NOTEND_SCHEME (0xff) -#define NOTEND_HOSTINFO (T_SLASH | T_QUESTION | T_HASH | T_NUL) -#define NOTEND_PATH (T_QUESTION | T_HASH | T_NUL) - -/* parse_uri_components(): - * Parse a given URI, fill in all supplied fields of a uri_components - * structure. This eliminates the necessity of extracting host, port, - * path, query info repeatedly in the modules. - * Side effects: - * - fills in fields of uri_components *uptr - * - none on any of the r->* fields - */ -AP_DECLARE(int) ap_parse_uri_components(apr_pool_t *p, const char *uri, uri_components *uptr) -{ - const char *s; - const char *s1; - const char *hostinfo; - char *endstr; - int port; - - /* Initialize the structure. parse_uri() and parse_uri_components() - * can be called more than once per request. - */ - memset (uptr, '\0', sizeof(*uptr)); - uptr->is_initialized = 1; - - /* We assume the processor has a branch predictor like most -- - * it assumes forward branches are untaken and backwards are taken. That's - * the reason for the gotos. -djg - */ - if (uri[0] == '/') { -deal_with_path: - /* we expect uri to point to first character of path ... remember - * that the path could be empty -- http://foobar?query for example - */ - s = uri; - while ((uri_delims[*(unsigned char *)s] & NOTEND_PATH) == 0) { - ++s; - } - if (s != uri) { - uptr->path = apr_pstrndup(p, uri, s - uri); - } - if (*s == 0) { - return HTTP_OK; - } - if (*s == '?') { - ++s; - s1 = ap_strchr_c(s, '#'); - if (s1) { - uptr->fragment = apr_pstrdup(p, s1 + 1); - uptr->query = apr_pstrndup(p, s, s1 - s); - } - else { - uptr->query = apr_pstrdup(p, s); - } - return HTTP_OK; - } - /* otherwise it's a fragment */ - uptr->fragment = apr_pstrdup(p, s + 1); - return HTTP_OK; - } - - /* find the scheme: */ - s = uri; - while ((uri_delims[*(unsigned char *)s] & NOTEND_SCHEME) == 0) { - ++s; - } - /* scheme must be non-empty and followed by :// */ - if (s == uri || s[0] != ':' || s[1] != '/' || s[2] != '/') { - goto deal_with_path; /* backwards predicted taken! */ - } - - uptr->scheme = apr_pstrndup(p, uri, s - uri); - s += 3; - hostinfo = s; - while ((uri_delims[*(unsigned char *)s] & NOTEND_HOSTINFO) == 0) { - ++s; - } - uri = s; /* whatever follows hostinfo is start of uri */ - uptr->hostinfo = apr_pstrndup(p, hostinfo, uri - hostinfo); - - /* If there's a username:password@host:port, the @ we want is the last @... - * too bad there's no memrchr()... For the C purists, note that hostinfo - * is definately not the first character of the original uri so therefore - * &hostinfo[-1] < &hostinfo[0] ... and this loop is valid C. - */ - do { - --s; - } while (s >= hostinfo && *s != '@'); - if (s < hostinfo) { - /* again we want the common case to be fall through */ -deal_with_host: - /* We expect hostinfo to point to the first character of - * the hostname. If there's a port it is the first colon. - */ - s = memchr(hostinfo, ':', uri - hostinfo); - if (s == NULL) { - /* we expect the common case to have no port */ - uptr->hostname = apr_pstrndup(p, hostinfo, uri - hostinfo); - goto deal_with_path; - } - uptr->hostname = apr_pstrndup(p, hostinfo, s - hostinfo); - ++s; - uptr->port_str = apr_pstrndup(p, s, uri - s); - if (uri != s) { - port = strtol(uptr->port_str, &endstr, 10); - uptr->port = port; - if (*endstr == '\0') { - goto deal_with_path; - } - /* Invalid characters after ':' found */ - return HTTP_BAD_REQUEST; - } - uptr->port = ap_default_port_for_scheme(uptr->scheme); - goto deal_with_path; - } - - /* first colon delimits username:password */ - s1 = memchr(hostinfo, ':', s - hostinfo); - if (s1) { - uptr->user = apr_pstrndup(p, hostinfo, s1 - hostinfo); - ++s1; - uptr->password = apr_pstrndup(p, s1, s - s1); - } - else { - uptr->user = apr_pstrndup(p, hostinfo, s - hostinfo); - } - hostinfo = s + 1; - goto deal_with_host; -} - -/* Special case for CONNECT parsing: it comes with the hostinfo part only */ -/* See the INTERNET-DRAFT document "Tunneling SSL Through a WWW Proxy" - * currently at http://www.mcom.com/newsref/std/tunneling_ssl.html - * for the format of the "CONNECT host:port HTTP/1.0" request - */ -AP_DECLARE(int) ap_parse_hostinfo_components(apr_pool_t *p, const char *hostinfo, uri_components *uptr) -{ - const char *s; - char *endstr; - - /* Initialize the structure. parse_uri() and parse_uri_components() - * can be called more than once per request. - */ - memset (uptr, '\0', sizeof(*uptr)); - uptr->is_initialized = 1; - uptr->hostinfo = apr_pstrdup(p, hostinfo); - - /* We expect hostinfo to point to the first character of - * the hostname. There must be a port, separated by a colon - */ - s = ap_strchr_c(hostinfo, ':'); - if (s == NULL) { - return HTTP_BAD_REQUEST; - } - uptr->hostname = apr_pstrndup(p, hostinfo, s - hostinfo); - ++s; - uptr->port_str = apr_pstrdup(p, s); - if (*s != '\0') { - uptr->port = (unsigned short) strtol(uptr->port_str, &endstr, 10); - if (*endstr == '\0') { - return HTTP_OK; - } - /* Invalid characters after ':' found */ - } - return HTTP_BAD_REQUEST; -} diff --git a/server/util_xml.c b/server/util_xml.c deleted file mode 100644 index 9c617b298c..0000000000 --- a/server/util_xml.c +++ /dev/null @@ -1,134 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - */ - -#include "apr_xml.h" - -#include "httpd.h" -#include "http_protocol.h" -#include "http_log.h" -#include "http_core.h" - -#include "util_xml.h" - - -#define READ_BLOCKSIZE 2048 /* used for reading input blocks */ - - -AP_DECLARE(int) ap_xml_parse_input(request_rec * r, apr_xml_doc **pdoc) -{ - apr_xml_parser *parser; - int result; - apr_status_t status; - char errbuf[200]; - - if ((result = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK) - return result; - - if (r->remaining == 0) { - *pdoc = NULL; - return OK; - } - - parser = apr_xml_parser_create(r->pool); - - if (ap_should_client_block(r)) { - long len; - char *buffer; - apr_size_t total_read = 0; - apr_size_t limit_xml_body = ap_get_limit_xml_body(r); - - /* allocate our working buffer */ - buffer = apr_palloc(r->pool, READ_BLOCKSIZE); - - /* read the body, stuffing it into the parser */ - while ((len = ap_get_client_block(r, buffer, READ_BLOCKSIZE)) > 0) { - total_read += len; - if (limit_xml_body && total_read > limit_xml_body) { - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "XML request body is larger than the configured " - "limit of %lu", (unsigned long)limit_xml_body); - goto read_error; - } - - status = apr_xml_parser_feed(parser, buffer, len); - if (status) - goto parser_error; - } - if (len == -1) { - /* ap_get_client_block() has logged an error */ - goto read_error; - } - } - - /* tell the parser that we're done */ - status = apr_xml_parser_done(parser, pdoc); - if (status) - goto parser_error; - - return OK; - - parser_error: - (void) apr_xml_parser_geterror(parser, errbuf, sizeof(errbuf)); - ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "%s", errbuf); - - /* FALLTHRU */ - - read_error: - /* make sure the parser is terminated */ - (void) apr_xml_parser_done(parser, NULL); - - /* Apache will supply a default error, plus the error log above. */ - return HTTP_BAD_REQUEST; -} diff --git a/server/vhost.c b/server/vhost.c deleted file mode 100644 index ca373e5916..0000000000 --- a/server/vhost.c +++ /dev/null @@ -1,1017 +0,0 @@ -/* ==================================================================== - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2000-2001 The Apache Software Foundation. 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. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowledgment may appear in the software itself, - * if and wherever such third-party acknowledgments normally appear. - * - * 4. The names "Apache" and "Apache Software Foundation" 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 name, without prior written - * permission of the Apache Software Foundation. - * - * THIS SOFTWARE IS PROVIDED ``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 SOFTWARE FOUNDATION 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 Software Foundation. For more - * information on the Apache Software Foundation, please see - * <http://www.apache.org/>. - * - * Portions of this software are based upon public domain software - * originally written at the National Center for Supercomputing Applications, - * University of Illinois, Urbana-Champaign. - */ - -/* - * http_vhost.c: functions pertaining to virtual host addresses - * (configuration and run-time) - */ - -#include "apr.h" -#include "apr_strings.h" -#include "apr_lib.h" - -#define APR_WANT_STRFUNC -#include "apr_want.h" - -#define CORE_PRIVATE -#include "ap_config.h" -#include "httpd.h" -#include "http_config.h" -#include "http_log.h" -#include "http_vhost.h" -#include "http_protocol.h" -#include "http_core.h" - -#if APR_HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif - -/* - * After all the definitions there's an explanation of how it's all put - * together. - */ - -/* meta-list of name-vhosts. Each server_rec can be in possibly multiple - * lists of name-vhosts. - */ -typedef struct name_chain name_chain; -struct name_chain { - name_chain *next; - server_addr_rec *sar; /* the record causing it to be in - * this chain (needed for port comparisons) */ - server_rec *server; /* the server to use on a match */ -}; - -/* meta-list of ip addresses. Each server_rec can be in possibly multiple - * hash chains since it can have multiple ips. - */ -typedef struct ipaddr_chain ipaddr_chain; -struct ipaddr_chain { - ipaddr_chain *next; - server_addr_rec *sar; /* the record causing it to be in - * this chain (need for both ip addr and port - * comparisons) */ - server_rec *server; /* the server to use if this matches */ - name_chain *names; /* if non-NULL then a list of name-vhosts - * sharing this address */ -}; - -/* This defines the size of the hash apr_table_t used for hashing ip addresses - * of virtual hosts. It must be a power of two. - */ -#ifndef IPHASH_TABLE_SIZE -#define IPHASH_TABLE_SIZE 256 -#endif - -/* A (n) bucket hash table, each entry has a pointer to a server rec and - * a pointer to the other entries in that bucket. Each individual address, - * even for virtualhosts with multiple addresses, has an entry in this hash - * table. There are extra buckets for _default_, and name-vhost entries. - * - * Note that after config time this is constant, so it is thread-safe. - */ -static ipaddr_chain *iphash_table[IPHASH_TABLE_SIZE]; - -/* dump out statistics about the hash function */ -/* #define IPHASH_STATISTICS */ - -/* list of the _default_ servers */ -static ipaddr_chain *default_list; - -/* list of the NameVirtualHost addresses */ -static server_addr_rec *name_vhost_list; -static server_addr_rec **name_vhost_list_tail; - -/* - * How it's used: - * - * The ip address determines which chain in iphash_table is interesting, then - * a comparison is done down that chain to find the first ipaddr_chain whose - * sar matches the address:port pair. - * - * If that ipaddr_chain has names == NULL then you're done, it's an ip-vhost. - * - * Otherwise it's a name-vhost list, and the default is the server in the - * ipaddr_chain record. We tuck away the ipaddr_chain record in the - * conn_rec field vhost_lookup_data. Later on after the headers we get a - * second chance, and we use the name_chain to figure out what name-vhost - * matches the headers. - * - * If there was no ip address match in the iphash_table then do a lookup - * in the default_list. - * - * How it's put together ... well you should be able to figure that out - * from how it's used. Or something like that. - */ - - -/* called at the beginning of the config */ -void ap_init_vhost_config(apr_pool_t *p) -{ - memset(iphash_table, 0, sizeof(iphash_table)); - default_list = NULL; - name_vhost_list = NULL; - name_vhost_list_tail = &name_vhost_list; -} - - -/* - * Parses a host of the form <address>[:port] - * paddr is used to create a list in the order of input - * **paddr is the ->next pointer of the last entry (or s->addrs) - * *paddr is the variable used to keep track of **paddr between calls - * port is the default port to assume - */ -static const char *get_addresses(apr_pool_t *p, const char *w_, - server_addr_rec ***paddr, - apr_port_t default_port) -{ - apr_sockaddr_t *my_addr; - server_addr_rec *sar; - char *w, *host, *scope_id; - int wild_port; - size_t wlen; - apr_port_t port; - apr_status_t rv; - - if (*w_ == '\0') - return NULL; - - w = apr_pstrdup(p, w_); - /* apr_parse_addr_port() doesn't understand ":*" so handle that first. */ - wlen = strlen(w); - if (wlen > 2 && w[wlen - 1] == '*' && w[wlen - 2] == ':') { - w[wlen - 2] = '\0'; - wild_port = 1; - } - else { - wild_port = 0; - } - rv = apr_parse_addr_port(&host, &scope_id, &port, w, p); - if (rv != APR_SUCCESS) { - return "The address or port is invalid"; - } - if (scope_id) { - return "Scope ids are not supported"; - } - if (!port && !wild_port) { - port = default_port; - } - - if (strcmp(host, "*") == 0) { - rv = apr_sockaddr_info_get(&my_addr, NULL, APR_INET, port, 0, p); - my_addr->sa.sin.sin_addr.s_addr = htonl(INADDR_ANY); - } else if (strcasecmp(host, "_default_") == 0 - || strcmp(host, "255.255.255.255") == 0) { - rv = apr_sockaddr_info_get(&my_addr, NULL, APR_INET, port, 0, p); - ap_assert(rv == APR_SUCCESS); /* must be bug or out of storage */ - my_addr->sa.sin.sin_addr.s_addr = DEFAULT_VHOST_ADDR; - } else { - rv = apr_sockaddr_info_get(&my_addr, host, APR_UNSPEC, port, 0, p); - if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, - "Cannot resolve host name %s --- ignoring!", host); - return NULL; - } - } - - /* XXX Gotta go through *all* addresses for the host name! - * Fix apr_sockaddr_info_get() to save them! */ - - sar = apr_pcalloc(p, sizeof(server_addr_rec)); - **paddr = sar; - *paddr = &sar->next; - sar->host_addr = my_addr; - sar->host_port = port; - sar->virthost = host; - return NULL; -} - - -/* parse the <VirtualHost> addresses */ -const char *ap_parse_vhost_addrs(apr_pool_t *p, const char *hostname, server_rec *s) -{ - server_addr_rec **addrs; - const char *err; - - /* start the list of addreses */ - addrs = &s->addrs; - while (hostname[0]) { - err = get_addresses(p, ap_getword_conf(p, &hostname), &addrs, s->port); - if (err) { - *addrs = NULL; - return err; - } - } - /* terminate the list */ - *addrs = NULL; - if (s->addrs) { - if (s->addrs->host_port) { - /* override the default port which is inherited from main_server */ - s->port = s->addrs->host_port; - } - } - return NULL; -} - - -const char *ap_set_name_virtual_host (cmd_parms *cmd, void *dummy, - const char *arg) -{ - /* use whatever port the main server has at this point */ - return get_addresses(cmd->pool, arg, &name_vhost_list_tail, - cmd->server->port); -} - - -/* hash apr_table_t statistics, keep this in here for the beta period so - * we can find out if the hash function is ok - */ -#ifdef IPHASH_STATISTICS -static int iphash_compare(const void *a, const void *b) -{ - return (*(const int *) b - *(const int *) a); -} - - -static void dump_iphash_statistics(server_rec *main_s) -{ - unsigned count[IPHASH_TABLE_SIZE]; - int i; - ipaddr_chain *src; - unsigned total; - char buf[HUGE_STRING_LEN]; - char *p; - - total = 0; - for (i = 0; i < IPHASH_TABLE_SIZE; ++i) { - count[i] = 0; - for (src = iphash_table[i]; src; src = src->next) { - ++count[i]; - if (i < IPHASH_TABLE_SIZE) { - /* don't count the slop buckets in the total */ - ++total; - } - } - } - qsort(count, IPHASH_TABLE_SIZE, sizeof(count[0]), iphash_compare); - p = buf + apr_snprintf(buf, sizeof(buf), - "iphash: total hashed = %u, avg chain = %u, " - "chain lengths (count x len):", - total, total / IPHASH_TABLE_SIZE); - total = 1; - for (i = 1; i < IPHASH_TABLE_SIZE; ++i) { - if (count[i - 1] != count[i]) { - p += apr_snprintf(p, sizeof(buf) - (p - buf), " %ux%u", - total, count[i - 1]); - total = 1; - } - else { - ++total; - } - } - p += apr_snprintf(p, sizeof(buf) - (p - buf), " %ux%u", - total, count[IPHASH_TABLE_SIZE - 1]); - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, main_s, buf); -} -#endif - - -/* This hashing function is designed to get good distribution in the cases - * where the server is handling entire "networks" of servers. i.e. a - * whack of /24s. This is probably the most common configuration for - * ISPs with large virtual servers. - * - * NOTE: This function is symmetric (i.e. collapses all 4 octets - * into one), so machine byte order (big/little endianness) does not matter. - * - * Hash function provided by David Hankins. - */ -static APR_INLINE unsigned hash_inaddr(unsigned key) -{ - key ^= (key >> 16); - return ((key >> 8) ^ key) % IPHASH_TABLE_SIZE; -} - -static APR_INLINE unsigned hash_addr(struct apr_sockaddr_t *sa) -{ - unsigned key; - - /* The key is the last four bytes of the IP address. - * For IPv4, this is the entire address, as always. - * For IPv6, this is usually part of the MAC address. - */ - key = *(unsigned *)((char *)sa->ipaddr_ptr + sa->ipaddr_len - 4); - return hash_inaddr(key); -} - -static ipaddr_chain *new_ipaddr_chain(apr_pool_t *p, - server_rec *s, server_addr_rec *sar) -{ - ipaddr_chain *new; - - new = apr_palloc(p, sizeof(*new)); - new->names = NULL; - new->server = s; - new->sar = sar; - new->next = NULL; - return new; -} - - -static name_chain *new_name_chain(apr_pool_t *p, server_rec *s, server_addr_rec *sar) -{ - name_chain *new; - - new = apr_palloc(p, sizeof(*new)); - new->server = s; - new->sar = sar; - new->next = NULL; - return new; -} - - -static APR_INLINE ipaddr_chain *find_ipaddr(apr_sockaddr_t *sa) -{ - unsigned bucket; - ipaddr_chain *trav; - - /* scan the hash apr_table_t for an exact match first */ - bucket = hash_addr(sa); - for (trav = iphash_table[bucket]; trav; trav = trav->next) { - server_addr_rec *sar = trav->sar; - apr_sockaddr_t *cur = sar->host_addr; - - if (cur->sa.sin.sin_port == 0 || - sa->sa.sin.sin_port == 0 || - cur->sa.sin.sin_port == sa->sa.sin.sin_port) { - if (cur->ipaddr_len == sa->ipaddr_len && - !memcmp(cur->ipaddr_ptr, - sa->ipaddr_ptr, - sa->ipaddr_len)) { - return trav; - } - } - } - return NULL; -} - - -static ipaddr_chain *find_default_server(apr_port_t port) -{ - server_addr_rec *sar; - ipaddr_chain *trav; - - for (trav = default_list; trav; trav = trav->next) { - sar = trav->sar; - if (sar->host_port == 0 || sar->host_port == port) { - /* match! */ - return trav; - } - } - return NULL; -} - -static void dump_a_vhost(apr_file_t *f, ipaddr_chain *ic) -{ - name_chain *nc; - int len; - char buf[MAX_STRING_LEN]; - apr_sockaddr_t *ha = ic->sar->host_addr; - - if (ha->sa.sin.sin_family == APR_INET && - ha->sa.sin.sin_addr.s_addr == DEFAULT_VHOST_ADDR) { - len = apr_snprintf(buf, sizeof(buf), "_default_:%u", - ic->sar->host_port); - } - else if (ha->sa.sin.sin_family == APR_INET && - ha->sa.sin.sin_addr.s_addr == INADDR_ANY) { - len = apr_snprintf(buf, sizeof(buf), "*:%u", - ic->sar->host_port); - } - else { - len = apr_snprintf(buf, sizeof(buf), "%pI", ha); - } - if (ic->sar->host_port == 0) { - buf[len-1] = '*'; - } - if (ic->names == NULL) { - apr_file_printf(f, "%-22s %s (%s:%u)\n", buf, ic->server->server_hostname, - ic->server->defn_name, ic->server->defn_line_number); - return; - } - apr_file_printf(f, "%-22s is a NameVirtualHost\n" - "%8s default server %s (%s:%u)\n", - buf, "", ic->server->server_hostname, - ic->server->defn_name, ic->server->defn_line_number); - for (nc = ic->names; nc; nc = nc->next) { - if (nc->sar->host_port) { - apr_file_printf(f, "%8s port %u ", "", nc->sar->host_port); - } - else { - apr_file_printf(f, "%8s port * ", ""); - } - apr_file_printf(f, "namevhost %s (%s:%u)\n", nc->server->server_hostname, - nc->server->defn_name, nc->server->defn_line_number); - } -} - -static void dump_vhost_config(apr_file_t *f) -{ - ipaddr_chain *ic; - int i; - - apr_file_printf(f, "VirtualHost configuration:\n"); - for (i = 0; i < IPHASH_TABLE_SIZE; ++i) { - for (ic = iphash_table[i]; ic; ic = ic->next) { - dump_a_vhost(f, ic); - } - } - if (default_list) { - apr_file_printf(f, "wildcard NameVirtualHosts and _default_ servers:\n"); - for (ic = default_list; ic; ic = ic->next) { - dump_a_vhost(f, ic); - } - } -} - -/* - * Two helper functions for ap_fini_vhost_config() - */ -static int add_name_vhost_config(apr_pool_t *p, server_rec *main_s, server_rec *s, - server_addr_rec *sar, ipaddr_chain *ic) -{ - /* the first time we encounter a NameVirtualHost address - * ic->server will be NULL, on subsequent encounters - * ic->names will be non-NULL. - */ - if (ic->names || ic->server == NULL) { - name_chain *nc = new_name_chain(p, s, sar); - nc->next = ic->names; - ic->names = nc; - ic->server = s; - if (sar->host_port != ic->sar->host_port) { - /* one of the two is a * port, the other isn't */ - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, main_s, - "VirtualHost %s:%u -- mixing * " - "ports and non-* ports with " - "a NameVirtualHost address is not supported," - " proceeding with undefined results", - sar->virthost, sar->host_port); - } - return 1; - } - else { - /* IP-based vhosts are handled by the caller */ - return 0; - } -} - -static void remove_unused_name_vhosts(server_rec *main_s, ipaddr_chain **pic) -{ - while (*pic) { - ipaddr_chain *ic = *pic; - - if (ic->server == NULL) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, main_s, - "NameVirtualHost %s:%u has no VirtualHosts", - ic->sar->virthost, ic->sar->host_port); - *pic = ic->next; - } - else if (ic->names == NULL) { - /* if server != NULL and names == NULL then we're done - * looking at NameVirtualHosts - */ - break; - } - else { - pic = &ic->next; - } - } -} - -/* compile the tables and such we need to do the run-time vhost lookups */ -AP_DECLARE(void) ap_fini_vhost_config(apr_pool_t *p, server_rec *main_s) -{ - server_addr_rec *sar; - int has_default_vhost_addr; - server_rec *s; - int i; - ipaddr_chain **iphash_table_tail[IPHASH_TABLE_SIZE]; - - /* terminate the name_vhost list */ - *name_vhost_list_tail = NULL; - - /* Main host first */ - s = main_s; - - if (!s->server_hostname) { - s->server_hostname = ap_get_local_host(p); - } - - /* initialize the tails */ - for (i = 0; i < IPHASH_TABLE_SIZE; ++i) { - iphash_table_tail[i] = &iphash_table[i]; - } - - /* The first things to go into the hash apr_table_t are the NameVirtualHosts - * Since name_vhost_list is in the same order that the directives - * occured in the config file, we'll copy it in that order. - */ - for (sar = name_vhost_list; sar; sar = sar->next) { - unsigned bucket = hash_addr(sar->host_addr); - ipaddr_chain *ic = new_ipaddr_chain(p, NULL, sar); - - if (sar->host_addr->sa.sin.sin_addr.s_addr != INADDR_ANY) { - *iphash_table_tail[bucket] = ic; - iphash_table_tail[bucket] = &ic->next; - } - else { - /* A wildcard NameVirtualHost goes on the default_list so - * that it can catch incoming requests on any address. - */ - ic->next = default_list; - default_list = ic; - } - /* Notice that what we've done is insert an ipaddr_chain with - * both server and names NULL. This fact is used to spot name- - * based vhosts in add_name_vhost_config(). - */ - } - - /* The next things to go into the hash apr_table_t are the virtual hosts - * themselves. They're listed off of main_s->next in the reverse - * order they occured in the config file, so we insert them at - * the iphash_table_tail but don't advance the tail. - */ - - for (s = main_s->next; s; s = s->next) { - has_default_vhost_addr = 0; - for (sar = s->addrs; sar; sar = sar->next) { - ipaddr_chain *ic; - - if (sar->host_addr->sa.sin.sin_addr.s_addr == DEFAULT_VHOST_ADDR - || sar->host_addr->sa.sin.sin_addr.s_addr == INADDR_ANY) { - ic = find_default_server(sar->host_port); - if (!ic || !add_name_vhost_config(p, main_s, s, sar, ic)) { - if (ic && ic->sar->host_port != 0) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, - 0, main_s, "_default_ VirtualHost overlap on port %u," - " the first has precedence", sar->host_port); - } - ic = new_ipaddr_chain(p, s, sar); - ic->next = default_list; - default_list = ic; - } - has_default_vhost_addr = 1; - } - else { - /* see if it matches something we've already got */ - ic = find_ipaddr(sar->host_addr); - - if (!ic) { - unsigned bucket = hash_addr(sar->host_addr); - - ic = new_ipaddr_chain(p, s, sar); - ic->next = *iphash_table_tail[bucket]; - *iphash_table_tail[bucket] = ic; - } - else if (!add_name_vhost_config(p, main_s, s, sar, ic)) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0, main_s, - "VirtualHost %s:%u overlaps with " - "VirtualHost %s:%u, the first has precedence, " - "perhaps you need a NameVirtualHost directive", - sar->virthost, sar->host_port, - ic->sar->virthost, ic->sar->host_port); - ic->sar = sar; - ic->server = s; - } - } - } - - /* Ok now we want to set up a server_hostname if the user was - * silly enough to forget one. - * XXX: This is silly we should just crash and burn. - */ - if (!s->server_hostname) { - if (has_default_vhost_addr) { - s->server_hostname = main_s->server_hostname; - } - else if (!s->addrs) { - /* what else can we do? at this point this vhost has - no configured name, probably because they used - DNS in the VirtualHost statement. It's disabled - anyhow by the host matching code. -djg */ - s->server_hostname = - apr_pstrdup(p, "bogus_host_without_forward_dns"); - } - else { - apr_status_t rv; - char *hostname; - - rv = apr_getnameinfo(&hostname, s->addrs->host_addr, 0); - if (rv == APR_SUCCESS) { - s->server_hostname = apr_pstrdup(p, hostname); - } - else { - /* again, what can we do? They didn't specify a - ServerName, and their DNS isn't working. -djg */ - char *ipaddr_str; - - apr_sockaddr_ip_get(&ipaddr_str, s->addrs->host_addr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, main_s, - "Failed to resolve server name " - "for %s (check DNS) -- or specify an explicit " - "ServerName", - ipaddr_str); - s->server_hostname = - apr_pstrdup(p, "bogus_host_without_reverse_dns"); - } - } - } - } - - /* now go through and delete any NameVirtualHosts that didn't have any - * hosts associated with them. Lamers. - */ - for (i = 0; i < IPHASH_TABLE_SIZE; ++i) { - remove_unused_name_vhosts(main_s, &iphash_table[i]); - } - remove_unused_name_vhosts(main_s, &default_list); - -#ifdef IPHASH_STATISTICS - dump_iphash_statistics(main_s); -#endif - if (ap_exists_config_define("DUMP_VHOSTS")) { - apr_file_t *thefile = NULL; - apr_file_open_stderr(&thefile, p); - dump_vhost_config(thefile); - } -} - - -/***************************************************************************** - * run-time vhost matching functions - */ - -/* Lowercase and remove any trailing dot and/or :port from the hostname, - * and check that it is sane. - * - * In most configurations the exact syntax of the hostname isn't - * important so strict sanity checking isn't necessary. However, in - * mass hosting setups (using mod_vhost_alias or mod_rewrite) where - * the hostname is interpolated into the filename, we need to be sure - * that the interpolation doesn't expose parts of the filesystem. - * We don't do strict RFC 952 / RFC 1123 syntax checking in order - * to support iDNS and people who erroneously use underscores. - * Instead we just check for filesystem metacharacters: directory - * separators / and \ and sequences of more than one dot. - */ -static void fix_hostname(request_rec *r) -{ - char *host, *scope_id; - char *dst; - apr_port_t port; - apr_status_t rv; - - rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool); - if (rv != APR_SUCCESS || scope_id) { - goto bad; - } - - /* if the hostname is an IPv6 numeric address string, it was validated - * already; otherwise, further validation is needed - */ - if (r->hostname[0] != '[') { - for (dst = host; *dst; dst++) { - if (*dst == '.') { - dst++; - if (*dst == '.') - goto bad; - } - else if (*dst == '/' || *dst == '\\') { - goto bad; - } - } - /* strip trailing gubbins */ - if (dst > host && dst[-1] == '.') { - dst[-1] = '\0'; - } - } - r->hostname = host; - return; - -bad: - r->status = HTTP_BAD_REQUEST; - ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, - "Client sent malformed Host header"); - return; -} - - -/* return 1 if host matches ServerName or ServerAliases */ -static int matches_aliases(server_rec *s, const char *host) -{ - int i; - apr_array_header_t *names; - - /* match ServerName */ - if (!strcasecmp(host, s->server_hostname)) { - return 1; - } - - /* search all the aliases from ServerAlias directive */ - names = s->names; - if (names) { - char **name = (char **) names->elts; - for (i = 0; i < names->nelts; ++i) { - if(!name[i]) continue; - if (!strcasecmp(host, name[i])) - return 1; - } - } - names = s->wild_names; - if (names) { - char **name = (char **) names->elts; - for (i = 0; i < names->nelts; ++i) { - if(!name[i]) continue; - if (!ap_strcasecmp_match(host, name[i])) - return 1; - } - } - return 0; -} - - -/* Suppose a request came in on the same socket as this r, and included - * a header "Host: host:port", would it map to r->server? It's more - * than just that though. When we do the normal matches for each request - * we don't even bother considering Host: etc on non-namevirtualhosts, - * we just call it a match. But here we require the host:port to match - * the ServerName and/or ServerAliases. - */ -AP_DECLARE(int) ap_matches_request_vhost(request_rec *r, const char *host, - apr_port_t port) -{ - server_rec *s; - server_addr_rec *sar; - - s = r->server; - - /* search all the <VirtualHost> values */ - /* XXX: If this is a NameVirtualHost then we may not be doing the Right Thing - * consider: - * - * NameVirtualHost 10.1.1.1 - * <VirtualHost 10.1.1.1> - * ServerName v1 - * </VirtualHost> - * <VirtualHost 10.1.1.1> - * ServerName v2 - * </VirtualHost> - * - * Suppose r->server is v2, and we're asked to match "10.1.1.1". We'll say - * "yup it's v2", when really it isn't... if a request came in for 10.1.1.1 - * it would really go to v1. - */ - for (sar = s->addrs; sar; sar = sar->next) { - if ((sar->host_port == 0 || port == sar->host_port) - && !strcasecmp(host, sar->virthost)) { - return 1; - } - } - - /* the Port has to match now, because the rest don't have ports associated - * with them. */ - if (port != s->port) { - return 0; - } - - return matches_aliases(s, host); -} - - -static void check_hostalias(request_rec *r) -{ - /* - * Even if the request has a Host: header containing a port we ignore - * that port. We always use the physical port of the socket. There - * are a few reasons for this: - * - * - the default of 80 or 443 for SSL is easier to handle this way - * - there is less of a possibility of a security problem - * - it simplifies the data structure - * - the client may have no idea that a proxy somewhere along the way - * translated the request to another ip:port - * - except for the addresses from the VirtualHost line, none of the other - * names we'll match have ports associated with them - */ - const char *host = r->hostname; - apr_port_t port; - server_rec *s; - server_rec *last_s; - name_chain *src; - apr_sockaddr_t *localsa; - - last_s = NULL; - apr_socket_addr_get(&localsa, APR_LOCAL, r->connection->client_socket); - apr_sockaddr_port_get(&port, localsa); - - /* Recall that the name_chain is a list of server_addr_recs, some of - * whose ports may not match. Also each server may appear more than - * once in the chain -- specifically, it will appear once for each - * address from its VirtualHost line which matched. We only want to - * do the full ServerName/ServerAlias comparisons once for each - * server, fortunately we know that all the VirtualHost addresses for - * a single server are adjacent to each other. - */ - - for (src = r->connection->vhost_lookup_data; src; src = src->next) { - server_addr_rec *sar; - - /* We only consider addresses on the name_chain which have a matching - * port - */ - sar = src->sar; - if (sar->host_port != 0 && port != sar->host_port) { - continue; - } - - s = src->server; - - /* does it match the virthost from the sar? */ - if (!strcasecmp(host, sar->virthost)) { - goto found; - } - - if (s == last_s) { - /* we've already done ServerName and ServerAlias checks for this - * vhost - */ - continue; - } - last_s = s; - - if (matches_aliases(s, host)) { - goto found; - } - } - return; - -found: - /* s is the first matching server, we're done */ - r->server = s; -} - - -static void check_serverpath(request_rec *r) -{ - server_rec *s; - server_rec *last_s; - name_chain *src; - apr_port_t port; - apr_sockaddr_t *localsa; - - apr_socket_addr_get(&localsa, APR_LOCAL, r->connection->client_socket); - apr_sockaddr_port_get(&port, localsa); - - /* - * This is in conjunction with the ServerPath code in http_core, so we - * get the right host attached to a non- Host-sending request. - * - * See the comment in check_hostalias about how each vhost can be - * listed multiple times. - */ - - last_s = NULL; - for (src = r->connection->vhost_lookup_data; src; src = src->next) { - /* We only consider addresses on the name_chain which have a matching - * port - */ - if (src->sar->host_port != 0 && port != src->sar->host_port) { - continue; - } - - s = src->server; - if (s == last_s) { - continue; - } - last_s = s; - - if (s->path && !strncmp(r->uri, s->path, s->pathlen) && - (s->path[s->pathlen - 1] == '/' || - r->uri[s->pathlen] == '/' || - r->uri[s->pathlen] == '\0')) { - r->server = s; - return; - } - } -} - - -void ap_update_vhost_from_headers(request_rec *r) -{ - /* must set this for HTTP/1.1 support */ - if (r->hostname || (r->hostname = apr_table_get(r->headers_in, "Host"))) { - fix_hostname(r); - if (r->status != HTTP_OK) - return; - } - /* check if we tucked away a name_chain */ - if (r->connection->vhost_lookup_data) { - if (r->hostname) - check_hostalias(r); - else - check_serverpath(r); - } -} - - -/* Called for a new connection which has a known local_addr. Note that the - * new connection is assumed to have conn->server == main server. - */ -void ap_update_vhost_given_ip(conn_rec *conn) -{ - ipaddr_chain *trav; - apr_port_t port; - - /* scan the hash apr_table_t for an exact match first */ - trav = find_ipaddr(conn->local_addr); - if (trav) { - /* save the name_chain for later in case this is a name-vhost */ - conn->vhost_lookup_data = trav->names; - conn->base_server = trav->server; - return; - } - - /* maybe there's a default server or wildcard name-based vhost - * matching this port - */ - apr_sockaddr_port_get(&port, conn->local_addr); - trav = find_default_server(port); - if (trav) { - conn->vhost_lookup_data = trav->names; - conn->base_server = trav->server; - return; - } - - /* otherwise we're stuck with just the main server - * and no name-based vhosts - */ - conn->vhost_lookup_data = NULL; -} |