Download | Plain Text | No Line Numbers
- /*
- * Copyright (C) 2000-2002 David Jao <djao@dominia.org>
- * "MaxConnPerUid", "MaxConnPerVhost" and "MaxLA*" portions by Maxim Chirkov <mc@tyumen.ru>
- * per VHost settings, advanced content-type shm-cache and check, scoreboard dump,
- * optional KeepAlive-Values, code reorganization and apache2 port by Manuel Mausz <manuel@mausz.at>
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy,
- * modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice, this permission notice, and the
- * following disclaimer shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- */
-
- #define CORE_PRIVATE
- #include "httpd.h"
- #include "http_request.h"
- #include "http_core.h"
- #include "http_log.h"
- #include "scoreboard.h"
- #include "unixd.h"
- #include "ap_mpm.h"
- #include "apr_strings.h"
-
- #if HAVE_SHMGET || APR_HAS_SHARED_MEMORY
- # define CREATE_OWN_SCOREBOARD
- # include <sys/ipc.h>
- # include <sys/shm.h>
- #endif
-
- #define VERSION "0.22-vhost"
- #define SHM_KEY IPC_PRIVATE
- //#define DEBUG
- //#define DUMP
-
- #ifdef DUMP
- # include <sys/types.h>
- # include <unistd.h>
- # include <time.h>
- # ifndef DEFAULT_TIME_FORMAT
- # define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
- # endif
- #endif
-
- #define LIPC_LOG(level,errno) level,APR_FROM_OS_ERROR(errno)
- AP_DECLARE_MODULE(limitipconn);
- static int server_limit, thread_limit;
-
- #ifdef CREATE_OWN_SCOREBOARD
- /* apache2 doesn't export ap_sb_handle_t via scoreboard.h */
- struct ap_sb_handle_t
- {
- int child_num;
- int thread_num;
- };
-
- /* our own personal scoreboard */
- typedef struct
- {
- uid_t uid;
- char handler[100];
- } limit_scoreboard_t;
-
- static void *score_board = (void *)-1;
- #endif
-
- typedef struct
- {
- int limit; /* max number of connections per IP */
- int limit_ka; /* optional keepalive limit */
- int limit_vhost; /* max number of connections per virtual host */
- int limit_vhost_ka; /* optional keepalive limit */
- double limit_la1; /* maximum value of Load Average for 1 min. */
- double limit_la5; /* maximum value of Load Average for 5 min. */
- double limit_la15; /* maximum value of Load Average for 15 min. */
-
- #ifdef CREATE_OWN_SCOREBOARD
- int limit_uid; /* max number of connections per user */
- int limit_uid_ka; /* optional keepalive limit */
- apr_array_header_t *excl_limit; /* array of MIME types to limit check; all
- other types are exempt */
- #endif
- } limitipconn_config_t;
-
- #ifdef DUMP
- static const char *ap_scdump_fname = NULL;
-
- static int dump_scoreboard(request_rec *r, const char *reason,
- int matches[server_limit][thread_limit])
- {
- char buf[255];
- FILE *fd;
- int i, j;
- char *vhost = NULL;
- pid_t worker_pid;
-
- if (!ap_scdump_fname)
- {
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_ERR, 0), r,
- "Error: Trying to dump scoreboard, but directive ScoreboardDump isn't set");
- return 1;
- }
-
- apr_snprintf(buf, sizeof(buf), "%s.%u", ap_scdump_fname, getpid());
- char *fname = ap_server_root_relative(r->pool, buf);
- {
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_ERR, errno), r,
- "Error while opening: %s.", fname);
- return 1;
- }
-
- ap_generation_t mpm_generation;
- ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
-
- ap_escape_logitem(r->pool, r->hostname));
-
- for (i = 0; i < server_limit; i++)
- {
- for (j = 0; j < thread_limit; j++)
- {
- worker_score *ws_record = ap_get_scoreboard_worker_from_indexes(i, j);
- process_score *ps_record = ap_get_scoreboard_process(i);
- if (ps_record->generation == mpm_generation)
- vhost = ws_record->vhost;
-
- switch (ws_record->status)
- {
- case SERVER_BUSY_READ:
- case SERVER_BUSY_WRITE:
- case SERVER_BUSY_KEEPALIVE:
- case SERVER_BUSY_LOG:
- case SERVER_BUSY_DNS:
- case SERVER_GRACEFUL:
- if (!matches[i][j])
- continue;
- break;
- default:
- continue;
- }
-
- /* MPM sets per-worker pid and generation */
- ap_generation_t worker_generation;
- if (ws_record->pid)
- {
- worker_pid = ws_record->pid;
- worker_generation = ws_record->generation;
- }
- else
- {
- worker_pid = ps_record->pid;
- worker_generation = ps_record->generation;
- }
-
- if (ws_record->status == SERVER_DEAD)
- else
-
- switch (ws_record->status)
- {
- case SERVER_READY:
- break;
- case SERVER_STARTING:
- break;
- case SERVER_BUSY_READ:
- break;
- case SERVER_BUSY_WRITE:
- break;
- case SERVER_BUSY_KEEPALIVE:
- break;
- case SERVER_BUSY_LOG:
- break;
- case SERVER_BUSY_DNS:
- break;
- case SERVER_DEAD:
- break;
- case SERVER_GRACEFUL:
- break;
- default:
- break;
- }
-
- uid_t userid = 0;
- char *handler = "(unavailable)";
- #ifdef CREATE_OWN_SCOREBOARD
- limit_scoreboard_t (* sb)[thread_limit] = score_board;
- userid = sb[i][j].uid;
- handler = sb[i][j].handler;
- #endif
-
- ap_escape_html(r->pool, ws_record->client),
- ap_escape_html(r->pool, ap_escape_logitem(r->pool, ws_record->request)),
- handler, vhost ? ap_escape_html(r->pool, vhost) : "(unavailable)",
- userid);
- }
- }
-
-
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_ERR, 0), r,
- "Wrote scoreboard dump to: %s", fname);
- return 0;
- }
- #endif
-
- static int limitipconn_handler(request_rec *r)
- {
- limitipconn_config_t *cfg = ap_get_module_config(r->server->module_config,
- &limitipconn_module);
-
- int requests_ip = 0, requests_vhost = 0;
- const char *current_vhost = NULL, *current_ip = NULL;
- int i, j;
- #ifdef CREATE_OWN_SCOREBOARD
- char **exlim = (char **)cfg->excl_limit->elts;
- int requests_uid = 0;
- uid_t current_uid = 0;
- #endif
- #ifdef DUMP
- int matches[server_limit][thread_limit];
- #endif
-
- /* a limit value of 0 by convention means no limit. */
- if (cfg->limit <= 0 && cfg->limit_ka <= 0
- #ifdef CREATE_OWN_SCOREBOARD
- && cfg->limit_uid <= 0 && cfg->limit_uid_ka <= 0
- #endif
- && cfg->limit_vhost <= 0 && cfg->limit_vhost_ka <= 0
- && cfg->limit_la1 <= 0.0 && cfg->limit_la5 <= 0.0 && cfg->limit_la15 <= 0.0)
- {
- #ifdef DEBUG
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_DEBUG, 0), r,
- "OK: No limit");
- #endif
- return OK;
- }
-
- #ifdef CREATE_OWN_SCOREBOARD
- ap_sb_handle_t *sbh = r->connection->sbh;
- if (sbh == NULL)
- {
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_ERR, 0), r,
- "Warning: Request has no reference to scoreboard!");
- return OK;
- }
- limit_scoreboard_t (* sb)[thread_limit] = score_board;
- limit_scoreboard_t *sbrec = &sb[sbh->child_num][sbh->thread_num];
-
- /* cycle through the exclusive list, if it exists; if our handler
- * is not present, bail out */
- if (cfg->excl_limit->nelts > 0)
- {
- /* always update our scoreboard */
- if (r->handler)
- apr_cpystrn(sbrec->handler, r->handler, sizeof(sbrec->handler));
- else
- sbrec->handler[0] = 0;
-
- #ifdef DEBUG
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_DEBUG, 0), r,
- "uri: %s handler: %s", r->uri, r->handler);
- #endif
-
- for (i = 0; r->handler && i < cfg->excl_limit->nelts; i++)
- {
- break;
- }
- if (i == cfg->excl_limit->nelts)
- {
- #ifdef DEBUG
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_DEBUG, 0), r,
- "OK: %s not checked", r->handler);
- #endif
- return OK;
- }
- }
- #endif /* CREATE_OWN_SCOREBOARD */
-
- /* check load average overflow */
- if (cfg->limit_la1 > 0.0 || cfg->limit_la5 > 0.0 || cfg->limit_la15 > 0.0)
- {
- double current_la[3];
- if (getloadavg(current_la, 3) != -1)
- {
- if ((current_la[0] >= cfg->limit_la1) && (current_la[1] >= cfg->limit_la5)
- && (current_la[2] >= cfg->limit_la15))
- {
- r->connection->keepalive = -1;
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_ERR, 0), r,
- "Load Average limit exceeded (limit: %.2f, %.2f, %.2f)",
- cfg->limit_la1, cfg->limit_la5, cfg->limit_la15);
- return HTTP_SERVICE_UNAVAILABLE;
- }
- }
- }
-
- /* get client ip */
- if (cfg->limit > 0 || cfg->limit_ka > 0)
- current_ip = r->connection->client_ip;
-
- /* get uid of current virual host for future use */
- if (r->server->is_virtual)
- {
- #ifdef CREATE_OWN_SCOREBOARD
- if (cfg->limit_uid > 0 || cfg->limit_uid_ka > 0)
- {
- ap_unix_identity_t *identity = ap_run_get_suexec_identity(r);
- if (identity != NULL)
- current_uid = identity->uid;
- }
- sbrec->uid = current_uid;
- #endif
- if (cfg->limit_vhost > 0 || cfg->limit_vhost_ka > 0)
- current_vhost = r->server->server_hostname;
- }
-
- ap_generation_t mpm_generation;
- ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation);
-
- /* count up the number of connections we are handling right now from
- * this IP address */
- for (i = 0; i < server_limit; i++)
- {
- for (j = 0; j < thread_limit; j++)
- {
- #ifdef DUMP
- matches[i][j] = 0;
- #endif
- worker_score *ws_record = ap_get_scoreboard_worker_from_indexes(i, j);
- process_score *ps_record = ap_get_scoreboard_process(i);
- switch (ws_record->status)
- {
- case SERVER_BUSY_READ:
- case SERVER_BUSY_WRITE:
- case SERVER_BUSY_KEEPALIVE:
- case SERVER_BUSY_LOG:
- case SERVER_BUSY_DNS:
- case SERVER_GRACEFUL:
- #ifdef CREATE_OWN_SCOREBOARD
- /* cycle through the exclusive list, if it exists; if our handler
- * is not present, skip */
- if (cfg->excl_limit->nelts > 0)
- {
- /* skip if no handler is set */
- if (!sb[i][j].handler)
- continue;
-
- int k;
- for (k = 0; k < cfg->excl_limit->nelts; k++)
- {
- break;
- }
- if (k == cfg->excl_limit->nelts)
- continue;
- }
- #endif
-
- sizeof(ws_record->client)) == 0)
- {
- requests_ip++;
- #ifdef DUMP
- matches[i][j] = 1;
- #endif
- }
-
- if (ps_record->generation == mpm_generation)
- {
- #ifdef CREATE_OWN_SCOREBOARD
- if (current_uid && current_uid != ap_unixd_config.user_id
- && sb[i][j].uid == current_uid)
- requests_uid++;
- #endif
- {
- requests_vhost++;
- }
- }
- break;
- default:
- break;
- }
- }
- }
-
- /* turn off keepalive if keepalive-limit reached */
- if ((cfg->limit_ka > 0 && requests_ip > cfg->limit_ka)
- #ifdef CREATE_OWN_SCOREBOARD
- || (cfg->limit_uid_ka > 0 && requests_uid > cfg->limit_uid_ka)
- #endif
- || (cfg->limit_vhost_ka > 0 && requests_vhost > cfg->limit_vhost_ka))
- {
- #ifdef DEBUG
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_DEBUG, 0), r,
- "Keepalive-limit reached. Disabling keepalive.");
- #endif
- r->connection->keepalive = -1;
- }
-
- /* hard limit reached */
- if (cfg->limit > 0 && requests_ip > cfg->limit)
- {
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_ERR, 0), r,
- "Rejected, too many connections from address %s (limit: %d).",
- current_ip, cfg->limit);
- apr_table_setn(r->subprocess_env, "LIMITIP", "1");
- #ifdef DUMP
- dump_scoreboard(r, "IP-Limit", matches);
- #endif
- return HTTP_SERVICE_UNAVAILABLE;
- }
- #ifdef CREATE_OWN_SCOREBOARD
- else if (cfg->limit_uid > 0 && requests_uid > cfg->limit_uid)
- {
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_ERR, 0), r,
- "Rejected, too many connections for uid %d (limit: %d)",
- current_uid, cfg->limit_uid);
- #ifdef DUMP
- dump_scoreboard(r, "UID-Limit", matches);
- #endif
- return HTTP_SERVICE_UNAVAILABLE;
- }
- #endif
- else if (cfg->limit_vhost > 0 && requests_vhost > cfg->limit_vhost)
- {
- ap_log_rerror(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_ERR, 0), r,
- "Rejected, too many connections for vhost %s (limit: %d)",
- current_vhost, cfg->limit_vhost);
- #ifdef DUMP
- dump_scoreboard(r, "Vhost-Limit", matches);
- #endif
- return HTTP_SERVICE_UNAVAILABLE;
- }
-
- return OK;
- }
-
- static void *limitipconn_create_config(apr_pool_t *p, server_rec *s)
- {
- limitipconn_config_t *cfg = apr_pcalloc(p, sizeof(*cfg));
-
- /* default configuration: no limit, and both arrays are empty */
- cfg->limit = -1;
- cfg->limit_ka = -1;
- cfg->limit_vhost = -1;
- cfg->limit_vhost_ka = -1;
- cfg->limit_la1 = -1.0;
- cfg->limit_la5 = -1.0;
- cfg->limit_la15 = -1.0;
- #ifdef CREATE_OWN_SCOREBOARD
- cfg->limit_uid = -1;
- cfg->limit_uid_ka = -1;
- cfg->excl_limit = apr_array_make(p, 0, sizeof(char *));
- #endif
-
- return cfg;
- }
-
- /* simple merge: per vhost entries overrides main server entries */
- static void *limitipconn_merge_config(apr_pool_t *p, void *BASE, void *ADD)
- {
- limitipconn_config_t *base = BASE;
- limitipconn_config_t *add = ADD;
- limitipconn_config_t *cfg = apr_pcalloc(p, sizeof(*cfg));
-
- cfg->limit = (add->limit == -1) ? base->limit : add->limit;
- cfg->limit_ka = (add->limit_ka == -1) ? base->limit_ka : add->limit_ka;
- #ifdef CREATE_OWN_SCOREBOARD
- cfg->limit_uid = (add->limit_uid == -1) ? base->limit_uid : add->limit_uid;
- cfg->limit_uid_ka = (add->limit_uid_ka == -1) ? base->limit_uid_ka : add->limit_uid_ka;
- #endif
- cfg->limit_vhost = (add->limit_vhost == -1) ? base->limit_vhost : add->limit_vhost;
- cfg->limit_vhost_ka = (add->limit_vhost_ka == -1) ? base->limit_vhost_ka : add->limit_vhost_ka;
- cfg->limit_la1 = (add->limit_la1 == -1.0) ? base->limit_la1 : add->limit_la1;
- cfg->limit_la5 = (add->limit_la5 == -1.0) ? base->limit_la5 : add->limit_la5;
- cfg->limit_la15 = (add->limit_la15 == -1.0) ? base->limit_la15 : add->limit_la15;
- #ifdef CREATE_OWN_SCOREBOARD
- cfg->excl_limit = (add->excl_limit->nelts == 0) ? base->excl_limit : add->excl_limit;
- #endif
-
- return cfg;
- }
-
- /* parse the MaxConnPerIP directive */
- static const char *limit_config_cmd(cmd_parms *cmd, void *mconfig,
- const char *arg1, const char *arg2)
- {
- limitipconn_config_t *cfg = ap_get_module_config(cmd->server->module_config,
- &limitipconn_module);
-
- if (limit < 0 || limit > INT_MAX)
- return "Integer overflow or invalid number";
- cfg->limit = limit;
-
- if (arg2)
- {
- if (limit_ka < 0 || limit_ka > INT_MAX)
- return "Integer overflow or invalid number";
- if (limit > 0 && limit_ka > limit)
- return "KeepAlive-limit has to be smaller than hard limit.";
- cfg->limit_ka = limit_ka;
- }
-
- return NULL;
- }
-
- #ifdef CREATE_OWN_SCOREBOARD
- /* parse the IPLimit directive */
- static const char *excl_limit_config_cmd(cmd_parms *cmd, void *mconfig,
- const char *arg)
- {
- limitipconn_config_t *cfg = ap_get_module_config(cmd->server->module_config,
- &limitipconn_module);
- *(char **)apr_array_push(cfg->excl_limit) = apr_pstrdup(cmd->pool, arg);
- return NULL;
- }
- #endif
-
- /* parse the MaxConnPerVhost directive */
- static const char *limit_vhost_config_cmd(cmd_parms *cmd, void *mconfig,
- const char *arg1, const char *arg2)
- {
- limitipconn_config_t *cfg = ap_get_module_config(cmd->server->module_config,
- &limitipconn_module);
-
- if (limit < 0 || limit > INT_MAX)
- return "Integer overflow or invalid number";
- cfg->limit_vhost = limit;
-
- if (arg2)
- {
- if (limit_ka < 0 || limit_ka > INT_MAX)
- return "Integer overflow or invalid number";
- if (limit > 0 && limit_ka > limit)
- return "KeepAlive-limit has to be smaller than hard limit.";
- cfg->limit_vhost_ka = limit_ka;
- }
-
- return NULL;
- }
-
- #ifdef CREATE_OWN_SCOREBOARD
- /* parse the MaxConnPerUid directive */
- static const char *limit_uid_config_cmd(cmd_parms *cmd, void *mconfig,
- const char *arg1, const char *arg2)
- {
- limitipconn_config_t *cfg = ap_get_module_config(cmd->server->module_config,
- &limitipconn_module);
-
- if (limit < 0 || limit > INT_MAX)
- return "Integer overflow or invalid number";
- cfg->limit_uid = limit;
-
- if (arg2)
- {
- if (limit_ka < 0 || limit_ka > INT_MAX)
- return "Integer overflow or invalid number";
- if (limit > 0 && limit_ka > limit)
- return "KeepAlive-limit has to be smaller than hard limit.";
- cfg->limit_uid_ka = limit_ka;
- }
-
- return NULL;
- }
- #endif
-
- /* parse the MaxLA1 directive */
- static const char *limit_la1_config_cmd(cmd_parms *cmd, void *mconfig,
- const char *arg)
- {
- limitipconn_config_t *cfg = ap_get_module_config(cmd->server->module_config,
- &limitipconn_module);
-
- if (limit < 0.0)
- return "Invalid LA1 value";
-
- cfg->limit_la1 = limit;
- return NULL;
- }
-
- /* parse the MaxLA5 directive */
- static const char *limit_la5_config_cmd(cmd_parms *cmd, void *mconfig,
- const char *arg)
- {
- limitipconn_config_t *cfg = ap_get_module_config(cmd->server->module_config,
- &limitipconn_module);
-
- if (limit < 0.0)
- return "Invalid LA5 value";
-
- cfg->limit_la5 = limit;
- return NULL;
- }
-
- /* parse the MaxLA15 directive */
- static const char *limit_la15_config_cmd(cmd_parms *cmd, void *mconfig,
- const char *arg)
- {
- limitipconn_config_t *cfg = ap_get_module_config(cmd->server->module_config,
- &limitipconn_module);
-
- if (limit < 0.0)
- return "Invalid LA15 value";
-
- cfg->limit_la15 = limit;
- return NULL;
- }
-
- #ifdef DUMP
- static const char *set_scoreboard_dump(cmd_parms *cmd, void *mconfig,
- const char *arg)
- {
- const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
- if (err != NULL)
- return err;
-
- if (cmd->server->is_virtual)
- return "ScoreboardDump directive not allowed in <VirtualHost>";
-
- ap_scdump_fname = arg;
- return NULL;
- }
- #endif
-
- static command_rec limitipconn_cmds[] = {
- AP_INIT_TAKE12("MaxConnPerIP", limit_config_cmd, NULL, RSRC_CONF,
- "maximum simultaneous connections per IP address. Second value is optional."
- " If reached, KeepAlive will be turned off."),
- #ifdef CREATE_OWN_SCOREBOARD
- AP_INIT_ITERATE("IPLimit", excl_limit_config_cmd, NULL, RSRC_CONF,
- "restrict limit checking to these handlers/MIME types only."),
- #endif
- #ifdef CREATE_OWN_SCOREBOARD
- AP_INIT_TAKE12("MaxConnPerUid", limit_uid_config_cmd, NULL, RSRC_CONF,
- "maximum simultaneous connections per user. Second value is optional."
- " If reached, KeepAlive will be turned off."),
- #endif
- AP_INIT_TAKE12("MaxConnPerVhost", limit_vhost_config_cmd, NULL, RSRC_CONF,
- "maximum simultaneous connections per virtual host. Second value is optional."
- " If reached, KeepAlive will be turned off."),
- AP_INIT_TAKE1("MaxLA1", limit_la1_config_cmd, NULL, RSRC_CONF,
- "maximum Load Overage value for the past 1 minute."),
- AP_INIT_TAKE1("MaxLA5", limit_la5_config_cmd, NULL, RSRC_CONF,
- "maximum Load Overage value for the past 5 minutes."),
- AP_INIT_TAKE1("MaxLA15", limit_la15_config_cmd, NULL, RSRC_CONF,
- "maximum Load Overage value for the past 15 minutes."),
- #ifdef DUMP
- AP_INIT_TAKE1("ScoreboardDump", set_scoreboard_dump, NULL, RSRC_CONF,
- "The filename of the scoreboard dumps. Will be appended by the process id."),
- #endif
- { NULL },
- };
-
- #ifdef CREATE_OWN_SCOREBOARD
- static apr_status_t limit_detach_shm(void *data)
- {
- shmdt(data);
- return OK;
- }
- #endif
-
- static int limitipconn_init(apr_pool_t *p, apr_pool_t *plog,
- apr_pool_t *ptemp, server_rec *s)
- {
- /* initialize_module() will be called twice, and if it's a DSO
- * then all static data from the first call will be lost. Only
- * set up our static data on the second call. */
- if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG)
- return OK;
-
- ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
- ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit);
-
- #ifdef CREATE_OWN_SCOREBOARD
- int shmid;
- if ((shmid = shmget(SHM_KEY, sizeof(limit_scoreboard_t) * server_limit * thread_limit,
- IPC_CREAT | SHM_R | SHM_W)) == -1)
- {
- ap_log_error(APLOG_MARK, LIPC_LOG(APLOG_EMERG, errno), s,
- "Could not initialize shared memory");
- }
-
- #ifdef DEBUG
- ap_log_error(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_DEBUG, 0), s,
- "Initialized shared memory.");
- #endif
-
- if ((score_board = shmat(shmid, NULL, 0)) == (void *)-1)
- ap_log_error(APLOG_MARK, LIPC_LOG(APLOG_EMERG, errno), s, "shmat error");
- /* exit later after marking the segment to remove itself */
- else
- apr_pool_cleanup_register(p, (void *)score_board, limit_detach_shm,
- apr_pool_cleanup_null);
-
- /* mark the segment for deletion once all attachments are detached */
- if (shmctl(shmid, IPC_RMID, NULL) == -1)
- ap_log_error(APLOG_MARK, LIPC_LOG(APLOG_EMERG, errno), s,
- "Could not mark shared segment for deletion, you must manually clean it up");
-
- /* exit if we didn't attach successfully */
- if (score_board == (void *)-1)
- #endif
-
- ap_log_error(APLOG_MARK, LIPC_LOG(APLOG_NOERRNO|APLOG_NOTICE, 0), s, "Initialized");
- return OK;
- }
-
- static void register_hooks(apr_pool_t * p)
- {
- ap_hook_post_config(limitipconn_init, NULL, NULL, APR_HOOK_MIDDLE);
- ap_hook_fixups(limitipconn_handler, NULL, NULL, APR_HOOK_MIDDLE);
- }
-
- module AP_MODULE_DECLARE_DATA limitipconn_module =
- {
- STANDARD20_MODULE_STUFF,
- NULL, /* per-directory config creator */
- NULL, /* dir config merger */
- limitipconn_create_config, /* server config creator */
- limitipconn_merge_config, /* server config merger */
- limitipconn_cmds, /* command table */
- register_hooks, /* set up other request processing hooks */
- };
-