Rather ugly, but in the http module rather than mpm. Still needs some work but works in most cases here. I think there are instances where an aborted connection will not decrement the count, maybe. Had to add configuration stuff to http_core, since it, wrongly in my opinion, uses the core server config structures.

Patch is against 2.2.3, since that's what we run mostly around here.

--
Brian Akins
Chief Operations Engineer
Turner Digital Media Technologies
diff -ur httpd-2.2.3/include/http_core.h 
httpd-2.2.3-keepalive/include/http_core.h
--- httpd-2.2.3/include/http_core.h     2006-07-11 23:38:44.000000000 -0400
+++ httpd-2.2.3-keepalive/include/http_core.h   2006-11-15 15:26:14.000000000 
-0500
@@ -682,6 +682,8 @@
 
 /* ---------------------------------------------------------------------- */
 
+AP_DECLARE(int) ap_can_keepalive(request_rec *r);
+
 #ifdef __cplusplus
 }
 #endif
diff -ur httpd-2.2.3/modules/http/http_core.c 
httpd-2.2.3-keepalive/modules/http/http_core.c
--- httpd-2.2.3/modules/http/http_core.c        2006-07-24 09:34:19.000000000 
-0400
+++ httpd-2.2.3-keepalive/modules/http/http_core.c      2006-11-15 
17:20:25.000000000 -0500
@@ -35,6 +35,8 @@
 
 #include "mod_core.h"
 
+module AP_MODULE_DECLARE_DATA http_module;
+
 /* Handles for core filters */
 AP_DECLARE_DATA ap_filter_rec_t *ap_http_input_filter_handle;
 AP_DECLARE_DATA ap_filter_rec_t *ap_http_header_filter_handle;
@@ -42,6 +44,28 @@
 AP_DECLARE_DATA ap_filter_rec_t *ap_http_outerror_filter_handle;
 AP_DECLARE_DATA ap_filter_rec_t *ap_byterange_filter_handle;
 
+
+typedef struct {
+    int maxkaconn;
+} http_core_conf_t;
+
+static apr_uint32_t current_ka = 0;
+
+static void *create_http_conf(apr_pool_t * p, server_rec *s)
+{
+    http_core_conf_t *conf = apr_pcalloc(p, sizeof(http_core_conf_t));
+    return conf;
+}
+
+static const char *set_maxkaconn(cmd_parms *cmd, void *dummy,
+                                 const char *arg)
+{
+    http_core_conf_t *conf 
+        = ap_get_module_config(cmd->server->module_config, &http_module);
+    conf->maxkaconn = atoi(arg);
+    return NULL;
+}
+
 static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
                                           const char *arg)
 {
@@ -94,6 +118,9 @@
                   "or 0 for infinite"),
     AP_INIT_TAKE1("KeepAlive", set_keep_alive, NULL, RSRC_CONF,
                   "Whether persistent connections should be On or Off"),
+    AP_INIT_TAKE1("MaxKeepAliveConnections", set_maxkaconn, NULL, GLOBAL_ONLY,
+                  "Maximum number of Keep-Alive connections per child, "
+                  "or 0 for infinite"),
     { NULL }
 };
 
@@ -206,9 +233,43 @@
     return OK;
 }
 
+AP_DECLARE(int) ap_can_keepalive(request_rec *r) {
+    http_core_conf_t *conf 
+        = ap_get_module_config(r->server->module_config, &http_module);
+    apr_uint32_t current;
+
+    if(conf->maxkaconn) {
+        current = apr_atomic_read32(&current_ka);
+        
+        if(current >= conf->maxkaconn) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+static apr_status_t keepalive_cleanup(void *data)
+{
+    conn_rec *c = (conn_rec *)data;
+
+    /*need to check for abort??  Also, what happens when client closes and we 
are in keepalive?
+     * should we register a cleanup on connection pool?
+     */
+    if(c->keepalive == AP_CONN_KEEPALIVE) {
+        apr_atomic_inc32(&current_ka);
+    }
+
+    return APR_SUCCESS;
+}
+
 static int http_create_request(request_rec *r)
 {
     if (!r->main && !r->prev) {
+        conn_rec *c = r->connection;
+         http_core_conf_t *conf 
+             = ap_get_module_config(r->server->module_config, &http_module);
+         
         ap_add_output_filter_handle(ap_byterange_filter_handle,
                                     NULL, r, r->connection);
         ap_add_output_filter_handle(ap_content_length_filter_handle,
@@ -217,6 +278,15 @@
                                     NULL, r, r->connection);
         ap_add_output_filter_handle(ap_http_outerror_filter_handle,
                                     NULL, r, r->connection);
+
+        if(conf->maxkaconn) {
+            /*this connection had been kept alive, but it's now "active" 
again*/
+            if(c->keepalive == AP_CONN_KEEPALIVE) {
+                apr_atomic_dec32(&current_ka);
+            }
+            apr_pool_cleanup_register(r->pool, c, keepalive_cleanup,
+                                      keepalive_cleanup);
+        }
     }
 
     return OK;
@@ -265,7 +335,7 @@
     STANDARD20_MODULE_STUFF,
     NULL,              /* create per-directory config structure */
     NULL,              /* merge per-directory config structures */
-    NULL,              /* create per-server config structure */
+    create_http_conf,  /* create per-server config structure */
     NULL,              /* merge per-server config structures */
     http_cmds,         /* command apr_table_t */
     register_hooks     /* register hooks */
diff -ur httpd-2.2.3/modules/http/http_protocol.c 
httpd-2.2.3-keepalive/modules/http/http_protocol.c
--- httpd-2.2.3/modules/http/http_protocol.c    2006-07-11 23:38:44.000000000 
-0400
+++ httpd-2.2.3-keepalive/modules/http/http_protocol.c  2006-11-15 
15:21:18.000000000 -0500
@@ -157,6 +157,15 @@
  */
 #define METHOD_NUMBER_LAST  62
 
+static int can_it_keepalive(request_rec *r) {
+    if(!ap_can_keepalive(r)) {
+        ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
+                     "Maximum keepalive connections reached");
+        return 0;
+    } else {
+        return 1;
+    }
+}
 
 AP_DECLARE(int) ap_set_keepalive(request_rec *r)
 {
@@ -212,9 +221,9 @@
         && (!apr_table_get(r->subprocess_env, "nokeepalive")
             || apr_table_get(r->headers_in, "Via"))
         && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive"))
-            || (r->proto_num >= HTTP_VERSION(1,1)))) {
+            || (r->proto_num >= HTTP_VERSION(1,1))) && can_it_keepalive(r)) {
         int left = r->server->keep_alive_max - r->connection->keepalives;
-
+        
         r->connection->keepalive = AP_CONN_KEEPALIVE;
         r->connection->keepalives++;
 

Reply via email to