On Fri, 2009-10-16 at 12:31 +1100, Bojan Smojver wrote:
> Slightly more sophisticated craziness attached.
OK, just a little bit cleaner this time.
--
Bojan
--- httpd-2.2.14/server/mpm/prefork/prefork.c 2009-02-01 07:54:55.000000000 +1100
+++ httpd-2.2.14-p/server/mpm/prefork/prefork.c 2009-10-16 13:55:28.764567473 +1100
@@ -803,6 +803,7 @@
int free_slots[MAX_SPAWN_RATE];
int last_non_dead;
int total_non_dead;
+ static apr_time_t maxed_out = 0;
/* initialize the free_list */
free_length = 0;
@@ -856,12 +857,14 @@
*/
ap_mpm_pod_signal(pod);
idle_spawn_rate = 1;
+ maxed_out = 0;
}
else if (idle_count < ap_daemons_min_free) {
/* terminate the free list */
if (free_length == 0) {
/* only report this condition once */
static int reported = 0;
+ apr_time_t now = apr_time_now();
if (!reported) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
@@ -870,6 +873,39 @@
reported = 1;
}
idle_spawn_rate = 1;
+
+ /* Flooded by intentionally slow requests (e.g. slowloris)?
+ * Give the legitimate clients one maintenance interval to
+ * finish with request reads, then cull if we are still
+ * maxed out. Crude, but seems to clear things out.
+ */
+ if (maxed_out) {
+ apr_time_t diff = now - maxed_out;
+
+ if (diff >= SCOREBOARD_MAINTENANCE_INTERVAL) {
+ pid_t reader;
+
+ for (i = 0; i < ap_daemons_limit; ++i) {
+
+ ws = &ap_scoreboard_image->servers[i][0];
+
+ if (ws->status == SERVER_BUSY_READ ||
+ ws->status == SERVER_BUSY_KEEPALIVE) {
+
+ reader = ap_scoreboard_image->parent[i].pid;
+
+ ap_mpm_safe_kill(reader, SIGTERM);
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0,
+ ap_server_conf,
+ "Killed reader: %" APR_PID_T_FMT,
+ reader);
+ }
+ }
+ }
+ }
+ else {
+ maxed_out = now;
+ }
}
else {
if (idle_spawn_rate >= 8) {
@@ -902,10 +938,13 @@
else if (idle_spawn_rate < MAX_SPAWN_RATE) {
idle_spawn_rate *= 2;
}
+
+ maxed_out = 0;
}
}
else {
idle_spawn_rate = 1;
+ maxed_out = 0;
}
}