On Fri, 2009-10-16 at 08:00 +1100, Bojan Smojver wrote:
> I wrote the attached craziness.

Slightly more sophisticated craziness attached.

-- 
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 12:19:49.929566854 +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(), diff;
 
             if (!reported) {
                 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
@@ -870,6 +873,36 @@
                 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.
+             */
+            diff = now - maxed_out;
+
+            if (diff >= SCOREBOARD_MAINTENANCE_INTERVAL &&
+                diff <= SCOREBOARD_MAINTENANCE_INTERVAL * 2) {
+
+                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);
+                    }
+                }
+            }
+
+            maxed_out = now;
         }
         else {
             if (idle_spawn_rate >= 8) {
@@ -902,10 +934,13 @@
             else if (idle_spawn_rate < MAX_SPAWN_RATE) {
                 idle_spawn_rate *= 2;
             }
+
+            maxed_out = 0;
         }
     }
     else {
         idle_spawn_rate = 1;
+        maxed_out = 0;
     }
 }
 

Reply via email to