Enforce the per-vhost server limit. Note that this is per-vhost, not per-directory (since it works by reading the scoreboard), so we need to add per-server configuration data. Index: httpd-2.4.1/server/mpm/itk/itk.c =================================================================== --- httpd-2.4.1.orig/server/mpm/itk/itk.c +++ httpd-2.4.1/server/mpm/itk/itk.c @@ -166,6 +166,11 @@ typedef struct char *username; } itk_per_dir_conf; +typedef struct +{ + int max_clients_vhost; +} itk_server_conf; + module AP_MODULE_DECLARE_DATA mpm_itk_module; #ifdef GPROF @@ -1491,9 +1496,29 @@ static int itk_post_perdir_config(reques gid_t wanted_gid; const char *wanted_username; int err = 0; + + itk_server_conf *sconf = + (itk_server_conf *) ap_get_module_config(r->server->module_config, &mpm_itk_module); + itk_per_dir_conf *dconf; + + /* Enforce MaxClientsVhost. */ + if (sconf->max_clients_vhost > 0) { + int i, num_other_servers = 0; + for (i = 0; i < ap_daemons_limit; ++i) { + worker_score *ws = &ap_scoreboard_image->servers[i][0]; + if (ws->status >= SERVER_BUSY_READ && strncmp(ws->vhost, r->server->server_hostname, 31) == 0) + ++num_other_servers; + } - itk_per_dir_conf *dconf = - (itk_per_dir_conf *) ap_get_module_config(r->per_dir_config, &mpm_itk_module); + if (num_other_servers > sconf->max_clients_vhost) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \ + "MaxClientsVhost reached for %s, refusing client.", + r->server->server_hostname); + return HTTP_SERVICE_UNAVAILABLE; + } + } + + dconf = (itk_per_dir_conf *) ap_get_module_config(r->per_dir_config, &mpm_itk_module); strncpy(ap_scoreboard_image->servers[my_child_num][0].vhost, r->server->server_hostname, 31); ap_scoreboard_image->servers[my_child_num][0].vhost[31] = 0; @@ -1625,6 +1650,14 @@ static const char *assign_user_id (cmd_p return NULL; } +static const char *set_max_clients_vhost (cmd_parms *cmd, void *dummy, const char *arg) +{ + itk_server_conf *sconf = + (itk_server_conf *) ap_get_module_config(cmd->server->module_config, &mpm_itk_module); + sconf->max_clients_vhost = atoi(arg); + return NULL; +} + static const command_rec itk_cmds[] = { LISTEN_COMMANDS, AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, @@ -1641,6 +1674,8 @@ AP_INIT_TAKE1("ServerLimit", set_server_ "Maximum value of MaxRequestWorkers for this run of Apache"), AP_INIT_TAKE2("AssignUserID", assign_user_id, NULL, RSRC_CONF|ACCESS_CONF, "Tie a virtual host to a specific child process."), +AP_INIT_TAKE1("MaxClientsVHost", set_max_clients_vhost, NULL, RSRC_CONF, + "Maximum number of children alive at the same time for this virtual host."), AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND, { NULL } }; @@ -1654,12 +1689,21 @@ static void *itk_create_dir_config(apr_p return c; } +/* == allocate a private server config structure == */ +static void *itk_create_server_config(apr_pool_t *p, server_rec *s) +{ + itk_server_conf *c = (itk_server_conf *) + apr_pcalloc(p, sizeof(itk_server_conf)); + c->max_clients_vhost = -1; + return c; +} + AP_DECLARE_MODULE(mpm_itk) = { MPM20_MODULE_STUFF, NULL, /* hook to run before apache parses args */ itk_create_dir_config, /* create per-directory config structure */ NULL, /* merge per-directory config structures */ - NULL, /* create per-server config structure */ + itk_create_server_config, /* create per-server config structure */ NULL, /* merge per-server config structures */ itk_cmds, /* command apr_table_t */ itk_hooks, /* register hooks */