diff -Nur httpd-2.2.17-peruser-rc2/modules/generators/mod_status.c.orig httpd-2.2.17-peruser-rc3/modules/generators/mod_status.c.orig --- httpd-2.2.17-peruser-rc2/modules/generators/mod_status.c.orig 2008-01-02 07:43:52.000000000 -0200 +++ httpd-2.2.17-peruser-rc3/modules/generators/mod_status.c.orig 1969-12-31 21:00:00.000000000 -0300 @@ -1,881 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Status Module. Display lots of internal data about how Apache is - * performing and the state of all children processes. - * - * To enable this, add the following lines into any config file: - * - * - * SetHandler server-status - * - * - * You may want to protect this location by password or domain so no one - * else can look at it. Then you can access the statistics with a URL like: - * - * http://your_server_name/server-status - * - * /server-status - Returns page using tables - * /server-status?notable - Returns page for browsers without table support - * /server-status?refresh - Returns page with 1 second refresh - * /server-status?refresh=6 - Returns page with refresh every 6 seconds - * /server-status?auto - Returns page with data for automatic parsing - * - * Mark Cox, mark@ukweb.com, November 1995 - * - * 12.11.95 Initial version for www.telescope.org - * 13.3.96 Updated to remove rprintf's [Mark] - * 18.3.96 Added CPU usage, process information, and tidied [Ben Laurie] - * 18.3.96 Make extra Scoreboard variables #definable - * 25.3.96 Make short report have full precision [Ben Laurie suggested] - * 25.3.96 Show uptime better [Mark/Ben Laurie] - * 29.3.96 Better HTML and explanation [Mark/Rob Hartill suggested] - * 09.4.96 Added message for non-STATUS compiled version - * 18.4.96 Added per child and per slot counters [Jim Jagielski] - * 01.5.96 Table format, cleanup, even more spiffy data [Chuck Murcko/Jim J.] - * 18.5.96 Adapted to use new rprintf() routine, incidentally fixing a missing - * piece in short reports [Ben Laurie] - * 21.5.96 Additional Status codes (DNS and LOGGING only enabled if - * extended STATUS is enabled) [George Burgyan/Jim J.] - * 10.8.98 Allow for extended status info at runtime (no more STATUS) - * [Jim J.] - */ - -#define CORE_PRIVATE -#include "httpd.h" -#include "http_config.h" -#include "http_core.h" -#include "http_protocol.h" -#include "http_main.h" -#include "ap_mpm.h" -#include "util_script.h" -#include -#include "scoreboard.h" -#include "http_log.h" -#include "mod_status.h" -#if APR_HAVE_UNISTD_H -#include -#endif -#define APR_WANT_STRFUNC -#include "apr_want.h" -#include "apr_strings.h" - -#ifdef NEXT -#if (NX_CURRENT_COMPILER_RELEASE == 410) -#ifdef m68k -#define HZ 64 -#else -#define HZ 100 -#endif -#else -#include -#endif -#endif /* NEXT */ - -#define STATUS_MAXLINE 64 - -#define KBYTE 1024 -#define MBYTE 1048576L -#define GBYTE 1073741824L - -#ifndef DEFAULT_TIME_FORMAT -#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z" -#endif - -#define STATUS_MAGIC_TYPE "application/x-httpd-status" - -module AP_MODULE_DECLARE_DATA status_module; - -static int server_limit, thread_limit; - -/* Implement 'ap_run_status_hook'. */ -APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap, STATUS, int, status_hook, - (request_rec *r, int flags), - (r, flags), - OK, DECLINED) - -#ifdef HAVE_TIMES -/* ugh... need to know if we're running with a pthread implementation - * such as linuxthreads that treats individual threads as distinct - * processes; that affects how we add up CPU time in a process - */ -static pid_t child_pid; -#endif - -/* - * command-related code. This is here to prevent use of ExtendedStatus - * without status_module included. - */ -static const char *set_extended_status(cmd_parms *cmd, void *dummy, int arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - ap_extended_status = arg; - return NULL; -} - -static const char *set_reqtail(cmd_parms *cmd, void *dummy, int arg) -{ - const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); - if (err != NULL) { - return err; - } - ap_mod_status_reqtail = arg; - return NULL; -} - - -static const command_rec status_module_cmds[] = -{ - AP_INIT_FLAG("ExtendedStatus", set_extended_status, NULL, RSRC_CONF, - "\"On\" to enable extended status information, \"Off\" to disable"), - AP_INIT_FLAG("SeeRequestTail", set_reqtail, NULL, RSRC_CONF, - "For verbose requests, \"On\" to see the last 63 chars of the request, " - "\"Off\" (default) to see the first 63 in extended status display"), - {NULL} -}; - -/* Format the number of bytes nicely */ -static void format_byte_out(request_rec *r, apr_off_t bytes) -{ - if (bytes < (5 * KBYTE)) - ap_rprintf(r, "%d B", (int) bytes); - else if (bytes < (MBYTE / 2)) - ap_rprintf(r, "%.1f kB", (float) bytes / KBYTE); - else if (bytes < (GBYTE / 2)) - ap_rprintf(r, "%.1f MB", (float) bytes / MBYTE); - else - ap_rprintf(r, "%.1f GB", (float) bytes / GBYTE); -} - -static void format_kbyte_out(request_rec *r, apr_off_t kbytes) -{ - if (kbytes < KBYTE) - ap_rprintf(r, "%d kB", (int) kbytes); - else if (kbytes < MBYTE) - ap_rprintf(r, "%.1f MB", (float) kbytes / KBYTE); - else - ap_rprintf(r, "%.1f GB", (float) kbytes / MBYTE); -} - -static void show_time(request_rec *r, apr_interval_time_t tsecs) -{ - int days, hrs, mins, secs; - - secs = (int)(tsecs % 60); - tsecs /= 60; - mins = (int)(tsecs % 60); - tsecs /= 60; - hrs = (int)(tsecs % 24); - days = (int)(tsecs / 24); - - if (days) - ap_rprintf(r, " %d day%s", days, days == 1 ? "" : "s"); - - if (hrs) - ap_rprintf(r, " %d hour%s", hrs, hrs == 1 ? "" : "s"); - - if (mins) - ap_rprintf(r, " %d minute%s", mins, mins == 1 ? "" : "s"); - - if (secs) - ap_rprintf(r, " %d second%s", secs, secs == 1 ? "" : "s"); -} - -/* Main handler for x-httpd-status requests */ - -/* ID values for command table */ - -#define STAT_OPT_END -1 -#define STAT_OPT_REFRESH 0 -#define STAT_OPT_NOTABLE 1 -#define STAT_OPT_AUTO 2 - -struct stat_opt { - int id; - const char *form_data_str; - const char *hdr_out_str; -}; - -static const struct stat_opt status_options[] = /* see #defines above */ -{ - {STAT_OPT_REFRESH, "refresh", "Refresh"}, - {STAT_OPT_NOTABLE, "notable", NULL}, - {STAT_OPT_AUTO, "auto", NULL}, - {STAT_OPT_END, NULL, NULL} -}; - -static char status_flags[SERVER_NUM_STATUS]; - -static int status_handler(request_rec *r) -{ - const char *loc; - apr_time_t nowtime; - apr_interval_time_t up_time; - int j, i, res; - int ready; - int busy; - unsigned long count; - unsigned long lres, my_lres, conn_lres; - apr_off_t bytes, my_bytes, conn_bytes; - apr_off_t bcount, kbcount; - long req_time; -#ifdef HAVE_TIMES - float tick; - int times_per_thread = getpid() != child_pid; -#endif - int short_report; - int no_table_report; - worker_score *ws_record; - process_score *ps_record; - char *stat_buffer; - pid_t *pid_buffer, worker_pid; - clock_t tu, ts, tcu, tcs; - ap_generation_t worker_generation; - - if (strcmp(r->handler, STATUS_MAGIC_TYPE) && - strcmp(r->handler, "server-status")) { - return DECLINED; - } - -#ifdef HAVE_TIMES -#ifdef _SC_CLK_TCK - tick = sysconf(_SC_CLK_TCK); -#else - tick = HZ; -#endif -#endif - - ready = 0; - busy = 0; - count = 0; - bcount = 0; - kbcount = 0; - short_report = 0; - no_table_report = 0; - - pid_buffer = apr_palloc(r->pool, server_limit * sizeof(pid_t)); - stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char)); - - nowtime = apr_time_now(); - tu = ts = tcu = tcs = 0; - - if (!ap_exists_scoreboard_image()) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "Server status unavailable in inetd mode"); - return HTTP_INTERNAL_SERVER_ERROR; - } - - r->allowed = (AP_METHOD_BIT << M_GET); - if (r->method_number != M_GET) - return DECLINED; - - ap_set_content_type(r, "text/html; charset=ISO-8859-1"); - - /* - * Simple table-driven form data set parser that lets you alter the header - */ - - if (r->args) { - i = 0; - while (status_options[i].id != STAT_OPT_END) { - if ((loc = ap_strstr_c(r->args, - status_options[i].form_data_str)) != NULL) { - switch (status_options[i].id) { - case STAT_OPT_REFRESH: { - apr_size_t len = strlen(status_options[i].form_data_str); - long t = 0; - - if (*(loc + len ) == '=') { - t = atol(loc + len + 1); - } - apr_table_set(r->headers_out, - status_options[i].hdr_out_str, - apr_ltoa(r->pool, t < 1 ? 10 : t)); - break; - } - case STAT_OPT_NOTABLE: - no_table_report = 1; - break; - case STAT_OPT_AUTO: - ap_set_content_type(r, "text/plain; charset=ISO-8859-1"); - short_report = 1; - break; - } - } - - i++; - } - } - - for (i = 0; i < server_limit; ++i) { -#ifdef HAVE_TIMES - clock_t proc_tu = 0, proc_ts = 0, proc_tcu = 0, proc_tcs = 0; - clock_t tmp_tu, tmp_ts, tmp_tcu, tmp_tcs; -#endif - - ps_record = ap_get_scoreboard_process(i); - for (j = 0; j < thread_limit; ++j) { - int indx = (i * thread_limit) + j; - - ws_record = ap_get_scoreboard_worker(i, j); - res = ws_record->status; - stat_buffer[indx] = status_flags[res]; - - if (!ps_record->quiescing - && ps_record->pid) { - if (res == SERVER_READY - && ps_record->generation == ap_my_generation) - ready++; - else if (res != SERVER_DEAD && - res != SERVER_STARTING && - res != SERVER_IDLE_KILL) - busy++; - } - - /* XXX what about the counters for quiescing/seg faulted - * processes? should they be counted or not? GLA - */ - if (ap_extended_status) { - lres = ws_record->access_count; - bytes = ws_record->bytes_served; - - if (lres != 0 || (res != SERVER_READY && res != SERVER_DEAD)) { -#ifdef HAVE_TIMES - tmp_tu = ws_record->times.tms_utime; - tmp_ts = ws_record->times.tms_stime; - tmp_tcu = ws_record->times.tms_cutime; - tmp_tcs = ws_record->times.tms_cstime; - - if (times_per_thread) { - proc_tu += tmp_tu; - proc_ts += tmp_ts; - proc_tcu += tmp_tcu; - proc_tcs += proc_tcs; - } - else { - if (tmp_tu > proc_tu || - tmp_ts > proc_ts || - tmp_tcu > proc_tcu || - tmp_tcs > proc_tcs) { - proc_tu = tmp_tu; - proc_ts = tmp_ts; - proc_tcu = tmp_tcu; - proc_tcs = proc_tcs; - } - } -#endif /* HAVE_TIMES */ - - count += lres; - bcount += bytes; - - if (bcount >= KBYTE) { - kbcount += (bcount >> 10); - bcount = bcount & 0x3ff; - } - } - } - } -#ifdef HAVE_TIMES - tu += proc_tu; - ts += proc_ts; - tcu += proc_tcu; - tcs += proc_tcs; -#endif - pid_buffer[i] = ps_record->pid; - } - - /* up_time in seconds */ - up_time = (apr_uint32_t) apr_time_sec(nowtime - - ap_scoreboard_image->global->restart_time); - - if (!short_report) { - ap_rputs(DOCTYPE_HTML_3_2 - "\nApache Status\n\n", - r); - ap_rputs("

Apache Server Status for ", r); - ap_rvputs(r, ap_get_server_name(r), "

\n\n", NULL); - ap_rvputs(r, "
Server Version: ", - ap_get_server_description(), "
\n", NULL); - ap_rvputs(r, "
Server Built: ", - ap_get_server_built(), "\n

\n", NULL); - ap_rvputs(r, "
Current Time: ", - ap_ht_time(r->pool, nowtime, DEFAULT_TIME_FORMAT, 0), - "
\n", NULL); - ap_rvputs(r, "
Restart Time: ", - ap_ht_time(r->pool, - ap_scoreboard_image->global->restart_time, - DEFAULT_TIME_FORMAT, 0), - "
\n", NULL); - ap_rprintf(r, "
Parent Server Generation: %d
\n", - (int)ap_my_generation); - ap_rputs("
Server uptime: ", r); - show_time(r, up_time); - ap_rputs("
\n", r); - } - - if (ap_extended_status) { - if (short_report) { - ap_rprintf(r, "Total Accesses: %lu\nTotal kBytes: %" - APR_OFF_T_FMT "\n", - count, kbcount); - -#ifdef HAVE_TIMES - /* Allow for OS/2 not having CPU stats */ - if (ts || tu || tcu || tcs) - ap_rprintf(r, "CPULoad: %g\n", - (tu + ts + tcu + tcs) / tick / up_time * 100.); -#endif - - ap_rprintf(r, "Uptime: %ld\n", (long) (up_time)); - if (up_time > 0) - ap_rprintf(r, "ReqPerSec: %g\n", - (float) count / (float) up_time); - - if (up_time > 0) - ap_rprintf(r, "BytesPerSec: %g\n", - KBYTE * (float) kbcount / (float) up_time); - - if (count > 0) - ap_rprintf(r, "BytesPerReq: %g\n", - KBYTE * (float) kbcount / (float) count); - } - else { /* !short_report */ - ap_rprintf(r, "
Total accesses: %lu - Total Traffic: ", count); - format_kbyte_out(r, kbcount); - ap_rputs("
\n", r); - -#ifdef HAVE_TIMES - /* Allow for OS/2 not having CPU stats */ - ap_rprintf(r, "
CPU Usage: u%g s%g cu%g cs%g", - tu / tick, ts / tick, tcu / tick, tcs / tick); - - if (ts || tu || tcu || tcs) - ap_rprintf(r, " - %.3g%% CPU load
\n", - (tu + ts + tcu + tcs) / tick / up_time * 100.); -#endif - - if (up_time > 0) - ap_rprintf(r, "
%.3g requests/sec - ", - (float) count / (float) up_time); - - if (up_time > 0) { - format_byte_out(r, (unsigned long)(KBYTE * (float) kbcount - / (float) up_time)); - ap_rputs("/second - ", r); - } - - if (count > 0) { - format_byte_out(r, (unsigned long)(KBYTE * (float) kbcount - / (float) count)); - ap_rputs("/request", r); - } - - ap_rputs("
\n", r); - } /* short_report */ - } /* ap_extended_status */ - - if (!short_report) - ap_rprintf(r, "
%d requests currently being processed, " - "%d idle workers
\n", busy, ready); - else - ap_rprintf(r, "BusyWorkers: %d\nIdleWorkers: %d\n", busy, ready); - - /* send the scoreboard 'table' out */ - if (!short_report) - ap_rputs("
", r);
-    else
-        ap_rputs("Scoreboard: ", r);
-
-    for (i = 0; i < server_limit; ++i) {
-        for (j = 0; j < thread_limit; ++j) {
-            int indx = (i * thread_limit) + j;
-            ap_rputc(stat_buffer[indx], r);
-            if ((indx % STATUS_MAXLINE == (STATUS_MAXLINE - 1))
-                && !short_report)
-                ap_rputs("\n", r);
-        }
-    }
-
-    if (short_report)
-        ap_rputs("\n", r);
-    else {
-        ap_rputs("
\n", r); - ap_rputs("

Scoreboard Key:
\n", r); - ap_rputs("\"_\" Waiting for Connection, \n", r); - ap_rputs("\"S\" Starting up, \n", r); - ap_rputs("\"R\" Reading Request,
\n", r); - ap_rputs("\"W\" Sending Reply, \n", r); - ap_rputs("\"K\" Keepalive (read), \n", r); - ap_rputs("\"D\" DNS Lookup,
\n", r); - ap_rputs("\"C\" Closing connection, \n", r); - ap_rputs("\"L\" Logging, \n", r); - ap_rputs("\"G\" Gracefully finishing,
\n", r); - ap_rputs("\"I\" Idle cleanup of worker, \n", r); - ap_rputs("\".\" Open slot with no current process

\n", r); - ap_rputs("

\n", r); - if (!ap_extended_status) { - int j; - int k = 0; - ap_rputs("PID Key:
\n", r); - ap_rputs("

\n", r);
-            for (i = 0; i < server_limit; ++i) {
-                for (j = 0; j < thread_limit; ++j) {
-                    int indx = (i * thread_limit) + j;
-
-                    if (stat_buffer[indx] != '.') {
-                        ap_rprintf(r, "   %" APR_PID_T_FMT
-                                   " in state: %c ", pid_buffer[i],
-                                   stat_buffer[indx]);
-
-                        if (++k >= 3) {
-                            ap_rputs("\n", r);
-                            k = 0;
-                        } else
-                            ap_rputs(",", r);
-                    }
-                }
-            }
-
-            ap_rputs("\n", r);
-            ap_rputs("
\n", r); - } - } - - if (ap_extended_status && !short_report) { - if (no_table_report) - ap_rputs("

Server Details

\n\n", r); - else - ap_rputs("\n\n" - "" - "" -#ifdef HAVE_TIMES - "" -#endif - "" - "" - "" - "\n\n", r); - - for (i = 0; i < server_limit; ++i) { - for (j = 0; j < thread_limit; ++j) { - ws_record = ap_get_scoreboard_worker(i, j); - - if (ws_record->access_count == 0 && - (ws_record->status == SERVER_READY || - ws_record->status == SERVER_DEAD)) { - continue; - } - - ps_record = ap_get_scoreboard_process(i); - - if (ws_record->start_time == 0L) - req_time = 0L; - else - req_time = (long) - ((ws_record->stop_time - - ws_record->start_time) / 1000); - if (req_time < 0L) - req_time = 0L; - - lres = ws_record->access_count; - my_lres = ws_record->my_access_count; - conn_lres = ws_record->conn_count; - bytes = ws_record->bytes_served; - my_bytes = ws_record->my_bytes_served; - conn_bytes = ws_record->conn_bytes; - if (ws_record->pid) { /* MPM sets per-worker pid and generation */ - worker_pid = ws_record->pid; - worker_generation = ws_record->generation; - } - else { - worker_pid = ps_record->pid; - worker_generation = ps_record->generation; - } - - if (no_table_report) { - if (ws_record->status == SERVER_DEAD) - ap_rprintf(r, - "Server %d-%d (-): %d|%lu|%lu [", - i, (int)worker_generation, - (int)conn_lres, my_lres, lres); - else - ap_rprintf(r, - "Server %d-%d (%" - APR_PID_T_FMT "): %d|%lu|%lu [", - i, (int) worker_generation, - worker_pid, - (int)conn_lres, my_lres, lres); - - switch (ws_record->status) { - case SERVER_READY: - ap_rputs("Ready", r); - break; - case SERVER_STARTING: - ap_rputs("Starting", r); - break; - case SERVER_BUSY_READ: - ap_rputs("Read", r); - break; - case SERVER_BUSY_WRITE: - ap_rputs("Write", r); - break; - case SERVER_BUSY_KEEPALIVE: - ap_rputs("Keepalive", r); - break; - case SERVER_BUSY_LOG: - ap_rputs("Logging", r); - break; - case SERVER_BUSY_DNS: - ap_rputs("DNS lookup", r); - break; - case SERVER_CLOSING: - ap_rputs("Closing", r); - break; - case SERVER_DEAD: - ap_rputs("Dead", r); - break; - case SERVER_GRACEFUL: - ap_rputs("Graceful", r); - break; - case SERVER_IDLE_KILL: - ap_rputs("Dying", r); - break; - default: - ap_rputs("?STATE?", r); - break; - } - - ap_rprintf(r, "] " -#ifdef HAVE_TIMES - "u%g s%g cu%g cs%g" -#endif - "\n %ld %ld (", -#ifdef HAVE_TIMES - ws_record->times.tms_utime / tick, - ws_record->times.tms_stime / tick, - ws_record->times.tms_cutime / tick, - ws_record->times.tms_cstime / tick, -#endif - (long)apr_time_sec(nowtime - - ws_record->last_used), - (long) req_time); - - format_byte_out(r, conn_bytes); - ap_rputs("|", r); - format_byte_out(r, my_bytes); - ap_rputs("|", r); - format_byte_out(r, bytes); - ap_rputs(")\n", r); - ap_rprintf(r, - " %s {%s}[%s]
\n\n", - ap_escape_html(r->pool, - ws_record->client), - ap_escape_html(r->pool, - ap_escape_logitem(r->pool, - ws_record->request)), - ap_escape_html(r->pool, - ws_record->vhost)); - } - else { /* !no_table_report */ - if (ws_record->status == SERVER_DEAD) - ap_rprintf(r, - "" -#ifdef HAVE_TIMES - "" -#endif - "\n\n"); - else - ap_rprintf(r, - "\n\n", - ap_escape_html(r->pool, - ws_record->client), - ap_escape_html(r->pool, - ws_record->vhost), - ap_escape_html(r->pool, - ap_escape_logitem(r->pool, - ws_record->request))); - } /* no_table_report */ - } /* for (j...) */ - } /* for (i...) */ - - if (!no_table_report) { - ap_rputs("
SrvPIDAccMCPU\nSSReqConnChildSlotClientVHostRequest
%d-%d-%d/%lu/%lu", - i, (int)worker_generation, - (int)conn_lres, my_lres, lres); - else - ap_rprintf(r, - "
%d-%d%" - APR_PID_T_FMT - "%d/%lu/%lu", - i, (int)worker_generation, - worker_pid, - (int)conn_lres, - my_lres, lres); - - switch (ws_record->status) { - case SERVER_READY: - ap_rputs("_", r); - break; - case SERVER_STARTING: - ap_rputs("S", r); - break; - case SERVER_BUSY_READ: - ap_rputs("R", r); - break; - case SERVER_BUSY_WRITE: - ap_rputs("W", r); - break; - case SERVER_BUSY_KEEPALIVE: - ap_rputs("K", r); - break; - case SERVER_BUSY_LOG: - ap_rputs("L", r); - break; - case SERVER_BUSY_DNS: - ap_rputs("D", r); - break; - case SERVER_CLOSING: - ap_rputs("C", r); - break; - case SERVER_DEAD: - ap_rputs(".", r); - break; - case SERVER_GRACEFUL: - ap_rputs("G", r); - break; - case SERVER_IDLE_KILL: - ap_rputs("I", r); - break; - default: - ap_rputs("?", r); - break; - } - - ap_rprintf(r, - "\n%.2f%ld%ld", -#ifdef HAVE_TIMES - (ws_record->times.tms_utime + - ws_record->times.tms_stime + - ws_record->times.tms_cutime + - ws_record->times.tms_cstime) / tick, -#endif - (long)apr_time_sec(nowtime - - ws_record->last_used), - (long)req_time); - - ap_rprintf(r, "%-1.1f%-2.2f%-2.2f\n", - (float)conn_bytes / KBYTE, (float) my_bytes / MBYTE, - (float)bytes / MBYTE); - - if (ws_record->status == SERVER_BUSY_READ) - ap_rprintf(r, - "??..reading..
%s%s%s
\n \ -
\ -\n \ -\n \ -\n \ -\n \ -\n" - -#ifdef HAVE_TIMES -"\n" -#endif - -"\n \ -\n \ -\n \ -\n \ -\n \ -
SrvChild Server number - generation
PIDOS process ID
AccNumber of accesses this connection / this child / this slot
MMode of operation
CPUCPU usage, number of seconds
SSSeconds since beginning of most recent request
ReqMilliseconds required to process most recent request
ConnKilobytes transferred this connection
ChildMegabytes transferred this child
SlotTotal megabytes transferred this slot
\n", r); - } - } /* if (ap_extended_status && !short_report) */ - else { - - if (!short_report) { - ap_rputs("
To obtain a full report with current status " - "information you need to use the " - "ExtendedStatus On directive.\n", r); - } - } - - { - /* Run extension hooks to insert extra content. */ - int flags = - (short_report ? AP_STATUS_SHORT : 0) | - (no_table_report ? AP_STATUS_NOTABLE : 0) | - (ap_extended_status ? AP_STATUS_EXTENDED : 0); - - ap_run_status_hook(r, flags); - } - - if (!short_report) { - ap_rputs(ap_psignature("
\n",r), r); - ap_rputs("\n", r); - } - - return 0; -} - - -static int status_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, - server_rec *s) -{ - status_flags[SERVER_DEAD] = '.'; /* We don't want to assume these are in */ - status_flags[SERVER_READY] = '_'; /* any particular order in scoreboard.h */ - status_flags[SERVER_STARTING] = 'S'; - status_flags[SERVER_BUSY_READ] = 'R'; - status_flags[SERVER_BUSY_WRITE] = 'W'; - status_flags[SERVER_BUSY_KEEPALIVE] = 'K'; - status_flags[SERVER_BUSY_LOG] = 'L'; - status_flags[SERVER_BUSY_DNS] = 'D'; - status_flags[SERVER_CLOSING] = 'C'; - status_flags[SERVER_GRACEFUL] = 'G'; - status_flags[SERVER_IDLE_KILL] = 'I'; - ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); - ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit); - return OK; -} - -#ifdef HAVE_TIMES -static void status_child_init(apr_pool_t *p, server_rec *s) -{ - child_pid = getpid(); -} -#endif - -static void register_hooks(apr_pool_t *p) -{ - ap_hook_handler(status_handler, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_post_config(status_init, NULL, NULL, APR_HOOK_MIDDLE); -#ifdef HAVE_TIMES - ap_hook_child_init(status_child_init, NULL, NULL, APR_HOOK_MIDDLE); -#endif -} - -module AP_MODULE_DECLARE_DATA status_module = -{ - STANDARD20_MODULE_STUFF, - NULL, /* dir config creater */ - NULL, /* dir merger --- default is to override */ - NULL, /* server config */ - NULL, /* merge server config */ - status_module_cmds, /* command table */ - register_hooks /* register_hooks */ -}; - diff -Nur httpd-2.2.17-peruser-rc2/modules/generators/mod_status.h.orig httpd-2.2.17-peruser-rc3/modules/generators/mod_status.h.orig --- httpd-2.2.17-peruser-rc2/modules/generators/mod_status.h.orig 2006-07-12 00:38:44.000000000 -0300 +++ httpd-2.2.17-peruser-rc3/modules/generators/mod_status.h.orig 1969-12-31 21:00:00.000000000 -0300 @@ -1,64 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file mod_status.h - * @brief Status Report Extension Module to Apache - * - * @defgroup MOD_STATUS mod_status - * @ingroup APACHE_MODS - * @{ - */ - -#ifndef MOD_STATUS_H -#define MOD_STATUS_H - -#include "ap_config.h" -#include "httpd.h" - -#define AP_STATUS_SHORT (0x1) /* short, non-HTML report requested */ -#define AP_STATUS_NOTABLE (0x2) /* HTML report without tables */ -#define AP_STATUS_EXTENDED (0x4) /* detailed report */ - -#if !defined(WIN32) -#define STATUS_DECLARE(type) type -#define STATUS_DECLARE_NONSTD(type) type -#define STATUS_DECLARE_DATA -#elif defined(STATUS_DECLARE_STATIC) -#define STATUS_DECLARE(type) type __stdcall -#define STATUS_DECLARE_NONSTD(type) type -#define STATUS_DECLARE_DATA -#elif defined(STATUS_DECLARE_EXPORT) -#define STATUS_DECLARE(type) __declspec(dllexport) type __stdcall -#define STATUS_DECLARE_NONSTD(type) __declspec(dllexport) type -#define STATUS_DECLARE_DATA __declspec(dllexport) -#else -#define STATUS_DECLARE(type) __declspec(dllimport) type __stdcall -#define STATUS_DECLARE_NONSTD(type) __declspec(dllimport) type -#define STATUS_DECLARE_DATA __declspec(dllimport) -#endif - -/* Optional hooks which can insert extra content into the mod_status - * output. FLAGS will be set to the bitwise OR of any of the - * AP_STATUS_* flags. - * - * Implementations of this hook should generate content using - * functions in the ap_rputs/ap_rprintf family; each hook should - * return OK or DECLINED. */ -APR_DECLARE_EXTERNAL_HOOK(ap, STATUS, int, status_hook, - (request_rec *r, int flags)) -#endif -/** @} */ diff -Nur httpd-2.2.17-peruser-rc2/modules/ssl/mod_ssl.h.orig httpd-2.2.17-peruser-rc3/modules/ssl/mod_ssl.h.orig --- httpd-2.2.17-peruser-rc2/modules/ssl/mod_ssl.h.orig 2006-07-12 00:38:44.000000000 -0300 +++ httpd-2.2.17-peruser-rc3/modules/ssl/mod_ssl.h.orig 1969-12-31 21:00:00.000000000 -0300 @@ -1,64 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file mod_ssl.h - * @brief SSL extension module for Apache - * - * @defgroup MOD_SSL mod_ssl - * @ingroup APACHE_MODS - * @{ - */ - -#ifndef __MOD_SSL_H__ -#define __MOD_SSL_H__ - -#include "httpd.h" -#include "apr_optional.h" - -/** The ssl_var_lookup() optional function retrieves SSL environment - * variables. */ -APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup, - (apr_pool_t *, server_rec *, - conn_rec *, request_rec *, - char *)); - -/** The ssl_ext_lookup() optional function retrieves the value of a SSL - * certificate X.509 extension. The client certificate is used if - * peer is non-zero; the server certificate is used otherwise. The - * oidnum parameter specifies the numeric OID (e.g. "1.2.3.4") of the - * desired extension. The string value of the extension is returned, - * or NULL on error. */ -APR_DECLARE_OPTIONAL_FN(const char *, ssl_ext_lookup, - (apr_pool_t *p, conn_rec *c, int peer, - const char *oidnum)); - -/** An optional function which returns non-zero if the given connection - * is using SSL/TLS. */ -APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); - -/** The ssl_proxy_enable() and ssl_engine_disable() optional functions - * are used by mod_proxy to enable use of SSL for outgoing - * connections. */ - -APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); - -APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); - -APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, ssl_extlist_by_oid, (request_rec *r, const char *oidstr)); - -#endif /* __MOD_SSL_H__ */ -/** @} */ diff -Nur httpd-2.2.17-peruser-rc2/modules/ssl/ssl_engine_vars.c.orig httpd-2.2.17-peruser-rc3/modules/ssl/ssl_engine_vars.c.orig --- httpd-2.2.17-peruser-rc2/modules/ssl/ssl_engine_vars.c.orig 2010-02-27 18:00:58.000000000 -0300 +++ httpd-2.2.17-peruser-rc3/modules/ssl/ssl_engine_vars.c.orig 1969-12-31 21:00:00.000000000 -0300 @@ -1,934 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* _ _ - * _ __ ___ ___ __| | ___ ___| | mod_ssl - * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL - * | | | | | | (_) | (_| | \__ \__ \ | - * |_| |_| |_|\___/ \__,_|___|___/___/_| - * |_____| - * ssl_engine_vars.c - * Variable Lookup Facility - */ - /* ``Those of you who think they - know everything are very annoying - to those of us who do.'' - -- Unknown */ -#include "ssl_private.h" -#include "mod_ssl.h" - -#include "apr_time.h" - -/* _________________________________________________________________ -** -** Variable Lookup -** _________________________________________________________________ -*/ - -static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var); -static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var); -static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var); -static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_UTCTIME *tm); -static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_UTCTIME *tm); -static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs); -static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var); -static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs); -static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, conn_rec *c); -static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, conn_rec *c, char *var); -static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize); -static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var); -static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl); - -static int ssl_is_https(conn_rec *c) -{ - SSLConnRec *sslconn = myConnConfig(c); - return sslconn && sslconn->ssl; -} - -static const char var_interface[] = "mod_ssl/" MOD_SSL_VERSION; -static char var_library_interface[] = SSL_LIBRARY_TEXT; -static char *var_library = NULL; - -void ssl_var_register(apr_pool_t *p) -{ - char *cp, *cp2; - - APR_REGISTER_OPTIONAL_FN(ssl_is_https); - APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); - APR_REGISTER_OPTIONAL_FN(ssl_ext_lookup); - - /* Perform once-per-process library version determination: */ - var_library = apr_pstrdup(p, SSL_LIBRARY_DYNTEXT); - - if ((cp = strchr(var_library, ' ')) != NULL) { - *cp = '/'; - if ((cp2 = strchr(cp, ' ')) != NULL) - *cp2 = NUL; - } - - if ((cp = strchr(var_library_interface, ' ')) != NULL) { - *cp = '/'; - if ((cp2 = strchr(cp, ' ')) != NULL) - *cp2 = NUL; - } -} - -/* This function must remain safe to use for a non-SSL connection. */ -char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var) -{ - SSLModConfigRec *mc = myModConfig(s); - const char *result; - BOOL resdup; - apr_time_exp_t tm; - - result = NULL; - resdup = TRUE; - - /* - * When no pool is given try to find one - */ - if (p == NULL) { - if (r != NULL) - p = r->pool; - else if (c != NULL) - p = c->pool; - else - p = mc->pPool; - } - - /* - * Request dependent stuff - */ - if (r != NULL) { - switch (var[0]) { - case 'H': - case 'h': - if (strcEQ(var, "HTTP_USER_AGENT")) - result = apr_table_get(r->headers_in, "User-Agent"); - else if (strcEQ(var, "HTTP_REFERER")) - result = apr_table_get(r->headers_in, "Referer"); - else if (strcEQ(var, "HTTP_COOKIE")) - result = apr_table_get(r->headers_in, "Cookie"); - else if (strcEQ(var, "HTTP_FORWARDED")) - result = apr_table_get(r->headers_in, "Forwarded"); - else if (strcEQ(var, "HTTP_HOST")) - result = apr_table_get(r->headers_in, "Host"); - else if (strcEQ(var, "HTTP_PROXY_CONNECTION")) - result = apr_table_get(r->headers_in, "Proxy-Connection"); - else if (strcEQ(var, "HTTP_ACCEPT")) - result = apr_table_get(r->headers_in, "Accept"); - else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5)) - /* all other headers from which we are still not know about */ - result = apr_table_get(r->headers_in, var+5); - break; - - case 'R': - case 'r': - if (strcEQ(var, "REQUEST_METHOD")) - result = r->method; - else if (strcEQ(var, "REQUEST_SCHEME")) - result = ap_http_scheme(r); - else if (strcEQ(var, "REQUEST_URI")) - result = r->uri; - else if (strcEQ(var, "REQUEST_FILENAME")) - result = r->filename; - else if (strcEQ(var, "REMOTE_HOST")) - result = ap_get_remote_host(r->connection, r->per_dir_config, - REMOTE_NAME, NULL); - else if (strcEQ(var, "REMOTE_IDENT")) - result = ap_get_remote_logname(r); - else if (strcEQ(var, "REMOTE_USER")) - result = r->user; - break; - - case 'S': - case 's': - if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */ - - if (strcEQ(var, "SERVER_ADMIN")) - result = r->server->server_admin; - else if (strcEQ(var, "SERVER_NAME")) - result = ap_get_server_name(r); - else if (strcEQ(var, "SERVER_PORT")) - result = apr_psprintf(p, "%u", ap_get_server_port(r)); - else if (strcEQ(var, "SERVER_PROTOCOL")) - result = r->protocol; - else if (strcEQ(var, "SCRIPT_FILENAME")) - result = r->filename; - break; - - default: - if (strcEQ(var, "PATH_INFO")) - result = r->path_info; - else if (strcEQ(var, "QUERY_STRING")) - result = r->args; - else if (strcEQ(var, "IS_SUBREQ")) - result = (r->main != NULL ? "true" : "false"); - else if (strcEQ(var, "DOCUMENT_ROOT")) - result = ap_document_root(r); - else if (strcEQ(var, "AUTH_TYPE")) - result = r->ap_auth_type; - else if (strcEQ(var, "THE_REQUEST")) - result = r->the_request; - break; - } - } - - /* - * Connection stuff - */ - if (result == NULL && c != NULL) { - SSLConnRec *sslconn = myConnConfig(c); - if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) - && sslconn && sslconn->ssl) - result = ssl_var_lookup_ssl(p, c, var+4); - else if (strcEQ(var, "REMOTE_ADDR")) - result = c->remote_ip; - else if (strcEQ(var, "HTTPS")) { - if (sslconn && sslconn->ssl) - result = "on"; - else - result = "off"; - } - } - - /* - * Totally independent stuff - */ - if (result == NULL) { - if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12)) - result = ssl_var_lookup_ssl_version(p, var+12); - else if (strcEQ(var, "SERVER_SOFTWARE")) - result = ap_get_server_banner(); - else if (strcEQ(var, "API_VERSION")) { - result = apr_itoa(p, MODULE_MAGIC_NUMBER); - resdup = FALSE; - } - else if (strcEQ(var, "TIME_YEAR")) { - apr_time_exp_lt(&tm, apr_time_now()); - result = apr_psprintf(p, "%02d%02d", - (tm.tm_year / 100) + 19, tm.tm_year % 100); - resdup = FALSE; - } -#define MKTIMESTR(format, tmfield) \ - apr_time_exp_lt(&tm, apr_time_now()); \ - result = apr_psprintf(p, format, tm.tmfield); \ - resdup = FALSE; - else if (strcEQ(var, "TIME_MON")) { - MKTIMESTR("%02d", tm_mon+1) - } - else if (strcEQ(var, "TIME_DAY")) { - MKTIMESTR("%02d", tm_mday) - } - else if (strcEQ(var, "TIME_HOUR")) { - MKTIMESTR("%02d", tm_hour) - } - else if (strcEQ(var, "TIME_MIN")) { - MKTIMESTR("%02d", tm_min) - } - else if (strcEQ(var, "TIME_SEC")) { - MKTIMESTR("%02d", tm_sec) - } - else if (strcEQ(var, "TIME_WDAY")) { - MKTIMESTR("%d", tm_wday) - } - else if (strcEQ(var, "TIME")) { - apr_time_exp_lt(&tm, apr_time_now()); - result = apr_psprintf(p, - "%02d%02d%02d%02d%02d%02d%02d", (tm.tm_year / 100) + 19, - (tm.tm_year % 100), tm.tm_mon+1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - resdup = FALSE; - } - /* all other env-variables from the parent Apache process */ - else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) { - result = apr_table_get(r->notes, var+4); - if (result == NULL) - result = apr_table_get(r->subprocess_env, var+4); - if (result == NULL) - result = getenv(var+4); - } - } - - if (result != NULL && resdup) - result = apr_pstrdup(p, result); - if (result == NULL) - result = ""; - return (char *)result; -} - -static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var) -{ - SSLConnRec *sslconn = myConnConfig(c); - char *result; - X509 *xs; - STACK_OF(X509) *sk; - SSL *ssl; - - result = NULL; - - ssl = sslconn->ssl; - if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) { - result = ssl_var_lookup_ssl_version(p, var+8); - } - else if (ssl != NULL && strcEQ(var, "PROTOCOL")) { - result = (char *)SSL_get_version(ssl); - } - else if (ssl != NULL && strcEQ(var, "SESSION_ID")) { - char buf[SSL_SESSION_ID_STRING_LEN]; - SSL_SESSION *pSession = SSL_get_session(ssl); - if (pSession) { - result = apr_pstrdup(p, SSL_SESSION_id2sz( - SSL_SESSION_get_session_id(pSession), - SSL_SESSION_get_session_id_length(pSession), - buf, sizeof(buf))); - } - } - else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) { - result = ssl_var_lookup_ssl_cipher(p, c, var+6); - } - else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) { - sk = SSL_get_peer_cert_chain(ssl); - result = ssl_var_lookup_ssl_cert_chain(p, sk, var+18); - } - else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) { - result = ssl_var_lookup_ssl_cert_verify(p, c); - } - else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) { - if ((xs = SSL_get_peer_certificate(ssl)) != NULL) { - result = ssl_var_lookup_ssl_cert(p, xs, var+7); - X509_free(xs); - } - } - else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) { - if ((xs = SSL_get_certificate(ssl)) != NULL) - result = ssl_var_lookup_ssl_cert(p, xs, var+7); - } - else if (ssl != NULL && strcEQ(var, "COMPRESS_METHOD")) { - result = ssl_var_lookup_ssl_compress_meth(ssl); - } -#ifndef OPENSSL_NO_TLSEXT - else if (ssl != NULL && strcEQ(var, "TLS_SNI")) { - result = apr_pstrdup(p, SSL_get_servername(ssl, - TLSEXT_NAMETYPE_host_name)); - } -#endif - else if (ssl != NULL && strcEQ(var, "SECURE_RENEG")) { - int flag = 0; -#ifdef SSL_get_secure_renegotiation_support - flag = SSL_get_secure_renegotiation_support(ssl); -#endif - result = apr_pstrdup(p, flag ? "true" : "false"); - } - - return result; -} - -static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, X509 *xs, char *var) -{ - char *result; - BOOL resdup; - X509_NAME *xsname; - int nid; - char *cp; - - result = NULL; - resdup = TRUE; - - if (strcEQ(var, "M_VERSION")) { - result = apr_psprintf(p, "%lu", X509_get_version(xs)+1); - resdup = FALSE; - } - else if (strcEQ(var, "M_SERIAL")) { - result = ssl_var_lookup_ssl_cert_serial(p, xs); - } - else if (strcEQ(var, "V_START")) { - result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs)); - } - else if (strcEQ(var, "V_END")) { - result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs)); - } - else if (strcEQ(var, "V_REMAIN")) { - result = ssl_var_lookup_ssl_cert_remain(p, X509_get_notAfter(xs)); - resdup = FALSE; - } - else if (strcEQ(var, "S_DN")) { - xsname = X509_get_subject_name(xs); - cp = X509_NAME_oneline(xsname, NULL, 0); - result = apr_pstrdup(p, cp); - modssl_free(cp); - resdup = FALSE; - } - else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) { - xsname = X509_get_subject_name(xs); - result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5); - resdup = FALSE; - } - else if (strcEQ(var, "I_DN")) { - xsname = X509_get_issuer_name(xs); - cp = X509_NAME_oneline(xsname, NULL, 0); - result = apr_pstrdup(p, cp); - modssl_free(cp); - resdup = FALSE; - } - else if (strlen(var) > 5 && strcEQn(var, "I_DN_", 5)) { - xsname = X509_get_issuer_name(xs); - result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5); - resdup = FALSE; - } - else if (strcEQ(var, "A_SIG")) { - nid = OBJ_obj2nid((ASN1_OBJECT *)X509_get_signature_algorithm(xs)); - result = apr_pstrdup(p, - (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid)); - resdup = FALSE; - } - else if (strcEQ(var, "A_KEY")) { - nid = OBJ_obj2nid((ASN1_OBJECT *)X509_get_key_algorithm(xs)); - result = apr_pstrdup(p, - (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid)); - resdup = FALSE; - } - else if (strcEQ(var, "CERT")) { - result = ssl_var_lookup_ssl_cert_PEM(p, xs); - } - - if (result != NULL && resdup) - result = apr_pstrdup(p, result); - return result; -} - -/* In this table, .extract is non-zero if RDNs using the NID should be - * extracted to for the SSL_{CLIENT,SERVER}_{I,S}_DN_* environment - * variables. */ -static const struct { - char *name; - int nid; - int extract; -} ssl_var_lookup_ssl_cert_dn_rec[] = { - { "C", NID_countryName, 1 }, - { "ST", NID_stateOrProvinceName, 1 }, /* officially (RFC2156) */ - { "SP", NID_stateOrProvinceName, 0 }, /* compatibility (SSLeay) */ - { "L", NID_localityName, 1 }, - { "O", NID_organizationName, 1 }, - { "OU", NID_organizationalUnitName, 1 }, - { "CN", NID_commonName, 1 }, - { "T", NID_title, 1 }, - { "I", NID_initials, 1 }, - { "G", NID_givenName, 1 }, - { "S", NID_surname, 1 }, - { "D", NID_description, 1 }, -#ifdef NID_userId - { "UID", NID_x500UniqueIdentifier, 1 }, -#endif - { "Email", NID_pkcs9_emailAddress, 1 }, - { NULL, 0, 0 } -}; - -static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var) -{ - char *result, *ptr; - X509_NAME_ENTRY *xsne; - int i, j, n, idx = 0; - apr_size_t varlen; - - /* if an _N suffix is used, find the Nth attribute of given name */ - ptr = strchr(var, '_'); - if (ptr != NULL && strspn(ptr + 1, "0123456789") == strlen(ptr + 1)) { - idx = atoi(ptr + 1); - varlen = ptr - var; - } else { - varlen = strlen(var); - } - - result = NULL; - - for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) { - if (strEQn(var, ssl_var_lookup_ssl_cert_dn_rec[i].name, varlen) - && strlen(ssl_var_lookup_ssl_cert_dn_rec[i].name) == varlen) { - for (j = 0; j < sk_X509_NAME_ENTRY_num((STACK_OF(X509_NAME_ENTRY) *) - X509_NAME_get_entries(xsname)); - j++) { - xsne = sk_X509_NAME_ENTRY_value((STACK_OF(X509_NAME_ENTRY) *) - X509_NAME_get_entries(xsname), j); - - n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); - - if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) { - unsigned char *data = X509_NAME_ENTRY_get_data_ptr(xsne); - /* cast needed from unsigned char to char */ - result = apr_pstrmemdup(p, (char *)data, - X509_NAME_ENTRY_get_data_len(xsne)); -#if APR_CHARSET_EBCDIC - ap_xlate_proto_from_ascii(result, X509_NAME_ENTRY_get_data_len(xsne)); -#endif /* APR_CHARSET_EBCDIC */ - break; - } - } - break; - } - } - return result; -} - -static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_UTCTIME *tm) -{ - char *result; - BIO* bio; - int n; - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - return NULL; - ASN1_UTCTIME_print(bio, tm); - n = BIO_pending(bio); - result = apr_pcalloc(p, n+1); - n = BIO_read(bio, result, n); - result[n] = NUL; - BIO_free(bio); - return result; -} - -#define DIGIT2NUM(x) (((x)[0] - '0') * 10 + (x)[1] - '0') - -/* Return a string giving the number of days remaining until 'tm', or - * "0" if this can't be determined. */ -static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_UTCTIME *tm) -{ - apr_time_t then, now = apr_time_now(); - apr_time_exp_t exp = {0}; - long diff; - - /* Fail if the time isn't a valid ASN.1 UTCTIME; RFC3280 mandates - * that the seconds digits are present even though ASN.1 - * doesn't. */ - if (tm->length < 11 || !ASN1_UTCTIME_check(tm)) { - return apr_pstrdup(p, "0"); - } - - exp.tm_year = DIGIT2NUM(tm->data); - exp.tm_mon = DIGIT2NUM(tm->data + 2) - 1; - exp.tm_mday = DIGIT2NUM(tm->data + 4) + 1; - exp.tm_hour = DIGIT2NUM(tm->data + 6); - exp.tm_min = DIGIT2NUM(tm->data + 8); - exp.tm_sec = DIGIT2NUM(tm->data + 10); - - if (exp.tm_year <= 50) exp.tm_year += 100; - - if (apr_time_exp_gmt_get(&then, &exp) != APR_SUCCESS) { - return apr_pstrdup(p, "0"); - } - - diff = (long)((apr_time_sec(then) - apr_time_sec(now)) / (60*60*24)); - - return diff > 0 ? apr_ltoa(p, diff) : apr_pstrdup(p, "0"); -} - -static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs) -{ - char *result; - BIO *bio; - int n; - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - return NULL; - i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs)); - n = BIO_pending(bio); - result = apr_pcalloc(p, n+1); - n = BIO_read(bio, result, n); - result[n] = NUL; - BIO_free(bio); - return result; -} - -static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var) -{ - char *result; - X509 *xs; - int n; - - result = NULL; - - if (strspn(var, "0123456789") == strlen(var)) { - n = atoi(var); - if (n < sk_X509_num(sk)) { - xs = sk_X509_value(sk, n); - result = ssl_var_lookup_ssl_cert_PEM(p, xs); - } - } - - return result; -} - -static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs) -{ - char *result; - BIO *bio; - int n; - - if ((bio = BIO_new(BIO_s_mem())) == NULL) - return NULL; - PEM_write_bio_X509(bio, xs); - n = BIO_pending(bio); - result = apr_pcalloc(p, n+1); - n = BIO_read(bio, result, n); - result[n] = NUL; - BIO_free(bio); - return result; -} - -static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, conn_rec *c) -{ - SSLConnRec *sslconn = myConnConfig(c); - char *result; - long vrc; - const char *verr; - const char *vinfo; - SSL *ssl; - X509 *xs; - - result = NULL; - ssl = sslconn->ssl; - verr = sslconn->verify_error; - vinfo = sslconn->verify_info; - vrc = SSL_get_verify_result(ssl); - xs = SSL_get_peer_certificate(ssl); - - if (vrc == X509_V_OK && verr == NULL && xs == NULL) - /* no client verification done at all */ - result = "NONE"; - else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL) - /* client verification done successful */ - result = "SUCCESS"; - else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS")) - /* client verification done in generous way */ - result = "GENEROUS"; - else - /* client verification failed */ - result = apr_psprintf(p, "FAILED:%s", verr); - - if (xs) - X509_free(xs); - return result; -} - -static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, conn_rec *c, char *var) -{ - SSLConnRec *sslconn = myConnConfig(c); - char *result; - BOOL resdup; - int usekeysize, algkeysize; - SSL *ssl; - - result = NULL; - resdup = TRUE; - - ssl = sslconn->ssl; - ssl_var_lookup_ssl_cipher_bits(ssl, &usekeysize, &algkeysize); - - if (ssl && strEQ(var, "")) { - MODSSL_SSL_CIPHER_CONST SSL_CIPHER *cipher = SSL_get_current_cipher(ssl); - result = (cipher != NULL ? (char *)SSL_CIPHER_get_name(cipher) : NULL); - } - else if (strcEQ(var, "_EXPORT")) - result = (usekeysize < 56 ? "true" : "false"); - else if (strcEQ(var, "_USEKEYSIZE")) { - result = apr_itoa(p, usekeysize); - resdup = FALSE; - } - else if (strcEQ(var, "_ALGKEYSIZE")) { - result = apr_itoa(p, algkeysize); - resdup = FALSE; - } - - if (result != NULL && resdup) - result = apr_pstrdup(p, result); - return result; -} - -static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize) -{ - MODSSL_SSL_CIPHER_CONST SSL_CIPHER *cipher; - - *usekeysize = 0; - *algkeysize = 0; - if (ssl != NULL) - if ((cipher = SSL_get_current_cipher(ssl)) != NULL) - *usekeysize = SSL_CIPHER_get_bits(cipher, algkeysize); - return; -} - -static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var) -{ - if (strEQ(var, "INTERFACE")) { - return apr_pstrdup(p, var_interface); - } - else if (strEQ(var, "LIBRARY_INTERFACE")) { - return apr_pstrdup(p, var_library_interface); - } - else if (strEQ(var, "LIBRARY")) { - return apr_pstrdup(p, var_library); - } - return NULL; -} - -/* Add each RDN in 'xn' to the table 't' where the NID is present in - * 'nids', using key prefix 'pfx'. */ -static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx, - X509_NAME *xn, apr_pool_t *p) -{ - STACK_OF(X509_NAME_ENTRY) *ents = X509_NAME_get_entries(xn); - X509_NAME_ENTRY *xsne; - apr_hash_t *count; - int i, nid; - - /* Hash of (int) NID -> (int *) counter to count each time an RDN - * with the given NID has been seen. */ - count = apr_hash_make(p); - - /* For each RDN... */ - for (i = 0; i < sk_X509_NAME_ENTRY_num(ents); i++) { - const char *tag; - - xsne = sk_X509_NAME_ENTRY_value(ents, i); - - /* Retrieve the nid, and check whether this is one of the nids - * which are to be extracted. */ - nid = OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); - - tag = apr_hash_get(nids, &nid, sizeof nid); - if (tag) { - unsigned char *data = X509_NAME_ENTRY_get_data_ptr(xsne); - const char *key; - int *dup; - char *value; - - /* Check whether a variable with this nid was already - * been used; if so, use the foo_N=bar syntax. */ - dup = apr_hash_get(count, &nid, sizeof nid); - if (dup) { - key = apr_psprintf(p, "%s%s_%d", pfx, tag, ++(*dup)); - } - else { - /* Otherwise, use the plain foo=bar syntax. */ - dup = apr_pcalloc(p, sizeof *dup); - apr_hash_set(count, &nid, sizeof nid, dup); - key = apr_pstrcat(p, pfx, tag, NULL); - } - - /* cast needed from 'unsigned char *' to 'char *' */ - value = apr_pstrmemdup(p, (char *)data, - X509_NAME_ENTRY_get_data_len(xsne)); -#if APR_CHARSET_EBCDIC - ap_xlate_proto_from_ascii(value, X509_NAME_ENTRY_get_data_len(xsne)); -#endif /* APR_CHARSET_EBCDIC */ - apr_table_setn(t, key, value); - } - } -} - -void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p) -{ - apr_hash_t *nids; - unsigned n; - X509 *xs; - - /* Build up a hash table of (int *)NID->(char *)short-name for all - * the tags which are to be extracted: */ - nids = apr_hash_make(p); - for (n = 0; ssl_var_lookup_ssl_cert_dn_rec[n].name; n++) { - if (ssl_var_lookup_ssl_cert_dn_rec[n].extract) { - apr_hash_set(nids, &ssl_var_lookup_ssl_cert_dn_rec[n].nid, - sizeof(ssl_var_lookup_ssl_cert_dn_rec[0].nid), - ssl_var_lookup_ssl_cert_dn_rec[n].name); - } - } - - /* Extract the server cert DNS -- note that the refcount does NOT - * increase: */ - xs = SSL_get_certificate(ssl); - if (xs) { - extract_dn(t, nids, "SSL_SERVER_S_DN_", X509_get_subject_name(xs), p); - extract_dn(t, nids, "SSL_SERVER_I_DN_", X509_get_issuer_name(xs), p); - } - - /* Extract the client cert DNs -- note that the refcount DOES - * increase: */ - xs = SSL_get_peer_certificate(ssl); - if (xs) { - extract_dn(t, nids, "SSL_CLIENT_S_DN_", X509_get_subject_name(xs), p); - extract_dn(t, nids, "SSL_CLIENT_I_DN_", X509_get_issuer_name(xs), p); - X509_free(xs); - } -} - -const char *ssl_ext_lookup(apr_pool_t *p, conn_rec *c, int peer, - const char *oidnum) -{ - SSLConnRec *sslconn = myConnConfig(c); - SSL *ssl; - X509 *xs = NULL; - ASN1_OBJECT *oid; - int count = 0, j; - char *result = NULL; - - if (!sslconn || !sslconn->ssl) { - return NULL; - } - ssl = sslconn->ssl; - - oid = OBJ_txt2obj(oidnum, 1); - if (!oid) { - ERR_clear_error(); - return NULL; - } - - xs = peer ? SSL_get_peer_certificate(ssl) : SSL_get_certificate(ssl); - if (xs == NULL) { - return NULL; - } - - count = X509_get_ext_count(xs); - - for (j = 0; j < count; j++) { - X509_EXTENSION *ext = X509_get_ext(xs, j); - - if (OBJ_cmp(ext->object, oid) == 0) { - BIO *bio = BIO_new(BIO_s_mem()); - - if (X509V3_EXT_print(bio, ext, 0, 0) == 1) { - BUF_MEM *buf; - - BIO_get_mem_ptr(bio, &buf); - result = apr_pstrmemdup(p, buf->data, buf->length); - } - - BIO_vfree(bio); - break; - } - } - - if (peer) { - /* only SSL_get_peer_certificate raises the refcount */ - X509_free(xs); - } - - ERR_clear_error(); - return result; -} - -static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl) -{ - char *result = "NULL"; -#ifdef OPENSSL_VERSION_NUMBER -#if (OPENSSL_VERSION_NUMBER >= 0x00908000) - SSL_SESSION *pSession = SSL_get_session(ssl); - - if (pSession) { - switch (pSession->compress_meth) { - case 0: - /* default "NULL" already set */ - break; - - /* Defined by RFC 3749, deflate is coded by "1" */ - case 1: - result = "DEFLATE"; - break; - - /* IANA assigned compression number for LZS */ - case 0x40: - result = "LZS"; - break; - - default: - result = "UNKNOWN"; - break; - } - } -#endif -#endif - return result; -} - -/* _________________________________________________________________ -** -** SSL Extension to mod_log_config -** _________________________________________________________________ -*/ - -#include "../../modules/loggers/mod_log_config.h" - -static const char *ssl_var_log_handler_c(request_rec *r, char *a); -static const char *ssl_var_log_handler_x(request_rec *r, char *a); - -/* - * register us for the mod_log_config function registering phase - * to establish %{...}c and to be able to expand %{...}x variables. - */ -void ssl_var_log_config_register(apr_pool_t *p) -{ - static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register; - - log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler); - - if (log_pfn_register) { - log_pfn_register(p, "c", ssl_var_log_handler_c, 0); - log_pfn_register(p, "x", ssl_var_log_handler_x, 0); - } - return; -} - -/* - * implement the %{..}c log function - * (we are the only function) - */ -static const char *ssl_var_log_handler_c(request_rec *r, char *a) -{ - SSLConnRec *sslconn = myConnConfig(r->connection); - char *result; - - if (sslconn == NULL || sslconn->ssl == NULL) - return NULL; - result = NULL; - if (strEQ(a, "version")) - result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_PROTOCOL"); - else if (strEQ(a, "cipher")) - result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER"); - else if (strEQ(a, "subjectdn") || strEQ(a, "clientcert")) - result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_S_DN"); - else if (strEQ(a, "issuerdn") || strEQ(a, "cacert")) - result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_I_DN"); - else if (strEQ(a, "errcode")) - result = "-"; - else if (strEQ(a, "errstr")) - result = (char *)sslconn->verify_error; - if (result != NULL && result[0] == NUL) - result = NULL; - return result; -} - -/* - * extend the implementation of the %{..}x log function - * (there can be more functions) - */ -static const char *ssl_var_log_handler_x(request_rec *r, char *a) -{ - char *result; - - result = ssl_var_lookup(r->pool, r->server, r->connection, r, a); - if (result != NULL && result[0] == NUL) - result = NULL; - return result; -} - diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/config.m4.orig httpd-2.2.17-peruser-rc3/server/mpm/config.m4.orig --- httpd-2.2.17-peruser-rc2/server/mpm/config.m4.orig 2005-10-30 15:05:26.000000000 -0200 +++ httpd-2.2.17-peruser-rc3/server/mpm/config.m4.orig 1969-12-31 21:00:00.000000000 -0300 @@ -1,79 +0,0 @@ -AC_MSG_CHECKING(which MPM to use) -AC_ARG_WITH(mpm, -APACHE_HELP_STRING(--with-mpm=MPM,Choose the process model for Apache to use. - MPM={beos|event|worker|prefork|mpmt_os2}),[ - APACHE_MPM=$withval -],[ - if test "x$APACHE_MPM" = "x"; then - APACHE_MPM=prefork - fi -]) -AC_MSG_RESULT($APACHE_MPM) - -apache_cv_mpm=$APACHE_MPM - -ap_mpm_is_threaded () -{ - if test "$apache_cv_mpm" = "worker" -o "$apache_cv_mpm" = "event" ; then - return 0 - else - return 1 - fi -} - -ap_mpm_is_experimental () -{ - if test "$apache_cv_mpm" = "event" ; then - return 0 - else - return 1 - fi -} - -if ap_mpm_is_threaded; then - APR_CHECK_APR_DEFINE(APR_HAS_THREADS) - - 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 - else - case $host in - *-linux-*) - case `uname -r` in - 2.0* ) - dnl Threaded MPM's are not supported on Linux 2.0 - dnl as on 2.0 the linuxthreads library uses SIGUSR1 - dnl and SIGUSR2 internally - echo "Threaded MPM's are not supported on this platform" - AC_MSG_CHECKING(checking for replacement) - AC_MSG_RESULT(prefork selected) - apache_cv_mpm=prefork - ;; - esac - ;; - esac - fi -fi - -APACHE_FAST_OUTPUT(server/mpm/Makefile) - -MPM_NAME=$apache_cv_mpm -if ap_mpm_is_experimental; then - AC_MSG_WARN(You have selected an EXPERIMENTAL MPM. Be warned!) - MPM_SUBDIR_NAME=experimental/$MPM_NAME -else - MPM_SUBDIR_NAME=$MPM_NAME -fi -MPM_DIR=server/mpm/$MPM_SUBDIR_NAME -MPM_LIB=$MPM_DIR/lib${MPM_NAME}.la - -if test ! -f "$abs_srcdir/$MPM_DIR/mpm.h"; then - AC_MSG_ERROR(the selected mpm -- $apache_cv_mpm -- is not supported) -fi - -APACHE_SUBST(MPM_NAME) -APACHE_SUBST(MPM_SUBDIR_NAME) -MODLIST="$MODLIST mpm_${MPM_NAME}" - diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/AUTHORS httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/AUTHORS --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/AUTHORS 2010-12-28 13:10:02.000000000 -0200 +++ httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/AUTHORS 2011-01-13 18:23:42.000000000 -0200 @@ -9,3 +9,4 @@ Steve Amerige Stefan Klingner (Peruser maintainer) Michal Grzedzicki +Marcelo Coelho diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/Makefile.in httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/Makefile.in --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/Makefile.in 2010-12-28 13:10:02.000000000 -0200 +++ httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/Makefile.in 2011-01-26 17:37:35.000000000 -0200 @@ -1,5 +1,13 @@ - LTLIBRARY_NAME = libperuser.la + +### Remove '#' to enable +# PERUSER_MAX_CPU_USAGE = 1 + +.if defined(PERUSER_MAX_CPU_USAGE) +LTLIBRARY_SOURCES = peruser.c cpu_usage.c +LTLIBRARY_LIBADD = -lkvm +.else LTLIBRARY_SOURCES = peruser.c +.endif include $(top_srcdir)/build/ltlib.mk diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/cpu_usage.c httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/cpu_usage.c --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/cpu_usage.c 1969-12-31 21:00:00.000000000 -0300 +++ httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/cpu_usage.c 2011-01-26 17:36:26.000000000 -0200 @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include + +#ifndef _PATH_DEVNULL +# define _PATH_DEVNULL "/dev/null" +#endif /* !_PATH_DEVNULL */ + + +static kvm_t *cpu_usage_kd; +static struct kinfo_proc *cpu_usage_kp; +static int cpu_usage_total = 0; +static int cpu_usage_status = 0; + +static int cpu_usage_init() +{ + if (cpu_usage_status) return 0; + cpu_usage_kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL); + if (cpu_usage_kd == NULL) return -1; + cpu_usage_status = 1; + return 0; +} + +void cpu_usage_finish() +{ + if (cpu_usage_status) { + kvm_close(cpu_usage_kd); + cpu_usage_status = 0; + } +} + +void cpu_usage_refresh() +{ + if (cpu_usage_init() == 0) { + cpu_usage_kp = kvm_getprocs(cpu_usage_kd, KERN_PROC_ALL, 0, &cpu_usage_total); + } +} + +double cpu_usage_pid(pid_t pid) +{ + double ret = 0; + int i; + struct kinfo_proc *pp; + if (cpu_usage_kp && cpu_usage_total > 0) { + ret = 0; + pp = NULL; + for (pp = cpu_usage_kp, i = 0; i < cpu_usage_total; pp++, i++) { + if (pp->ki_pid == pid || pp->ki_pgid == pid) + ret += (100.0 * pp->ki_pctcpu / FSCALE); + } + } + return ret; +} + + diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/cpu_usage.h httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/cpu_usage.h --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/cpu_usage.h 1969-12-31 21:00:00.000000000 -0300 +++ httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/cpu_usage.h 2011-01-26 17:36:29.000000000 -0200 @@ -0,0 +1,9 @@ +#ifndef APACHE_MPM_CPU_USAGE_H +#define APACHE_MPM_CPU_USAGE_H + +void cpu_usage_finish(); +void cpu_usage_refresh(); +double cpu_usage_pid(pid_t pid); + +#endif + diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/mpm.h httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/mpm.h --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/mpm.h 2010-12-28 13:10:02.000000000 -0200 +++ httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/mpm.h 2011-01-26 17:38:31.000000000 -0200 @@ -69,7 +69,6 @@ #define MPM_NAME "Peruser" #define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES -#define AP_MPM_WANT_WAIT_OR_TIMEOUT #define AP_MPM_WANT_PROCESS_CHILD_STATUS #define AP_MPM_WANT_SET_PIDFILE #define AP_MPM_WANT_SET_SCOREBOARD @@ -96,7 +95,7 @@ #define SERVER_DYING 1 #define SERVER_ALIVE 2 -static const char* child_clone(); +static void child_clone(int child_num); #endif /* APACHE_MPM_PERUSER_H */ diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/mpm_default.h httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/mpm_default.h --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/mpm_default.h 2010-12-28 13:10:02.000000000 -0200 +++ httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/mpm_default.h 2011-01-26 17:38:37.000000000 -0200 @@ -62,7 +62,7 @@ /* Number of processors to spawn off for each ServerEnvironment by default */ #ifndef DEFAULT_START_PROCESSORS -#define DEFAULT_START_PROCESSORS 0 +#define DEFAULT_START_PROCESSORS 1 #endif /* Minimum number of running processors per ServerEnvironment */ @@ -159,4 +159,20 @@ #define DEFAULT_PROCESSOR_WAIT_STEPS 10 #endif +/* + * Max %CPU for each processor (0 to disable) + */ + +#ifndef DEFAULT_MAX_CPU_USAGE +#define DEFAULT_MAX_CPU_USAGE 0 +#endif + +/* + * Header buffer used between pass_request() and receive_connection() + */ + +#ifndef PERUSER_MAX_HEADER_SIZE +#define PERUSER_MAX_HEADER_SIZE 20000 +#endif + #endif /* AP_MPM_DEFAULT_H */ diff -Nur httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/peruser.c httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/peruser.c --- httpd-2.2.17-peruser-rc2/server/mpm/experimental/peruser/peruser.c 2010-12-28 13:10:02.000000000 -0200 +++ httpd-2.2.17-peruser-rc3/server/mpm/experimental/peruser/peruser.c 2011-01-26 17:43:23.000000000 -0200 @@ -59,6 +59,8 @@ /* Peruser version 0.4.0 */ /* #define MPM_PERUSER_DEBUG */ +/* #define PERUSER_MAX_CPU_USAGE */ +/* #define PERUSER_PAM_SESSION */ #include "apr.h" #include "apr_hash.h" @@ -120,6 +122,10 @@ #error "Peruser MPM requres shared memory support." #endif +#ifdef PERUSER_PAM_SESSION +#include +#endif /* PERUSER_PAM_SESSION */ + /* should be APR-ized */ #include #include @@ -130,6 +136,10 @@ #include #include +#ifdef PERUSER_MAX_CPU_USAGE +#include "cpu_usage.h" +#endif + #ifdef MPM_PERUSER_DEBUG # define _DBG(text,par...) \ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \ @@ -185,6 +195,7 @@ #define HARD_THREAD_LIMIT 1 #endif +#define CHILD_TYPE_RESERVED -1 #define CHILD_TYPE_UNKNOWN 0 #define CHILD_TYPE_MULTIPLEXER 1 #define CHILD_TYPE_PROCESSOR 2 @@ -204,10 +215,14 @@ int ap_threads_per_child = 0; /* Worker threads per child */ static apr_proc_mutex_t *accept_mutex; +static int ap_start_processors = DEFAULT_START_PROCESSORS; static int ap_min_processors = DEFAULT_MIN_PROCESSORS; static int ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS; static int ap_max_free_processors = DEFAULT_MAX_FREE_PROCESSORS; static int ap_max_processors = DEFAULT_MAX_PROCESSORS; +#ifdef PERUSER_MAX_CPU_USAGE +static int ap_max_cpu_usage = DEFAULT_MAX_CPU_USAGE; +#endif static int ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS; static int ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS; static int ap_daemons_limit = 0; /* MaxClients */ @@ -227,6 +242,7 @@ typedef struct { + int id; int processor_id; const char *name; /* Server environment's unique string identifier */ @@ -239,10 +255,14 @@ const char *cgroup; /* cgroup directory, can be null */ /* resource settings */ + int start_processors; int min_processors; int min_free_processors; int max_free_processors; int max_processors; +#ifdef PERUSER_MAX_CPU_USAGE + int max_cpu_usage; +#endif short availability; /* sockets */ @@ -258,6 +278,24 @@ unsigned long stats_requests; /* requests handled */ unsigned long stats_connections; /* connections handled */ unsigned long stats_dropped; /* connections dropped because multiplexer was not able to pass */ + + /* counters */ + int total_processors; + int idle_processors; + int active_processors; + int total_processes; + + /* tmp counters */ + int tmp_total_processors; + int tmp_idle_processors; + int tmp_active_processors; + int tmp_total_processes; + +#ifdef PERUSER_MAX_CPU_USAGE + /* cpu usage */ + double tmp_total_cpu_usage; + double total_cpu_usage; +#endif } server_env_t; typedef struct @@ -285,11 +323,17 @@ /* stack context saved state */ jmp_buf jmpbuffer; + +#ifdef PERUSER_MAX_CPU_USAGE + int cpu_stopped; + double cpu_usage; +#endif } child_info_t; typedef struct { apr_size_t num; + int new; } child_info_control; typedef struct @@ -426,6 +470,8 @@ return "PROCESSOR"; case CHILD_TYPE_WORKER: return "WORKER"; + case CHILD_TYPE_RESERVED: + return "RESERVED"; } return "UNKNOWN"; @@ -542,6 +588,13 @@ retval = close(CHILD_INFO_TABLE[my_child_num].senv->output); _DBG("close(CHILD_INFO_TABLE[%d].senv->output) = %d", my_child_num, retval); + +#ifdef PERUSER_MAX_CPU_USAGE + if (CHILD_INFO_TABLE[my_child_num].cpu_stopped) { + CHILD_INFO_TABLE[my_child_num].cpu_stopped = 0; + } +#endif + } if (pchild) { @@ -552,6 +605,43 @@ exit(code); } +/* 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_exit_why_e *status, int *exitcode, 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; + ap_run_monitor(p); + } + + rv = apr_proc_wait_all_procs(ret, exitcode, 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(exitcode, status)) > 0) { + return; + } +#endif + + ret->pid = -1; + return; +} + static void accept_mutex_on(void) { apr_status_t rv = apr_proc_mutex_lock(accept_mutex); @@ -655,13 +745,20 @@ int n, pid; for (n = 0; n < NUM_CHILDS; ++n) { - if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD && - kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) { - ap_update_child_status_from_indexes(n, 0, SERVER_DEAD, NULL); - /* just mark it as having a successful exit status */ - *status = APR_PROC_EXIT; - *exitcode = 0; - return(pid); + if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD) { + if (unixd_killpg((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) { + ap_update_child_status_from_indexes(n, 0, SERVER_DEAD, NULL); + /* just mark it as having a successful exit status */ + *status = APR_PROC_EXIT; + *exitcode = 0; + return(pid); + } +#ifdef PERUSER_MAX_CPU_USAGE + if (CHILD_INFO_TABLE[n].cpu_stopped) { + unixd_killpg(ap_scoreboard_image->parent[n].pid, SIGCONT); + CHILD_INFO_TABLE[n].cpu_stopped = 0; + } +#endif } } return 0; @@ -679,7 +776,14 @@ "seg fault or similar nasty error detected " "in the parent process"); } - kill(getpid(), sig); + unixd_killpg(getpid(), sig); +#ifdef PERUSER_MAX_CPU_USAGE + if (CHILD_INFO_TABLE[my_child_num].cpu_stopped) { + unixd_killpg(getpid(), SIGCONT); + CHILD_INFO_TABLE[my_child_num].cpu_stopped = 0; + } +#endif + /* At this point we've got sig blocked, because we're still inside * the signal handler. When we leave the signal handler it will * be unblocked, and we'll take the signal... and coredump or whatever @@ -897,78 +1001,116 @@ return 0; } -static int total_processors(int child_num) +static int active_env_processors(int env_num) { - int i, total; - - for (i = 0, total = 0; i < NUM_CHILDS; ++i) { - if (CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv) - total++; + if (env_num >= NUM_SENV) { + return -1; } - - return total; + return SENV[env_num].active_processors; } -static int active_processors(int child_num) +static int update_single_processor_counters(int child_num) { - int i, total; - for (i = 0, total = 0; i < NUM_CHILDS; ++i) { - if (CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv - && CHILD_INFO_TABLE[i].pid > 0) { - total++; + if (child_num >= NUM_CHILDS) return -1; + if (!CHILD_INFO_TABLE[child_num].senv) return -1; + + int i; + int tmp_total_processors = 0; + int tmp_idle_processors = 0; + int tmp_active_processors = 0; + int tmp_total_processes = 0; +#ifdef PERUSER_MAX_CPU_USAGE + double tmp_total_cpu_usage = 0; +#endif + + /* counting processors */ + for (i = 0; i < NUM_CHILDS; ++i) { + if (CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv) { +#ifdef PERUSER_MAX_CPU_USAGE + tmp_total_cpu_usage += CHILD_INFO_TABLE[i].cpu_usage; +#endif + if (CHILD_INFO_TABLE[i].status != CHILD_STATUS_STANDBY) + tmp_total_processes++; + tmp_total_processors++; + if (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY || CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING) + tmp_idle_processors++; + if (CHILD_INFO_TABLE[i].pid > 0) + tmp_active_processors++; } } - return total; + /* updating counters */ + CHILD_INFO_TABLE[child_num].senv->total_processors = tmp_total_processors; + CHILD_INFO_TABLE[child_num].senv->idle_processors = tmp_idle_processors; + CHILD_INFO_TABLE[child_num].senv->active_processors = tmp_active_processors; + CHILD_INFO_TABLE[child_num].senv->total_processes = tmp_total_processes; +#ifdef PERUSER_MAX_CPU_USAGE + CHILD_INFO_TABLE[child_num].senv->total_cpu_usage = tmp_total_cpu_usage; +#endif + + return 0; } -static int active_env_processors(int env_num) +static void update_all_counters() { - int i, total; + int i; - if (env_num >= NUM_SENV) { - return -1; + if (!NUM_SENV) return; + + /* resetting counters */ + for (i = 0; i < NUM_SENV; ++i) { + SENV[i].tmp_total_processors = 0; + SENV[i].tmp_idle_processors = 0; + SENV[i].tmp_active_processors = 0; + SENV[i].tmp_total_processes = 0; +#ifdef PERUSER_MAX_CPU_USAGE + SENV[i].tmp_total_cpu_usage = 0; +#endif } - for (i = 0, total = 0; i < NUM_CHILDS; ++i) { - if (CHILD_INFO_TABLE[i].senv == &SENV[env_num] - && CHILD_INFO_TABLE[i].pid > 0) { - total++; + /* counting processors */ + for (i = 0; i < NUM_CHILDS; ++i) { + if (CHILD_INFO_TABLE[i].senv != NULL) { +#ifdef PERUSER_MAX_CPU_USAGE + CHILD_INFO_TABLE[i].senv->tmp_total_cpu_usage += CHILD_INFO_TABLE[i].cpu_usage; +#endif + CHILD_INFO_TABLE[i].senv->tmp_total_processors++; + if (CHILD_INFO_TABLE[i].status != CHILD_STATUS_STANDBY) + CHILD_INFO_TABLE[i].senv->tmp_total_processes++; + if (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY || CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING) + CHILD_INFO_TABLE[i].senv->tmp_idle_processors++; + if (CHILD_INFO_TABLE[i].pid > 0) + CHILD_INFO_TABLE[i].senv->tmp_active_processors++; } } - return total; -} - -static int idle_processors(int child_num) -{ - int i, total; - - for (i = 0, total = 0; i < NUM_CHILDS; ++i) { - if (CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv - && (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY - || CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING)) { - total++; - } + /* updating counters */ + for (i = 0; i < NUM_SENV; ++i) { + SENV[i].total_processors = SENV[i].tmp_total_processors; + SENV[i].idle_processors = SENV[i].tmp_idle_processors; + SENV[i].active_processors = SENV[i].tmp_active_processors; + SENV[i].total_processes = SENV[i].tmp_total_processes; +#ifdef PERUSER_MAX_CPU_USAGE + SENV[i].total_cpu_usage = SENV[i].tmp_total_cpu_usage; +#endif } - return total; + return; } -static int idle_env_processors(int env_num) -{ - int i, total; +static void activate_child(child_info_t *child) { + if (child->status == CHILD_STATUS_STANDBY) { + child->status = CHILD_STATUS_STARTING; - for (i = 0, total = 0; i < NUM_CHILDS; ++i) { - if (CHILD_INFO_TABLE[i].senv == &SENV[env_num] - && (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY - || CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING)) { - total++; + if (child->pid == 0) { + _DBG("Activating child #%d", child->id); + child_info_image->control->new = 1; + child->senv->total_processors++; + child->senv->idle_processors++; + child->senv->total_processes++; } } - - return total; } static int wait_for_workers(child_info_t *processor) @@ -977,9 +1119,26 @@ wait_step_size = 100 / processor_wait_steps; + /* Protection for graceful restart under high load */ + if (!processor->senv) return -1; + if (update_single_processor_counters(processor->id) == -1) return -1; + + /* If all processors are busy, we will clone a child */ + if ((processor->senv->idle_processors == 0 + && processor->senv->total_processors > 0 + && processor->senv->total_processors < processor->senv->max_processors + && processor->senv->total_processors <= processor->senv->total_processes) + || (processor->senv->idle_processors > processor->senv->total_processors)) { + _DBG("MULTIPLEXER CLONING CHILD %d", processor->id); + child_clone(processor->id); + child_info_image->control->new = 1; + apr_sleep(apr_time_from_sec(1)); + if (update_single_processor_counters(processor->id) == -1) return -1; + } + /* Check if the processor is available */ - if (total_processors(processor->id) == processor->senv->max_processors - && idle_processors(processor->id) == 0 && processor_wait_timeout > 0) { + if (processor->senv->total_processors >= processor->senv->max_processors + && processor->senv->idle_processors == 0 && processor_wait_timeout > 0) { /* The processor is currently busy, try to wait (a little) */ _DBG("processor seems to be busy, trying to wait for it"); @@ -1000,15 +1159,17 @@ } /* We sleep a little (depending how available the processor is) */ - wait_time = (processor_wait_timeout / processor_wait_steps) * 1000000; + wait_time = (float) processor_wait_timeout / processor_wait_steps * 1000000; for (i = 0; i <= processor->senv->availability; i += wait_step_size) { - usleep(wait_time); + + apr_sleep(wait_time); /* Check if the processor is ready */ - if (total_processors(processor->id) + if (update_single_processor_counters(processor->id) == -1) return -1; + if (processor->senv->total_processors < processor->senv->max_processors - || idle_processors(processor->id) > 0) + || processor->senv->idle_processors > 0) { /* The processor has freed - lets use it */ _DBG("processor freed before wait time expired"); @@ -1044,8 +1205,7 @@ /* Smoothly increment the availability back to 100 */ if (processor->senv->availability >= 100 - wait_step_size) { processor->senv->availability = 100; - } - else { + } else { processor->senv->availability += wait_step_size; } } @@ -1120,10 +1280,7 @@ msg.msg_control = cmsg; msg.msg_controllen = cmsg->cmsg_len; - if (processor->status == CHILD_STATUS_STANDBY) { - _DBG("Activating child #%d", processor->id); - processor->status = CHILD_STATUS_STARTING; - } + activate_child(processor); _DBG("Writing message to %d, passing sock_fd: %d", processor->senv->output, sock_fd); @@ -1192,23 +1349,21 @@ _DBG("Forwarding without further inspection, processor %d", processor->id); - if (processor->status == CHILD_STATUS_STANDBY) { - _DBG("Activating child #%d", processor->id); - processor->status = CHILD_STATUS_STARTING; - } + activate_child(processor); _DBG("Creating new pool",0); apr_pool_create(&ptrans, pool); _DBG("Passing request.",0); if (pass_socket(sock, processor, ptrans) == -1) { - if (processor->senv->error_pass == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, - "Could not pass request to proper child, " - "request will not be honoured."); + if (processor->senv) { + if (processor->senv->error_pass == 0) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, + "Could not pass request to proper child, " + "request will not be honoured."); + } + processor->senv->error_pass = 1; } - - processor->senv->error_pass = 1; } else { processor->senv->error_pass = 0; @@ -1273,6 +1428,7 @@ ap_process_connection(current_conn, sock); ap_lingering_close(current_conn); } + } static int peruser_process_connection(conn_rec *conn) @@ -1425,6 +1581,11 @@ header_len = strlen(h.headers); + if (header_len > PERUSER_MAX_HEADER_SIZE) { + _DBG("Header too big (header_len=%d)", header_len); + return -2; + } + iov[0].iov_base = &header_len; iov[0].iov_len = sizeof(header_len); iov[1].iov_base = &body_len; @@ -1451,10 +1612,7 @@ msg.msg_control = cmsg; msg.msg_controllen = cmsg->cmsg_len; - if (child->status == CHILD_STATUS_STANDBY) { - _DBG("Activating child #%d", child->id); - child->status = CHILD_STATUS_STARTING; - } + activate_child(child); _DBG("Writing message to %d, passing sock_fd: %d", child->senv->output, sock_fd); @@ -1484,8 +1642,8 @@ { struct msghdr msg; struct cmsghdr *cmsg; - char buff[HUGE_STRING_LEN] = ""; - char headers[HUGE_STRING_LEN] = ""; + char buff[PERUSER_MAX_HEADER_SIZE] = ""; + char headers[PERUSER_MAX_HEADER_SIZE] = ""; char *body = ""; apr_size_t header_len, body_len; struct iovec iov[4]; @@ -1508,7 +1666,7 @@ iov[2].iov_base = &remote_addr; iov[2].iov_len = sizeof(remote_addr); iov[3].iov_base = (char*) &buff; - iov[3].iov_len = HUGE_STRING_LEN; + iov[3].iov_len = PERUSER_MAX_HEADER_SIZE; cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(trans_sock_fd)); cmsg->cmsg_len = CMSG_LEN(sizeof(trans_sock_fd)); @@ -1575,7 +1733,7 @@ if (body_len) { body = (char*) &buff[header_len + 1]; - _DBG("body_len=%d body=\"%s\"", body_len, body); + _DBG("body_len=%d", strlen(body)); bucket = apr_bucket_heap_create(body, body_len, NULL, alloc); APR_BRIGADE_INSERT_HEAD(bb, bucket); @@ -1726,6 +1884,54 @@ peruser_setup_cgroup(childnum, senv, pool); } +#ifdef PERUSER_PAM_SESSION + /* + * Use PAM session support. Initial goal was to use the pam_limits module. + */ +#ifndef PAM_SERVICE_NAME +#define PAM_SERVICE_NAME "peruser" +#endif /* PAM_SERVICE_NAME */ + + if(senv->uid > 1000) { + + struct passwd *pw; + pw = getpwuid (senv->uid); + + /* + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + "user: %s", pw->pw_name); + */ + + #define PAM_CALL(call, name, err_code, do_end) \ + do \ + { \ + rc = (call); \ + if (rc != PAM_SUCCESS) \ + { \ + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \ + "error: %s(): [%d] %s", (name), rc,pam_strerror(pamh, rc)); \ + (do_end) && pam_end(pamh, rc); \ + exit(err_code); \ + } \ + } while (0) + + { + int rc; + pam_handle_t *pamh = NULL; + struct pam_conv pamc = { NULL, NULL }; + + PAM_CALL(pam_start(PAM_SERVICE_NAME, pw->pw_name, &pamc, &pamh), "pam_start", 241, 0); + PAM_CALL(pam_open_session(pamh, 0), "pam_open_session", 242, 1); + PAM_CALL(pam_close_session(pamh, 0), "pam_close_session", 243, 1); + PAM_CALL(pam_end(pamh, 0), "pam_end", 244, 0); + } + +#undef PAM_CALL + } + +#undef PAM_SERVICE_NAME +#endif /* PERUSER_PAM_SESSION */ + if (senv->uid == -1 && senv->gid == -1) { return unixd_setup_child(); } @@ -1877,6 +2083,7 @@ my_child_num = child_num_arg; ap_my_pid = getpid(); + setpgid(ap_my_pid, ap_my_pid); requests_this_child = 0; _DBG("sock_fd_in=%d sock_fd_out=%d", @@ -1931,7 +2138,7 @@ _DBG("unspecified child type for %d sleeping a while ...", my_child_num); - sleep(5); + apr_sleep(apr_time_from_sec(5)); return; } @@ -1981,6 +2188,9 @@ && ap_max_requests_per_child > 0 && requests_this_child++ >= ap_max_requests_per_child) { _DBG("max requests reached, dying now", 0); +#ifdef PERUSER_MAX_CPU_USAGE + CHILD_INFO_TABLE[my_child_num].cpu_stopped = 0; +#endif clean_child_exit(0); } @@ -2073,6 +2283,7 @@ if (CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_READY) { CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_ACTIVE; + CHILD_INFO_TABLE[my_child_num].senv->idle_processors--; _DBG("Child %d (%s) is now active", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type)); } @@ -2083,23 +2294,25 @@ _DBG("CHECKING IF WE SHOULD CLONE A CHILD..."); + update_single_processor_counters(my_child_num); + _DBG("total_processors = %d, max_processors = %d", - total_processors(my_child_num), + CHILD_INFO_TABLE[my_child_num].senv->total_processors, CHILD_INFO_TABLE[my_child_num].senv->max_processors); _DBG("idle_processors = %d, min_free_processors = %d", - idle_processors(my_child_num), + CHILD_INFO_TABLE[my_child_num].senv->idle_processors, CHILD_INFO_TABLE[my_child_num].senv->min_free_processors); - if (total_processors(my_child_num) + if (CHILD_INFO_TABLE[my_child_num].senv->total_processors < CHILD_INFO_TABLE[my_child_num].senv->max_processors - && (idle_processors(my_child_num) + && (CHILD_INFO_TABLE[my_child_num].senv->idle_processors <= CHILD_INFO_TABLE[my_child_num].senv->min_free_processors - || total_processors(my_child_num) + || CHILD_INFO_TABLE[my_child_num].senv->total_processors < CHILD_INFO_TABLE[my_child_num].senv->min_processors)) { _DBG("CLONING CHILD"); - child_clone(); + child_clone(-1); // -1 => this child } } @@ -2144,6 +2357,8 @@ } } + // Call apr_pool_clear() - Apache prefork bug (PR 43857) + apr_pool_clear(ptrans); _DBG("clean_child_exit(0)"); clean_child_exit(0); } @@ -2221,19 +2436,28 @@ SENV[NUM_SENV].input = socks[0]; SENV[NUM_SENV].output = socks[1]; + _DBG("New senv id %d", NUM_SENV); + SENV[NUM_SENV].id = NUM_SENV; + senv = &SENV[NUM_SENV]; return &SENV[server_env_image->control->num++]; } -static const char* child_clone() +static void child_clone(int child_num) { - int i; + int i, child_to_clone; child_info_t *this; child_info_t *new; + if (child_num == -1) + child_to_clone = my_child_num; + else + child_to_clone = child_num; + for (i = 0; i < NUM_CHILDS; i++) { if (CHILD_INFO_TABLE[i].pid == 0 && CHILD_INFO_TABLE[i].type == CHILD_TYPE_UNKNOWN) { + CHILD_INFO_TABLE[i].type = CHILD_TYPE_RESERVED; break; } } @@ -2241,12 +2465,12 @@ if (i == NUM_CHILDS && NUM_CHILDS >= server_limit) { _DBG("Trying to use more child ID's than ServerLimit. " "Increase ServerLimit in your config file."); - return NULL; + return; } - _DBG("cloning child #%d from #%d", i, my_child_num); + _DBG("cloning child #%d from #%d", i, child_to_clone); - this = &CHILD_INFO_TABLE[my_child_num]; + this = &CHILD_INFO_TABLE[child_to_clone]; new = &CHILD_INFO_TABLE[i]; new->senv = this->senv; @@ -2260,12 +2484,16 @@ new->sock_fd = this->sock_fd; new->status = CHILD_STATUS_STARTING; + if (child_num == -1) child_info_image->control->new = 1; + new->senv->total_processors++; + new->senv->idle_processors++; + new->senv->total_processes++; if (i == NUM_CHILDS) { child_info_image->control->num++; } - return NULL; + return; } static const char* child_add(int type, int status, apr_pool_t *pool, @@ -2273,9 +2501,16 @@ { int i; + if (senv->chroot && !ap_is_directory(pool, senv->chroot)) { + return apr_psprintf(pool, + "Error: chroot directory [%s] does not exist", + senv->chroot); + } + for (i = 0; i < NUM_CHILDS; i++) { if (CHILD_INFO_TABLE[i].pid == 0 && CHILD_INFO_TABLE[i].type == CHILD_TYPE_UNKNOWN) { + CHILD_INFO_TABLE[i].type = CHILD_TYPE_RESERVED; break; } } @@ -2287,15 +2522,11 @@ "Increase ServerLimit in your config file."; } - if (senv->chroot && !ap_is_directory(pool, senv->chroot)) { - return apr_psprintf(pool, - "Error: chroot directory [%s] does not exist", - senv->chroot); - } - CHILD_INFO_TABLE[i].senv = senv_add(senv); if (CHILD_INFO_TABLE[i].senv == NULL) { + // Changing back to UNKNOWN type + CHILD_INFO_TABLE[i].type = CHILD_TYPE_UNKNOWN; return "Trying to use more server environments than ServerLimit. " "Increase ServerLimit in your config file."; } @@ -2330,7 +2561,7 @@ { int pid; - _DBG("function entered", 0); + _DBG("function entered slot=%d", slot); dump_server_env_image(); switch (CHILD_INFO_TABLE[slot].type) { @@ -2383,7 +2614,7 @@ /* 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); + apr_sleep(apr_time_from_sec(10)); return -1; } @@ -2416,6 +2647,10 @@ ap_scoreboard_image->parent[slot].pid = pid; CHILD_INFO_TABLE[slot].pid = pid; + CHILD_INFO_TABLE[slot].senv->active_processors++; +#ifdef PERUSER_MAX_CPU_USAGE + CHILD_INFO_TABLE[slot].cpu_stopped = 0; +#endif return 0; } @@ -2430,26 +2665,25 @@ #ifndef MAX_SPAWN_RATE #define MAX_SPAWN_RATE (32) #endif -static int total_processes(int child_num) -{ - int i, total; - - for (i = 0, total = 0; i < NUM_CHILDS; ++i) { - if (CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv - && CHILD_INFO_TABLE[i].status != CHILD_STATUS_STANDBY) { - total++; - } - } - - return total; -} -static int determine_child_fate(int childnum, child_info_t *child, +static inline int determine_child_fate(int childnum, child_info_t *child, worker_score *child_sb, apr_time_t now) { time_t idle_time = apr_time_sec(now - child_sb->last_used); - if (total_processes(childnum) <= child->senv->min_processors) { + /* All active processors must be killed after ExpireTimeout, regardless + MinProcessors, or infinite loop processors will never end */ + if ((child->type == CHILD_TYPE_PROCESSOR || + child->type == CHILD_TYPE_WORKER) + && child->status == CHILD_STATUS_ACTIVE + && expire_timeout > 0 && idle_time > expire_timeout) { + /* Child has not handled a request for some time now, stop it */ + _DBG("First expire timeout reached for child #%d", childnum); + return 1; + } + + if (child->senv->min_processors > 0 && + child->senv->total_processes <= child->senv->min_processors) { /* We will not kill a child, if the senv needs live workers */ return 0; } @@ -2457,18 +2691,37 @@ if (child->type == CHILD_TYPE_PROCESSOR || child->type == CHILD_TYPE_WORKER) { - if (idle_processors(childnum) <= child->senv->min_free_processors || - child->senv->min_free_processors == 0) { + /* + If MinProcessors AND MinSpareProcessors are set to a positive + value, server will keep idle processors, regardless IdleTimeout + configuration, but if MinProcessors is 0, server will keep idle + processors UNTIL IdleTimeout. + */ + if (child->senv->min_processors > 0 && + child->senv->min_free_processors > 0 && + child->senv->idle_processors <= child->senv->min_free_processors) { /* We will not kill a child, if the senv needs idle workers */ return 0; } + /* TODO: Maybe this step will be removed from here */ if (expire_timeout > 0 && idle_time > expire_timeout) { /* Child has not handled a request for some time now, stop it */ - _DBG("Expire timeout reached for child #%d", childnum); + _DBG("Second expire timeout reached for child #%d", childnum); return 1; } + /* Never kill the last idle child if all others are busy */ + if (child->senv->total_processes > 0 + && child->senv->active_processors >= child->senv->total_processors + && child->senv->idle_processors == 1 + && child_sb->status == SERVER_READY) { + /* We will not kill this child, this is the last idle child, + all others are busy */ + _DBG("Child %d not killed, all others are busy", childnum); + return 0; + } + if (idle_timeout > 0 && child_sb->status == SERVER_READY && idle_time > idle_timeout) { /* Child has been idle for too long, stop it */ @@ -2476,8 +2729,11 @@ return 1; } - if (child->senv->max_free_processors > 0 - && idle_processors(childnum) >= child->senv->max_free_processors) { + /* Dont kill a recent created child */ + if (idle_time > 0 && child->type == CHILD_TYPE_WORKER + /* && child->status == CHILD_STATUS_READY */ + && child->senv->max_free_processors > 0 + && child->senv->idle_processors >= child->senv->max_free_processors) { /* Too many spare workers available */ _DBG("Too many spare workers for processor %s, stopping child #%d", child->senv->name, childnum); @@ -2495,17 +2751,57 @@ return 0; } +static void inline create_new_childs() +{ + int i; + + for (i = 0; i < NUM_CHILDS; ++i) { + if (restart_pending) { + _DBG("Exiting... restart_pending = %d", restart_pending); + break; + } + if (CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING + && CHILD_INFO_TABLE[i].pid == 0) + make_child(ap_server_conf, i); + } +} + +static void inline check_for_new_childs() +{ + int i; + + for (i = 0; i < 50; ++i) { + if (child_info_image->control->new) { + create_new_childs(); + child_info_image->control->new = 0; + } + apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL / 50); + } +} + static void perform_idle_server_maintenance(apr_pool_t *p) { - int i, stop_child; + int i, stop_child, retval; time_t idle_time; child_info_t *child; worker_score *child_sb; apr_time_t now; - now = apr_time_now(); + time_t up_time = apr_time_sec(now - ap_scoreboard_image->global->restart_time); + + _DBG("function entered"); + +#ifdef PERUSER_MAX_CPU_USAGE + cpu_usage_refresh(); +#endif + update_all_counters(); for (i = 0; i < NUM_CHILDS; ++i) { + if (restart_pending) { + _DBG("Exiting... restart_pending = %d", restart_pending); + break; + } + child = &CHILD_INFO_TABLE[i]; child_sb = &ap_scoreboard_image->servers[i][0]; @@ -2514,6 +2810,34 @@ } if (child->pid == 0) { + + /* If some child unexpectedly dies, we should free this child */ + if (child->type > CHILD_TYPE_UNKNOWN && + (child->status == CHILD_STATUS_ACTIVE || child->status == CHILD_STATUS_READY) + && child_sb->status == SERVER_DEAD) { + _DBG("Something is wrong with child #%d", child->id); + if (child->type != CHILD_TYPE_MULTIPLEXER && child->senv) { + /* + retval = close(child->senv->input); + _DBG("close(CHILD_INFO_TABLE[%d].senv->input) = %d", + i, retval); + retval = close(child->senv->output); + _DBG("close(CHILD_INFO_TABLE[%d].senv->output) = %d", + i, retval); + */ + } + if (child->type != CHILD_TYPE_PROCESSOR) { + /* completely free up this slot */ + child->senv = (server_env_t*) NULL; + child->type = CHILD_TYPE_UNKNOWN; + child->sock_fd = -3; /* -1 and -2 are taken */ + } +#ifdef PERUSER_MAX_CPU_USAGE + child->cpu_stopped = 0; +#endif + child->status = CHILD_STATUS_STANDBY; + } + if (child->status == CHILD_STATUS_STARTING) { make_child(ap_server_conf, i); } @@ -2525,15 +2849,74 @@ continue; } +#ifdef PERUSER_MAX_CPU_USAGE + /* Wait 20 seconds to start CPU control */ + if (up_time >= 20 && child->senv->max_cpu_usage > 0) { + child->cpu_usage = cpu_usage_pid(ap_scoreboard_image->parent[i].pid); + if (child->type != CHILD_TYPE_MULTIPLEXER) { + if (child->cpu_stopped > 0) { + if (child->cpu_usage < child->senv->max_cpu_usage) { + child->cpu_stopped--; + if (child->cpu_stopped <= 0) { + unixd_killpg(ap_scoreboard_image->parent[i].pid, SIGCONT); + child->cpu_stopped = 0; + continue; + } + } else { + if (child->cpu_stopped < 10) child->cpu_stopped++; + } + } else { + if (child->cpu_usage >= child->senv->max_cpu_usage) { + unixd_killpg(ap_scoreboard_image->parent[i].pid, SIGSTOP); + child->cpu_stopped = 1; + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, + "Processor %s stopped (pid = %d, cpu_usage = %.1f, max_cpu_usage = %d)", + child->senv->name, ap_scoreboard_image->parent[i].pid, + child->cpu_usage, child->senv->max_cpu_usage); + continue; + } + } + } + } +#endif + if (determine_child_fate(i, child, child_sb, now) == 1) { + + /* updating counters */ + if (child->status == CHILD_STATUS_READY) + child->senv->idle_processors--; + if (child->pid > 0) + child->senv->active_processors--; + if (child->status != CHILD_STATUS_STANDBY) + child->senv->total_processes--; + child->senv->total_processors--; + child->status = CHILD_STATUS_STANDBY; - if (kill(ap_scoreboard_image->parent[i].pid, SIGTERM) == -1) { +#ifdef PERUSER_MAX_CPU_USAGE + if (child->cpu_stopped) { + unixd_killpg(ap_scoreboard_image->parent[i].pid, SIGCONT); + child->cpu_stopped = 0; + } +#endif + + if (unixd_killpg(ap_scoreboard_image->parent[i].pid, SIGTERM) == -1) { ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "kill SIGTERM"); } + + /* If all processors are busy, we will clone a child */ + if (child->senv->idle_processors == 0 + && child->senv->total_processors > 0 + && child->senv->total_processors < child->senv->max_processors + && child->senv->total_processors <= child->senv->total_processes) { + _DBG("CLONING CHILD %d", child->id); + child_clone(child->id); + } + } } + } /***************************************************************** @@ -2710,7 +3093,7 @@ } else if (child_slot < ap_daemons_limit && CHILD_INFO_TABLE[child_slot].type - != CHILD_TYPE_UNKNOWN) + > CHILD_TYPE_UNKNOWN) { /* we're still doing a 1-for-1 replacement of dead * children with new children @@ -2726,7 +3109,7 @@ /* handled */ #endif } - else if (is_graceful) { + else { /* Great, we've probably just lost a slot in the * scoreboard. Somehow we don't know about this * child. @@ -2745,21 +3128,43 @@ continue; } + /* Create new processors while waiting */ + check_for_new_childs(); perform_idle_server_maintenance(pconf); #ifdef TPF shutdown_pending = os_check_server(tpf_server_name); ap_check_signals(); - sleep(1); + apr_sleep(apr_time_from_sec(1)); #endif /*TPF */ } +#ifdef PERUSER_MAX_CPU_USAGE + cpu_usage_finish(); +#endif + mpm_state = AP_MPMQ_STOPPING; if (shutdown_pending) { /* Time to gracefully shut down: * Kill child processes, tell them to call child_exit, etc... */ + + int n = 0; + for (n = 0; n < NUM_CHILDS; ++n) { + if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD && + ap_scoreboard_image->parent[n].pid) { +#ifdef PERUSER_MAX_CPU_USAGE + if (CHILD_INFO_TABLE[n].cpu_stopped) { + unixd_killpg(ap_scoreboard_image->parent[n].pid, SIGCONT); + CHILD_INFO_TABLE[n].cpu_stopped = 0; + } + CHILD_INFO_TABLE[n].cpu_usage = 0; +#endif + unixd_killpg(ap_scoreboard_image->parent[n].pid, SIGTERM); + } + } + if (unixd_killpg(getpgrp(), SIGTERM) < 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM"); @@ -2835,6 +3240,22 @@ } } else { + + int n = 0; + for (n = 0; n < NUM_CHILDS; ++n) { + if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD && + ap_scoreboard_image->parent[n].pid) { +#ifdef PERUSER_MAX_CPU_USAGE + if (CHILD_INFO_TABLE[n].cpu_stopped) { + unixd_killpg(ap_scoreboard_image->parent[n].pid, SIGCONT); + CHILD_INFO_TABLE[n].cpu_stopped = 0; + } + CHILD_INFO_TABLE[n].cpu_usage = 0; +#endif + unixd_killpg(ap_scoreboard_image->parent[n].pid, SIGTERM); + } + } + /* Kill 'em off */ if (unixd_killpg(getpgrp(), SIGHUP) < 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, @@ -2947,10 +3368,19 @@ unixd_pre_config(ptemp); ap_listen_pre_config(); + ap_start_processors = DEFAULT_START_PROCESSORS; + if (ap_start_processors < 1) ap_start_processors = 1; ap_min_processors = DEFAULT_MIN_PROCESSORS; ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS; ap_max_free_processors = DEFAULT_MAX_FREE_PROCESSORS; ap_max_processors = DEFAULT_MAX_PROCESSORS; + if (ap_max_processors < 1) ap_max_processors = 1; +#ifdef PERUSER_MAX_CPU_USAGE + ap_max_cpu_usage = DEFAULT_MAX_CPU_USAGE; + if (ap_max_cpu_usage < 1 || ap_max_cpu_usage > 99) ap_max_cpu_usage = 0; +#endif + if (ap_start_processors > ap_max_processors) + ap_start_processors = ap_max_processors; ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS; ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS; ap_daemons_limit = server_limit; @@ -3112,16 +3542,45 @@ senv.stats_connections = 0; senv.stats_requests = 0; senv.stats_dropped = 0; + senv.total_processors = 0; + senv.idle_processors = 0; + senv.active_processors = 0; + senv.total_processes = 0; +#ifdef PERUSER_MAX_CPU_USAGE + senv.total_cpu_usage = 0; +#endif + senv.start_processors = ap_start_processors; senv.min_processors = ap_min_multiplexers; senv.min_free_processors = ap_min_free_processors; senv.max_free_processors = ap_max_free_processors; senv.max_processors = ap_max_multiplexers; +#ifdef PERUSER_MAX_CPU_USAGE + senv.max_cpu_usage = 0; +#endif + + if (senv.start_processors > senv.max_processors) + senv.start_processors = senv.max_processors; r = child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING, p, &senv); - if (r != NULL) { + if (r == NULL) { + if (multiplexer_senv != NULL) { + /* first multiplexer */ + multiplexer_senv->total_processors++; + multiplexer_senv->idle_processors++; + multiplexer_senv->total_processes++; + if (multiplexer_senv->total_processors == 1 && + multiplexer_senv->start_processors > 1) { + int x; + for (x = 1; x < multiplexer_senv->start_processors; ++x) + child_clone(multiplexer_senv->processor_id); + child_info_image->control->new = 1; + _DBG("Starting %d multiplexers", multiplexer_senv->start_processors); + } + } + } else { ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, r); return -1; } @@ -3131,6 +3590,8 @@ static int peruser_post_read(request_rec *r) { + int retval; + _DBG("function entered"); peruser_server_conf *sconf = PERUSER_SERVER_CONF(r->server->module_config); @@ -3185,25 +3646,42 @@ if (processor->id != my_child_num) { if (processor->status == CHILD_STATUS_STANDBY) { - _DBG("Activating child #%d", processor->id); - processor->status = CHILD_STATUS_STARTING; + + _DBG("New processor %s started", processor->senv->name); + // Only start N processors if this is the first processor being started + if (processor->senv->start_processors > 1 + && processor->senv->total_processors == 1) { + _DBG("Starting %d processors for %s", + processor->senv->start_processors, processor->senv->name); + int x; + for (x = 1; x < processor->senv->start_processors; ++x) + child_clone(processor->id); + } + activate_child(processor); + } _DBG("Passing request.",0); - if (pass_request(r, processor) == -1) { - if (processor->senv->error_pass == 0) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, - "Could not pass request to processor %s " - "(virtualhost %s), " - "request will not be honoured.", - processor->senv->name, r->hostname); + retval = pass_request(r, processor); + if (retval == -1) { + if (processor->senv) { + if (processor->senv->error_pass == 0) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, + "Could not pass request to processor %s " + "(virtualhost %s), " + "request will not be honoured.", + processor->senv->name, r->hostname); + } + processor->senv->error_pass = 1; + processor->senv->stats_dropped++; } - processor->senv->error_pass = 1; - processor->senv->stats_dropped++; - return HTTP_SERVICE_UNAVAILABLE; } + else if (retval == -2) { + /* Request too big - protecting from segfault */ + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } else { processor->senv->error_pass = 0; } @@ -3346,7 +3824,8 @@ qsort(sorted_senv, NUM_SENV, sizeof(int), senv_active_cmp); ap_rputs("

Processors statistics:

" - "" + "
EnvironmentPss
" + "" "" "", r); @@ -3358,11 +3837,12 @@ continue; } - ap_rprintf(r, "" + ap_rprintf(r, "" "", + senv->id, senv->name == NULL ? "" : senv->name, active_env_processors(sorted_senv[x]), - idle_env_processors(sorted_senv[x]), + senv->idle_processors, senv->max_processors, senv->stats_connections, senv->stats_requests, senv->stats_dropped, senv->availability); @@ -3370,41 +3850,52 @@ ap_rputs("
IDEnvironmentActiveIdleMaxConnectionsRequestsDropped (503)Avail
%s%d/%d/%d
%d%s%d%d%d%d%d%d%d%%
", r); ap_rputs("
" - "" "
PssNumber of processors active/idle/max

", r); } else { ap_rputs("
\n", r); ap_rputs("

peruser status

\n", r); - ap_rputs("\n", r); + ap_rputs("
\n", r); ap_rputs("" - "" + "" + "" +#ifdef PERUSER_MAX_CPU_USAGE + "" +#endif "\n", r); for (x = 0; x < NUM_CHILDS; x++) { child = &CHILD_INFO_TABLE[x]; senv = child->senv; + if (senv == NULL) continue; ap_rprintf(r, "" - "" - "\n", + "" + "" +#ifdef PERUSER_MAX_CPU_USAGE + "" +#endif + "\n", child->id, child->pid, child_status_string(child->status), scoreboard_status_string(SCOREBOARD_STATUS(x)), child_type_string(child->type), senv == NULL ? NULL : (senv->name == NULL ? "" : senv->name), - active_processors(x), - idle_processors(x), + senv == NULL ? 0 : senv->active_processors, + senv == NULL ? 0 : senv->idle_processors, senv == NULL ? 0 : senv->max_processors, - senv == NULL ? 0 : senv->availability); + senv == NULL ? 0 : senv->availability +#ifdef PERUSER_MAX_CPU_USAGE + ,child->cpu_stopped, + child->senv->max_cpu_usage, + child->cpu_usage, + child->senv->total_cpu_usage +#endif + ); } - ap_rputs("
IDPIDSTATUSSB STATUSTypeProcessorPssAVAILTypeProcessorActiveIdleMaxAVAILCPU StoppedMaxCPUUsageCPU UsageCPU Total
%3d%5d%8s%8s%12s%48s%d/%d/%d%3d%%
%12s%48s%d%d%d%3d%%%d%d.0%%%.1f%%%.1f%%
\n", r); + ap_rputs("
\n", r); - ap_rputs("
" - "" - "" - "
STATUSProcessor status
PssNumber of processors active/idle/max

", r); } return OK; @@ -3447,15 +3938,25 @@ senv->nice_lvl = 0; senv->chroot = NULL; senv->cgroup = NULL; + senv->start_processors = ap_start_processors; senv->min_processors = ap_min_processors; senv->min_free_processors = ap_min_free_processors; senv->max_free_processors = ap_max_free_processors; senv->max_processors = ap_max_processors; +#ifdef PERUSER_MAX_CPU_USAGE + senv->max_cpu_usage = ap_max_cpu_usage; +#endif + if (senv->start_processors > senv->max_processors) + senv->start_processors = senv->max_processors; senv->error_cgroup = 0; senv->error_pass = 0; senv->stats_connections = 0; senv->stats_requests = 0; senv->stats_dropped = 0; + senv->total_processors = 0; + senv->idle_processors = 0; + senv->active_processors = 0; + senv->total_processes = 0; } static const char *cf_Processor(cmd_parms *cmd, void *dummy, const char *arg) @@ -3516,6 +4017,20 @@ else if (!strcasecmp(directive, "nicelevel")) { senv.nice_lvl = atoi(current->args); } +#ifdef PERUSER_MAX_CPU_USAGE + else if (!strcasecmp(directive, "maxcpuusage")) { + proc_temp = atoi(current->args); + + if (proc_temp < 0 || proc_temp > 99) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "WARNING: Require MaxCPUUsage between 0 AND 100," + "setting to 0"); + proc_temp = 0; + } + + senv.max_cpu_usage = proc_temp; + } +#endif else if (!strcasecmp(directive, "maxprocessors")) { proc_temp = atoi(current->args); @@ -3540,6 +4055,18 @@ senv.min_processors = proc_temp; } + else if (!strcasecmp(directive, "startprocessors")) { + proc_temp = atoi(current->args); + + if (proc_temp < 1) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "WARNING: Require StartProcessors > 0," + "setting to 1"); + proc_temp = 1; + } + + senv.start_processors = proc_temp; + } else if (!strcasecmp(directive, "minspareprocessors")) { proc_temp = atoi(current->args); @@ -3587,8 +4114,8 @@ senv.name, user_name, senv.uid, group_name, senv.gid, senv.chroot, senv.nice_lvl); - _DBG("min_processors=%d min_free_processors=%d max_spare_processors=%d " - "max_processors=%d", senv.min_processors, senv.min_free_processors, + _DBG("start_processors=%d min_processors=%d min_free_processors=%d max_spare_processors=%d " + "max_processors=%d", senv.start_processors, senv.min_processors, senv.min_free_processors, senv.max_free_processors, senv.max_processors); return child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY, cmd->pool, @@ -3754,6 +4281,43 @@ return NULL; } +static const char *set_start_processors(cmd_parms *cmd, void *dummy, + const char *arg) +{ + peruser_server_conf *sconf; + int start_procs; + const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE + | NOT_IN_LIMIT); + + if (err != NULL) { + return err; + } + + start_procs = atoi(arg); + + if (start_procs < 1) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "WARNING: Require StartProcessors > 0, setting to 1"); + start_procs = 1; + } + + if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { + sconf = PERUSER_SERVER_CONF(cmd->server->module_config); + + if (sconf->senv != NULL) { + sconf->senv->start_processors = start_procs; + } else { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "WARNING: StartProcessors must be set" + "after ServerEnvironment to take effect"); + } + } else { + ap_start_processors = start_procs; + } + + return NULL; +} + static const char *set_min_processors(cmd_parms *cmd, void *dummy, const char *arg) { @@ -3864,6 +4428,44 @@ return NULL; } +#ifdef PERUSER_MAX_CPU_USAGE +static const char *set_max_cpu_usage(cmd_parms *cmd, void *dummy, + const char *arg) +{ + peruser_server_conf *sconf; + int max_cpu; + const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE + | NOT_IN_LIMIT); + + if (err != NULL) { + return err; + } + + max_cpu = atoi(arg); + + if (max_cpu < 0 || max_cpu > 99) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "WARNING: Require MaxCPUUsage between 0 AND 100, setting to 0"); + max_cpu = 1; + } + + if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { + sconf = PERUSER_SERVER_CONF(cmd->server->module_config); + if (sconf->senv != NULL) { + sconf->senv->max_cpu_usage = max_cpu; + } else { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "WARNING: MaxCPUUsage must be set" + "after ServerEnvironment to take effect"); + } + } else { + ap_max_cpu_usage = max_cpu; + } + + return NULL; +} +#endif + static const char *set_max_processors(cmd_parms *cmd, void *dummy, const char *arg) { @@ -4068,11 +4670,16 @@ "Maximum number of idle children, 0 to disable"), AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF, "Maximum number of children alive at the same time"), +AP_INIT_TAKE1("StartProcessors", set_start_processors, NULL, RSRC_CONF, + "Number of child processors per vhost at startup"), AP_INIT_TAKE1("MinProcessors", set_min_processors, NULL, RSRC_CONF, "Minimum number of processors per vhost"), AP_INIT_TAKE1("MaxProcessors", set_max_processors, NULL, RSRC_CONF, "Maximum number of processors per vhost"), - +#ifdef PERUSER_MAX_CPU_USAGE +AP_INIT_TAKE1("MaxCPUUsage", set_max_cpu_usage, NULL, RSRC_CONF, + "Maximum CPU usage per active processor"), +#endif AP_INIT_TAKE1("MinMultiplexers", set_min_multiplexers, NULL, RSRC_CONF, "Minimum number of multiplexers the server can have") , AP_INIT_TAKE1("MaxMultiplexers", set_max_multiplexers, NULL, RSRC_CONF,