1 --- httpd-2.2.14-p/server/mpm/prefork/prefork.c 2009-02-01 07:54:55.000000000 +1100
2 +++ httpd-2.2.14/server/mpm/prefork/prefork.c 2009-11-02 12:09:50.511530535 +1100
10 #include <bstring.h> /* for IRIX, FD_SET calls bzero() */
15 +static int volatile client_socket = -1;
17 +#ifndef NO_USE_SIGACTION
18 +static void shutdown_socket(int sig, siginfo_t *info, void *context)
20 +static void shutdown_socket(int sig)
23 +#ifndef NO_USE_SIGACTION
24 + if (info->si_pid == getppid()) {
26 + if (client_socket != -1) {
27 + shutdown(client_socket, SHUT_RDWR);
29 +#ifndef NO_USE_SIGACTION
32 + clean_child_exit(0);
37 /* volatile just in case */
38 static int volatile shutdown_pending;
39 static int volatile restart_pending;
42 current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc);
44 + apr_os_sock_get((apr_os_sock_t *)&client_socket, csd);
46 ap_process_connection(current_conn, csd);
47 ap_lingering_close(current_conn);
52 /* Check the pod and the generation number after processing a
57 +#ifndef NO_USE_SIGACTION
58 + struct sigaction act;
61 #ifdef HAVE_BINDPROCESSOR
62 /* by default AIX binds to a single processor
63 * this bit unbinds children which will then bind to another cpu
65 * The pod is used for signalling the graceful restart.
67 apr_signal(AP_SIG_GRACEFUL, stop_listening);
69 + /* If the parent sends SIGINT to the child, we shutdown the
70 + * client socket, as we suspect that we are under a DoS attack.
72 +#ifndef NO_USE_SIGACTION
73 + memset(&act, 0, sizeof(act));
74 + act.sa_flags = SA_SIGINFO;
75 + act.sa_sigaction = shutdown_socket;
76 + sigaction(SIGINT, &act, NULL);
78 + apr_signal(SIGINT, shutdown_socket);
85 int free_slots[MAX_SPAWN_RATE];
89 + static apr_time_t maxed_out = 0;
91 /* initialize the free_list */
96 for (i = 0; i < ap_daemons_limit; ++i) {
99 if (i >= ap_max_daemons_limit && free_length == idle_spawn_rate)
101 ws = &ap_scoreboard_image->servers[i][0];
102 @@ -856,12 +900,17 @@
104 ap_mpm_pod_signal(pod);
108 else if (idle_count < ap_daemons_min_free) {
109 /* terminate the free list */
110 if (free_length == 0) {
111 /* only report this condition once */
112 static int reported = 0;
113 + static unsigned char sb_digest[APR_MD5_DIGESTSIZE];
114 + apr_time_t now = apr_time_now();
119 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
120 @@ -870,6 +919,120 @@
125 + /* If after one maintenace interval we still see the same
126 + * situation on the scoreboard, shutdown all client sockets
127 + * in read state and at least 10% of all client sockets.
128 + * Crude, but seems to clear things out.
131 + apr_time_t diff = now - maxed_out;
133 + if (diff >= SCOREBOARD_MAINTENANCE_INTERVAL) {
134 + unsigned char cur_digest[APR_MD5_DIGESTSIZE];
136 + /* Current digest of the scoreboard.
138 + apr_md5_init(&ctx);
139 + for (i = 0; i < ap_daemons_limit; ++i) {
140 + status = ap_scoreboard_image->servers[i][0].status;
141 + apr_md5_update(&ctx, &status, sizeof(status));
143 + pid = ap_scoreboard_image->parent[i].pid;
144 + apr_md5_update(&ctx, &pid, sizeof(pid));
146 + apr_md5_final(cur_digest, &ctx);
148 + /* If we haven't had a change for one maintenance
149 + * interval, we need to make room.
151 + if (memcmp(sb_digest, cur_digest, APR_MD5_DIGESTSIZE)) {
155 + int rdrs = 0, cull = ap_daemons_limit / 10;
157 + /* Disconnect all readers (includes keep alive).
159 + for (i = 0; i < ap_daemons_limit; ++i) {
160 + pid = ap_scoreboard_image->parent[i].pid;
161 + status = ap_scoreboard_image->servers[i][0].status;
163 + if (status == SERVER_BUSY_READ ||
164 + status == SERVER_BUSY_KEEPALIVE) {
166 + ap_mpm_safe_kill(pid, SIGINT);
171 + /* Make up to 10% of all sockets, if required.
173 + for (i = 0; i < ap_daemons_limit && cull > rdrs; ++i) {
174 + status = ap_scoreboard_image->servers[i][0].status;
176 + if (status != SERVER_BUSY_READ &&
177 + status != SERVER_BUSY_KEEPALIVE) {
179 + pid = ap_scoreboard_image->parent[i].pid;
180 + ap_mpm_safe_kill(pid, SIGINT);
190 + /* Create digest of the scorboard, see if things
191 + * change next time around.
193 + apr_md5_init(&ctx);
194 + for (i = 0; i < ap_daemons_limit; ++i) {
195 + status = ap_scoreboard_image->servers[i][0].status;
197 + /* These are the conditions we are concerned with.
200 + case SERVER_BUSY_READ:
201 + case SERVER_BUSY_KEEPALIVE:
203 + case SERVER_BUSY_WRITE:
205 + case SERVER_GRACEFUL:
211 + apr_md5_update(&ctx, &status, sizeof(status));
213 + pid = ap_scoreboard_image->parent[i].pid;
214 + apr_md5_update(&ctx, &pid, sizeof(pid));
216 + apr_md5_final(sb_digest, &ctx);
218 + /* Over 95% in read state (includes keep alive), clear now.
220 + if (ap_daemons_limit - rdrs < ap_daemons_limit / 20) {
221 + /* Disconnect all readers (includes keep alive).
223 + for (i = 0; i < ap_daemons_limit; ++i) {
224 + pid = ap_scoreboard_image->parent[i].pid;
225 + status = ap_scoreboard_image->servers[i][0].status;
227 + if (status == SERVER_BUSY_READ ||
228 + status == SERVER_BUSY_KEEPALIVE) {
229 + ap_mpm_safe_kill(pid, SIGINT);
240 if (idle_spawn_rate >= 8) {
241 @@ -902,10 +1065,13 @@
242 else if (idle_spawn_rate < MAX_SPAWN_RATE) {
243 idle_spawn_rate *= 2;
255 --- httpd-2.2.14-p/server/mpm/worker/worker.c 2009-11-02 09:40:23.129750043 +1100
256 +++ httpd-2.2.14/server/mpm/worker/worker.c 2009-11-02 12:37:53.987529627 +1100
258 #define APR_WANT_STRFUNC
259 #include "apr_want.h"
260 #include "apr_atomic.h"
261 +#include "apr_md5.h"
263 #if APR_HAVE_UNISTD_H
265 @@ -422,6 +423,101 @@
269 +#if !defined(NO_USE_SIGACTION) && defined(HAVE_PTHREAD_KILL)
270 +static void shutdown_sockets(int sig, siginfo_t *info, void *context)
272 + int csd, i, j, slot = 0, status, total_rdrs = 0, rdrs = 0,
273 + cull = ap_daemons_limit * ap_threads_per_child / 10;
275 + /* not from parent, ignore */
276 + if (info->si_pid != getppid()) {
280 + suspend_workers = 1;
281 + apr_atomic_set32(&suspended_workers, 0);
283 + /* suspend worker threads */
284 + for (i = 0; i < ap_threads_per_child; i++) {
285 + if (worker_os_threads[i]) {
286 + pthread_kill(*worker_os_threads[i], WORKER_SIGNAL);
290 + /* wait for threads to suspend, but press ahead after a while anyway */
292 + apr_atomic_read32(&suspended_workers) < ap_threads_per_child && i < 25;
294 + apr_sleep(apr_time_from_sec(1) / 5);
297 + /* Determine total number of readers (includes keep alive), our
298 + * slot and the number of our own readers.
300 + for (i = 0; i < ap_daemons_limit; ++i) {
301 + if (ap_scoreboard_image->parent[i].pid == ap_my_pid) {
305 + for (j = 0; j < ap_threads_per_child; j++) {
306 + status = ap_scoreboard_image->servers[i][j].status;
308 + if (status == SERVER_BUSY_READ ||
309 + status == SERVER_BUSY_KEEPALIVE) {
320 + /* Disconnect all readers (includes keep alive).
322 + for (j = 0; j < ap_threads_per_child; j++) {
323 + status = ap_scoreboard_image->servers[slot][j].status;
325 + if (worker_sockets[j] &&
326 + (status == SERVER_BUSY_READ ||
327 + status == SERVER_BUSY_KEEPALIVE)) {
329 + apr_os_sock_get((apr_os_sock_t *)&csd, worker_sockets[j]);
330 + shutdown(csd, SHUT_RDWR);
334 + /* Make up to 10% of all sockets, if required.
336 + if (total_rdrs < cull) {
337 + cull = ((ap_threads_per_child - rdrs) * (cull - total_rdrs)) / cull;
339 + for (j = 0; j < ap_threads_per_child && cull > 0; j++) {
340 + status = ap_scoreboard_image->servers[slot][j].status;
342 + if (worker_sockets[j] &&
343 + status != SERVER_BUSY_READ &&
344 + status != SERVER_BUSY_KEEPALIVE) {
346 + apr_os_sock_get((apr_os_sock_t *)&csd, worker_sockets[j]);
347 + shutdown(csd, SHUT_RDWR);
353 + suspend_workers = 0;
355 + /* resume worker threads */
356 + for (i = 0; i < ap_threads_per_child; i++) {
357 + if (worker_os_threads[i]) {
358 + pthread_kill(*worker_os_threads[i], WORKER_SIGNAL);
364 /*****************************************************************
365 * Connection structures and accounting...
367 @@ -1319,12 +1415,28 @@
368 join_workers(ts->listener, threads);
370 else { /* !one_process */
371 +#if !defined(NO_USE_SIGACTION) && defined(HAVE_PTHREAD_KILL)
372 + struct sigaction act;
375 /* remove SIGTERM from the set of blocked signals... if one of
376 * the other threads in the process needs to take us down
377 * (e.g., for MaxRequestsPerChild) it will send us SIGTERM
379 unblock_signal(SIGTERM);
380 apr_signal(SIGTERM, dummy_signal_handler);
382 + /* If the parent sends SIGINT to the child, we shutdown the
383 + * client socket, as we suspect that we are under a DoS attack.
385 +#if !defined(NO_USE_SIGACTION) && defined(HAVE_PTHREAD_KILL)
386 + unblock_signal(SIGINT);
387 + memset(&act, 0, sizeof(act));
388 + act.sa_flags = SA_SIGINFO;
389 + act.sa_sigaction = shutdown_sockets;
390 + sigaction(SIGINT, &act, NULL);
393 /* Watch for any messages from the parent over the POD */
395 rv = ap_mpm_pod_check(pod);
396 @@ -1476,6 +1588,8 @@
399 int active_thread_count = 0;
400 + int status = SERVER_DEAD;
401 + static apr_time_t maxed_out = 0;
403 /* initialize the free_list */
405 @@ -1487,7 +1601,6 @@
406 for (i = 0; i < ap_daemons_limit; ++i) {
407 /* Initialization to satisfy the compiler. It doesn't know
408 * that ap_threads_per_child is always > 0 */
409 - int status = SERVER_DEAD;
410 int any_dying_threads = 0;
411 int any_dead_threads = 0;
412 int all_dead_threads = 1;
413 @@ -1581,12 +1694,17 @@
414 /* Kill off one child */
415 ap_mpm_pod_signal(pod, TRUE);
419 else if (idle_thread_count < min_spare_threads) {
420 /* terminate the free list */
421 if (free_length == 0) {
422 /* only report this condition once */
423 static int reported = 0;
424 + static unsigned char sb_digest[APR_MD5_DIGESTSIZE];
425 + apr_time_t now = apr_time_now();
430 ap_log_error(APLOG_MARK, APLOG_ERR, 0,
431 @@ -1596,6 +1714,95 @@
436 + /* If after one maintenace interval we still see the same
437 + * situation on the scoreboard, shutdown all client sockets
438 + * in read state and at least 10% of all client sockets.
439 + * Crude, but seems to clear things out.
442 + apr_time_t diff = now - maxed_out;
444 + if (diff >= SCOREBOARD_MAINTENANCE_INTERVAL) {
445 + unsigned char cur_digest[APR_MD5_DIGESTSIZE];
447 + /* Current digest of the scoreboard.
449 + apr_md5_init(&ctx);
450 + for (i = 0; i < ap_daemons_limit; ++i) {
451 + for (j = 0; j < ap_threads_per_child; j++) {
452 + status = ap_scoreboard_image->servers[i][j].status;
453 + apr_md5_update(&ctx, &status, sizeof(status));
456 + pid = ap_scoreboard_image->parent[i].pid;
457 + apr_md5_update(&ctx, &pid, sizeof(pid));
459 + apr_md5_final(cur_digest, &ctx);
461 + /* If we haven't had a change for one maintenance
462 + * interval, we need to make room.
464 + if (memcmp(sb_digest, cur_digest, APR_MD5_DIGESTSIZE)) {
468 + /* Signal child processes to shutdown client sockets.
470 + for (i = 0; i < ap_daemons_limit; ++i) {
471 + pid = ap_scoreboard_image->parent[i].pid;
472 + ap_mpm_safe_kill(pid, SIGINT);
480 + /* Create digest of the scoreboard, see if things
481 + * change next time around.
483 + apr_md5_init(&ctx);
484 + for (i = 0; i < ap_daemons_limit; ++i) {
485 + for (j = 0; j < ap_threads_per_child; j++) {
486 + status = ap_scoreboard_image->servers[i][j].status;
488 + /* These are conditions we are concerned with.
491 + case SERVER_BUSY_READ:
492 + case SERVER_BUSY_KEEPALIVE:
494 + case SERVER_BUSY_WRITE:
496 + case SERVER_GRACEFUL:
502 + apr_md5_update(&ctx, &status, sizeof(status));
505 + pid = ap_scoreboard_image->parent[i].pid;
506 + apr_md5_update(&ctx, &pid, sizeof(pid));
508 + apr_md5_final(sb_digest, &ctx);
510 + /* Over 95% in read state (includes keep alive), clear now.
512 + if (ap_daemons_limit - rdrs < ap_daemons_limit / 20) {
513 + /* Signal child processes to shutdown client sockets.
515 + for (i = 0; i < ap_daemons_limit; ++i) {
516 + pid = ap_scoreboard_image->parent[i].pid;
517 + ap_mpm_safe_kill(pid, SIGINT);
526 if (free_length > idle_spawn_rate) {
527 @@ -1623,10 +1830,13 @@
528 else if (idle_spawn_rate < MAX_SPAWN_RATE) {
529 idle_spawn_rate *= 2;