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;
     }
 }
 

Reply via email to