I have a patch which I created to simulate users on slow or asymmetric
connections.  This patch adds two configuration settings to change the
speed of upload or download thru a tunnelling (CONNECT) proxy. 

It's a bit rough, but I wanted to get a general feel about it before I
do much more work refining it.  If people think it's useful, I'll do
whatever work is needed to make it clean enough to include in
mod_proxy.  Or somebody else can take the basic idea and do it a
better way; whatever you think is best.

In a nutshell, I replace send and recv in proxy_connect.c to calculate
a delay between reading chunks of data.  It's very much an
approximation, it doesn't simulate byte-by-byte throughput. 

One big problem I know is that it uses usleep(), which I don't think is
available on win32, and maybe not even all unix variants.

Anyway, here's the patch, I welcome any comments or feedback.  It's
off 1.3.22, but I don't think these files have changed much since then.

Thanks,

billo 
Intuit, Inc.  [EMAIL PROTECTED] [EMAIL PROTECTED]


--- /u/billo/src/apache_1.3.22/src/modules/proxy/mod_proxy.h    2001-10-05 
04:19:15.000000000 -0400
+++ ./mod_proxy.h       2002-05-15 18:31:48.201857000 -0400
@@ -224,6 +224,10 @@
     char viaopt_set;
     size_t recv_buffer_size;
     char recv_buffer_size_set;
+    int throttle_up_speed;     /* billo dial-up simulator */
+    char throttle_up_set;     /* billo dial-up simulator */
+    int throttle_down_speed;     /* billo dial-up simulator */
+    char throttle_down_set;     /* billo dial-up simulator */
 } proxy_server_conf;
 
 struct hdr_entry {
 
--- /u/billo/src/apache_1.3.22/src/modules/proxy/proxy_connect.c        
2001-10-05 04:19:15.000000000 -0400
+++ ./proxy_connect.c   2002-05-15 18:37:24.476203000 -0400
@@ -96,6 +96,46 @@
  * FIXME: no check for r->assbackwards, whatever that is.
  */
 
+static useconds_t sleep_calc(int speed, int len)
+{
+    useconds_t delay;
+    if (speed == 0) {    
+        return 0;
+    }
+    delay =  1000000 / (speed / 8);
+    
+    delay = delay * len;
+
+    return delay;
+}
+
+static ssize_t proxy_recv(int s, void *buf, size_t len, int flags, int choke, 
request_rec *r)
+{
+   if (choke > 0) {
+       ssize_t ret = recv(s, buf, len, flags);
+       useconds_t delay = sleep_calc(choke, ret);
+       /* ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: billo proxy recv 
delay %d",  delay); */
+       usleep(delay);
+       return ret;
+    } else {
+        return recv(s, buf, len, flags);
+    }
+}
+
+static ssize_t proxy_send(int s, void *buf, size_t len, int flags, int choke, 
request_rec *r)
+{
+    /* ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: billo proxy send"); */
+    if (choke > 0) {
+        ssize_t ret = send(s, buf, len, flags);
+        useconds_t delay = sleep_calc(choke, ret);
+        usleep(delay);
+        return ret;
+    } else {
+        return send(s, buf, len, flags);
+    }
+}
+
+
 static int
 allowed_port(proxy_server_conf *conf, int port)
 {
@@ -109,6 +149,7 @@
     return 0;
 }
 
+#define CONNECT_BUFFER_SIZE 256
 
 int ap_proxy_connect_handler(request_rec *r, cache_req *c, char *url,
                          const char *proxyhost, int proxyport)
@@ -119,8 +160,10 @@
     const char *host, *err;
     char *p;
     int port, sock;
-    char buffer[HUGE_STRING_LEN];
+    char buffer[CONNECT_BUFFER_SIZE];
     int nbytes, i, j;
+    int throttle_up = 0;
+    int throttle_down = 0;
     fd_set fds;
 
     void *sconf = r->server->module_config;
@@ -128,6 +171,12 @@
     (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
     struct noproxy_entry *npent = (struct noproxy_entry *) 
conf->noproxies->elts;
 
+    if (conf->throttle_up_set) {
+        throttle_up = conf->throttle_up_speed;
+    }
+    if (conf->throttle_down_set) {
+        throttle_down = conf->throttle_down_speed;
+    }
     memset(&server, '\0', sizeof(server));
     server.sin_family = AF_INET;
 
@@ -260,10 +309,10 @@
        if (i) {
            if (FD_ISSET(sock, &fds)) {
                ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r->server, 
"sock was set");
-               if ((nbytes = recv(sock, buffer, HUGE_STRING_LEN,0)) != 0) {
+               if ((nbytes = proxy_recv(sock, buffer, CONNECT_BUFFER_SIZE, 0, 
throttle_down, r)) != 0) {
                    if (nbytes == -1)
                        break;
-                   if (send(ap_bfileno(r->connection->client, B_WR), buffer, 
nbytes,0) == EOF)
+                   if (proxy_send(ap_bfileno(r->connection->client, B_WR), 
buffer, nbytes,0, throttle_down, r) == EOF)
                        break;
                    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 
r->server, "Wrote %d bytes to client", nbytes);
                }
@@ -272,11 +321,11 @@
            }
            else if (FD_ISSET(ap_bfileno(r->connection->client, B_WR), &fds)) {
                ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r->server, 
"client->fd was set");
-               if ((nbytes = recv(ap_bfileno(r->connection->client, B_WR), 
buffer,
-                                  HUGE_STRING_LEN, 0)) != 0) {
+               if ((nbytes = proxy_recv(ap_bfileno(r->connection->client, 
B_WR), buffer,
+                                  CONNECT_BUFFER_SIZE, 0, throttle_up, r)) != 
0) {
                    if (nbytes == -1)
                        break;
-                   if (send(sock, buffer, nbytes, 0) == EOF)
+                   if (proxy_send(sock, buffer, nbytes, 0, throttle_up, r) == 
EOF)
                        break;
                    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 
r->server, "Wrote %d bytes to server", nbytes);
                }
@@ -294,3 +343,4 @@
 
     return OK;
 }
+
--- /u/billo/src/apache_1.3.22/src/modules/proxy/mod_proxy.c    2001-09-24 
16:14:27.000000000 -0400
+++ ./mod_proxy.c       2002-05-17 10:45:04.454437000 -0400
@@ -442,6 +507,10 @@
     ps->cache.dirlength_set = 0;
     ps->cache.cache_completion = DEFAULT_CACHE_COMPLETION;
     ps->cache.cache_completion_set = 0;
+    ps->throttle_up_speed = 0; /* default no choke billo 10-may-2002 */
+    ps->throttle_up_set = 0; /* default no choke billo 10-may-2002 */
+    ps->throttle_down_speed = 0; /* default no choke billo 10-may-2002 */
+    ps->throttle_down_set = 0; /* default no choke billo 10-may-2002 */
 
     return ps;
 }
@@ -842,6 +917,31 @@
     return NULL;
 }
 
+
+static const char *
+     set_throttle_up_speed(cmd_parms *parms, void *dummy, char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+    int s = atoi(arg);
+
+    psf->throttle_up_speed = s;
+    psf->throttle_up_set = 1;
+    return NULL;
+}
+
+static const char *
+     set_throttle_down_speed(cmd_parms *parms, void *dummy, char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+    int s = atoi(arg);
+
+    psf->throttle_down_speed = s;
+    psf->throttle_down_set = 1;
+    return NULL;
+}
+
 static const char*
     set_cache_completion(cmd_parms *parms, void *dummy, char *arg)
 {
@@ -903,6 +1003,10 @@
      "A list of names, hosts or domains to which the proxy will not connect"},
     {"ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF, TAKE1,
      "Receive buffer size for outgoing HTTP and FTP connections in bytes"},
+    {"ProxyConnectThrottleUp", set_throttle_up_speed, NULL, RSRC_CONF, TAKE1,
+     "Reduce throughput of connect proxy (upload direction)"},
+    {"ProxyConnectThrottleDown", set_throttle_down_speed, NULL, RSRC_CONF, 
TAKE1,
+     "Reduce throughput of connect proxy (download direction)"},
     {"NoProxy", set_proxy_dirconn, NULL, RSRC_CONF, ITERATE,
      "A list of domains, hosts, or subnets to which the proxy will connect 
directly"},
     {"ProxyDomain", set_proxy_domain, NULL, RSRC_CONF, TAKE1,

Reply via email to