This is a multi-part message in MIME format.
--------------2CFF1B1D14F41B9A5DA44F7F
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Here is a polished and updated test suite a bit..
* pconn-banger reports a throughtput report, like tcp-banger2
* both tools include support to validate size and a simple checksum
* A couple of pconn-banger bugs fixed.
* Wrote a small perl script that joins a URL list, and a size-checksum
report from tcp-banger to a combined list (needed to use the validation
feature).
Syntax for URL lists is eiter plain 1 URL/line, or
METHOD URL [Request-File|-] [size checksum]
The tools can send HTTP requests with any method or request-body, but
they do not (yet) support HEAD replies.
Both read the list of requests from stdin.
pconn-banger options:
-p port			Port of proxy/server (default 3128)
-h serveraddr		IP address of proxy/server (default 127.0.0.1)
-n max_outstanding	Number of outstanding pipelined requests
-i			Use IMS (random times)
-t tracefile		Save all replies to a trace file
-r			Don't reopen the connection when closed
-c			Validate checksum
tcp-banger2 options:
-p port			Port of proxy/server (default 3128)
-h serveraddr		IP address of proxy/server (default 127.0.0.1)
-n max_connections	Number simoultaneous requests/connections
-i			Use IMS (random times)
-c			Validate checksum
-l lifetime		Connection lifetime
/Henrik
--------------2CFF1B1D14F41B9A5DA44F7F
Content-Type: text/plain; charset=us-ascii; name="squid-1.2.beta20-1.test_suite.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="squid-1.2.beta20-1.test_suite.patch"
Index: squid/test-suite/Makefile
diff -u squid/test-suite/Makefile:1.1.1.1 squid/test-suite/Makefile:1.1.1.1.10.1
--- squid/test-suite/Makefile:1.1.1.1	Sun Mar  8 15:46:55 1998
+++ squid/test-suite/Makefile	Wed Apr 29 22:18:25 1998
@@ -1,5 +1,5 @@
 CC	= gcc
-CFLAGS	= -O3 -DWITH_LIB
+CFLAGS	= -O3 -I../include -I../src
 OBJS	= membanger.o hash.o SizeToPool.o
 LIB	= -L. -lMem
 TARGLIB = libMem.a
Index: squid/test-suite/pconn-banger.c
diff -u squid/test-suite/pconn-banger.c:1.1.1.5 squid/test-suite/pconn-banger.c:1.1.1.5.16.3
--- squid/test-suite/pconn-banger.c:1.1.1.5	Thu Feb  5 22:45:12 1998
+++ squid/test-suite/pconn-banger.c	Mon May  4 21:19:52 1998
@@ -86,6 +86,9 @@
 #if HAVE_ASSERT_H
 #include <assert.h>
 #endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
 
 #define PROXY_PORT 3128
 #define PROXY_ADDR "127.0.0.1"
@@ -99,20 +102,27 @@
 static int noutstanding = 0;
 static int done_reading_urls = 0;
 static int opt_ims = 0;
-static int max_connections = 64;
+static int opt_checksum = 0;
+static int opt_reopen = 1;
+static int max_outstanding = 10;
 static time_t lifetime = 60;
 static const char *const crlf = "\r\n";
+static int trace_fd = -1;
+static int total_bytes_read = 0;
 
 #define REPLY_HDR_SZ 8192
 
 struct _r {
-    char *url;
+    char url[1024];
     int content_length;
     int hdr_length;
     int hdr_offset;
     int bytes_read;
     char reply_hdrs[REPLY_HDR_SZ];
     struct _r *next;
+    long sum;
+    long validsize;
+    long validsum;
 };
 
 static struct _r *Requests;
@@ -151,11 +161,13 @@
 void
 sig_intr(int sig)
 {
-    printf("\rWaiting for open connections to finish...\n");
+    fprintf(stderr, "\rWaiting for open connections to finish...\n");
     signal(sig, SIG_DFL);
+    done_reading_urls = 1;
 }
 
 int
+
 open_http_socket(void)
 {
     int s;
@@ -177,37 +189,90 @@
 }
 
 int
-send_request(int fd, const char *url)
+send_request(int fd, const char *data)
 {
-    char buf[4096];
+    char msg[4096],buf[4096];
     int len;
     time_t w;
     struct _r *r;
     struct _r **R;
-    buf[0] = '\0';
-    strcat(buf, "GET ");
-    strcat(buf, url);
-    strcat(buf, " HTTP/1.0\r\n");
-    strcat(buf, "Accept: */*\r\n");
-    strcat(buf, "Proxy-Connection: Keep-Alive\r\n");
+    char *method, *url, *file, *size, *checksum;
+    char *tmp = strdup(data);
+    struct stat st;
+    int file_fd = -1;
+    method=strtok(tmp, " ");
+    url=strtok(NULL, " ");
+    file=strtok(NULL, " ");
+    size=strtok(NULL, " ");
+    checksum=strtok(NULL, " ");
+    if (!url) {
+      url=method;
+      method="GET";
+    }
+    if (file && strcmp(file,"-")==0)
+	file=NULL;
+    if (size && strcmp(size,"-")==0)
+	size=NULL;
+    if (checksum && strcmp(checksum,"-")==0)
+	checksum=NULL;
+    msg[0] = '\0';
+    sprintf(buf, "%s %s HTTP/1.0\r\n", method, url);
+    strcat(msg,buf);
+    strcat(msg, "Accept: */*\r\n");
+    strcat(msg, "Proxy-Connection: Keep-Alive\r\n");
     if (opt_ims && (lrand48() & 0x03) == 0) {
         w = time(NULL) - (lrand48() & 0x3FFFF);
-	strcat(buf, "If-Modified-Since: ");
-	strcat(buf, mkrfc850(&w));
-	strcat(buf, "\r\n");
-    }
-    strcat(buf, "\r\n");
-    len = strlen(buf);
-    if (write(fd, buf, len) < 0) {
+	sprintf(buf, "If-Modified-Since: %s\r\n", mkrfc850(&w));
+	strcat(msg, buf);
+    }
+    if (file) {
+	if ( (file_fd = open(file,O_RDONLY)) < 0) {
+	    perror("open");
+	    return -1;
+	}
+	if ( fstat(file_fd, &st) ) {
+	    perror("fstat");
+	    close(file_fd);
+	    return -1;
+	}
+	sprintf(buf, "Content-length: %d\r\n", st.st_size);
+	strcat(msg, buf);
+    }
+    strcat(msg, "\r\n");
+    len = strlen(msg);
+    if (write(fd, msg, len) < 0) {
         close(fd);
-	perror("write");
+	perror("request write");
+	close(file_fd);
         return -1;
     }
+    if (file) {
+	while((len=read(file_fd, buf, sizeof buf)) > 0) {
+	    if (write(fd, buf, len) < 0) {
+		close(fd);
+		perror("body write");
+		close(file_fd);
+		return -1;
+	    }
+	}
+	if (len < 0) {
+	    perror("file read");
+	    close(file_fd);
+	    return -1;
+	}
+	close(file_fd);
+    }
     r = calloc(1, sizeof(struct _r));
-    r->url = strdup(url);
+    strcpy(r->url, url);
+    if (size)
+	r->validsize = atoi(size);
+    else
+	r->validsize = -1;
+    if (checksum)
+	r->validsum = atoi(checksum);
     for (R = &Requests; *R; R = &(*R)->next);
     *R = r;
-    fprintf(stderr, "REQUESTED %s\n", url);
+/*    fprintf(stderr, "REQUESTED %s\n", url); */
     noutstanding++;
     return 0;
 }
@@ -224,63 +289,153 @@
             return atoi(t);
         }
     }
-    return 0;
+    return -1;
+}
+
+static const char *
+get_header_string_value(const char *hdr, const char *buf, const char *end)
+{
+    const char *t;
+    static char result[8192];
+    for (t = buf; t < end; t += strcspn(t, crlf), t += strspn(t, crlf)) {
+	if (strncasecmp(t, hdr, strlen(hdr)) == 0) {
+	    t += strlen(hdr);
+	    while (isspace(*t))
+		t++;
+	    strcpy(result,"");
+	    strncat(result,t,strcspn(t, crlf));
+	    return result;
+	}
+    }
+    return NULL;
 }
 
+void
+request_done(struct _r *r)
+{
+#if 0
+    fprintf(stderr, "DONE: %s, (%d+%d)\n",
+	    r->url,
+	    r->hdr_length,
+	    r->content_length);
+#endif
+    if (r->content_length != r->bytes_read)
+	fprintf(stderr, "ERROR! Short reply, expected %d bytes got %d\n",
+	    r->content_length, r->bytes_read);
+    else if (r->validsize >= 0) {
+	if (r->validsize != r->bytes_read)
+	    fprintf(stderr, "WARNING: %s Object size mismatch, expected %d got %d\n",
+		    r->url, r->validsize, r->bytes_read);
+	else if (opt_checksum && r->sum != r->validsum)
+	    fprintf(stderr, "WARNING: %s Checksum error. Expected %d got %d\n",
+		    r->url, r->validsum, r->sum);
+    }
+}
 int
-handle_read(char *buf, int len)
+handle_read(char *inbuf, int len)
 {
     struct _r *r = Requests;
     const char *end;
-    int hlen;
-    if (len < 0) {
+    const char *url;
+    static char buf[READ_BUF_SZ];
+    int hlen,blen;
+    if (len < 0 ) {
         perror("read");
         Requests = r->next;
+	request_done(r);
         free(r);
         noutstanding--;
+	if (trace_fd >= 0)
+	    write(trace_fd,"\n[CLOSED]\n",10);
         return -1;
     }
+    total_bytes_read += len;
+    xmemcpy(buf,inbuf,len);
     if (len == 0) {
-	fprintf(stderr, "DONE: %s, server closed socket, read %d bytes\n", r->url, r->bytes_read);
+	fprintf(stderr, "WARNING: %s, server closed socket after %d+%d bytes\n", r->url, r->hdr_offset, r->bytes_read);
+	/* XXX, If no data was received and it isn't the first request on this
+	 * connection then the request should be restarted rather than aborted
+	 * but this is a simple test program an not a full blown HTTP client.
+	 */
+	request_done(r);
         Requests = r->next;
         free(r);
         noutstanding--;
         return -1;
     }
-    if (r->hdr_length == 0) {
-	hlen = min(len, REPLY_HDR_SZ - r->hdr_length);
-	strncpy(r->reply_hdrs + r->hdr_length, buf, hlen);
-	r->hdr_offset += hlen;
-	*(r->reply_hdrs + REPLY_HDR_SZ - 1) = '\0';
-    }
-    if (r->hdr_length == 0 && (end = mime_headers_end(r->reply_hdrs)) != NULL) {
-	fprintf(stderr, "FOUND EOH FOR %s\n", r->url);
-	r->hdr_length = end - r->reply_hdrs;
-	fprintf(stderr, "HDR_LENGTH = %d\n", r->hdr_length);
-	r->content_length = get_header_int_value("content-length:", r->reply_hdrs, end);
-	fprintf(stderr, "CONTENT_LENGTH = %d\n", r->content_length);
-    }
-    if (r->content_length && r->hdr_length) {
-	int bytes_left = r->content_length + r->hdr_length - r->bytes_read;
-	int bytes_used = len > bytes_left ? bytes_left : len;
-	r->bytes_read += bytes_used;
-	len -= bytes_used;
-	if (r->bytes_read == r->content_length + r->hdr_length) {
-	    fprintf(stderr, "DONE: %s, (%d == %d+%d)\n",
-		r->url,
-		r->bytes_read,
-		r->hdr_length,
-		r->content_length);
-	    Requests = r->next;
-	    free(r);
-	    noutstanding--;
-	} else {
-	    assert(r->bytes_read < r->content_length + r->hdr_length);
+    if (trace_fd > 0)
+	write(trace_fd, buf, len);
+    while (len > 0) {
+	/* Build headers */
+	if (r->hdr_length == 0) {
+	    hlen = min(len, REPLY_HDR_SZ - r->hdr_offset - 1);
+	    xmemcpy(r->reply_hdrs + r->hdr_offset, buf, hlen);
+	    r->hdr_offset += hlen;
+	    r->reply_hdrs[r->hdr_offset] = '\0';
+	    len -= hlen;
+	    /* Save any remaining read data */
+	    xmemmove(buf, buf + hlen, len);
+	}
+	/* Process headers */
+	if (r->hdr_length == 0 && (end = mime_headers_end(r->reply_hdrs)) != NULL) {
+#if 0
+	    fprintf(stderr, "FOUND EOH FOR %s\n", r->url); */
+#endif
+	    r->hdr_length = end - r->reply_hdrs;
+#if 0
+ 	    fprintf(stderr, "HDR_LENGTH = %d\n", r->hdr_length);
+#endif
+	    /* "unread" any body contents received */
+	    blen = r->hdr_offset - r->hdr_length;
+	    assert(blen >= 0);
+	    if (blen > 0) {
+		xmemmove(buf + blen, buf, len);
+		xmemcpy(buf, r->reply_hdrs + r->hdr_length, blen);
+		len += blen;
+	    }
+	    r->reply_hdrs[r->hdr_length]='\0'; /* Null terminate headers */
+	    /* Parse headers */
+	    r->content_length = get_header_int_value("content-length:", r->reply_hdrs, end);
+/*	    fprintf(stderr, "CONTENT_LENGTH = %d\n", r->content_length); */
+	    url = get_header_string_value("X-Request-URI:", r->reply_hdrs, end);
+	    if (url != NULL && strcmp(r->url, url) != 0)
+		fprintf(stderr, "WARNING: %s got reply %s\n", r->url, url);
+#if XREQUESTURI || 0
+	    fprintf(stderr, "LOCATION = %s\n", get_header_string_value("X-Request-URI:", r->reply_hdrs, end));  
+#endif
         }
-	if (len) {
-	    assert(bytes_used > 0);
+	if ( !(len==0 || r->hdr_length > 0) ) {
+	    fprintf(stderr, "ERROR!!!\n");
+	    assert((len==0 || r->hdr_length > 0));
+	}
+	/* Process body */
+	if (r->hdr_length != 0) {
+	    int i;
+	    int bytes_left, bytes_used;
+	    if (r->content_length >= 0) {
+		bytes_left = r->content_length - r->bytes_read;
+		assert(bytes_left >= 0);
+	    	bytes_used = len < bytes_left ? len : bytes_left;
+	    } else {
+		bytes_left = len + 1; /* Unknown end... */
+		bytes_used = len;
+	    }
+	    if (opt_checksum) {
+		for(i=0; i<bytes_used; i++)
+		    r->sum += (int)buf[i] & 0xFF;
+	    }
+	    r->bytes_read += bytes_used;
+	    len -= bytes_used;
+	    if (bytes_left == bytes_used) {
+		request_done(r);
+		Requests = r->next;
+		free(r);
+		noutstanding--;
+		r = Requests;
+	    } else {
+		assert(r->bytes_read < r->content_length);
+	    }
             xmemmove(buf, buf + bytes_used, len);
-	    return handle_read(buf, len);
         }
     }
     return 0;
@@ -294,8 +449,10 @@
     int x;
     len = read(fd, buf, READ_BUF_SZ);
     x = handle_read(buf, len);
-    if (x < 0)
+    if (x < 0) {
+	perror("read reply");
         close(fd);
+    }
     return x;
 }
 
@@ -305,21 +462,28 @@
     static int pconn_fd = -1;
     static char buf[8192];
     struct timeval to;
+    struct timeval now,last,start;
     fd_set R;
     struct _r *r;
     struct _r *nextr;
     int x;
     int timeouts;
+    int nrequests = 0, rrequests = 0, reqpersec = 0;
+
+    gettimeofday(&start, NULL);
+    last = start;
+
+    pconn_fd = open_http_socket();
+    if (pconn_fd < 0) {
+	perror("socket");
+	exit(1);
+    }
     while (!done_reading_urls || noutstanding) {
-	if (timeouts == 20) {
-	    close(pconn_fd);
-	    pconn_fd = -1;
-	    r = Requests;
-	    Requests = Requests->next;
-	    free(r);
-	    noutstanding--;
+	if (!opt_reopen && pconn_fd < 0) {
+	    fprintf(stderr,"TERMINATED: Connection closed\n");
+	    break;
         }
-	if (pconn_fd < 0) {
+	if (pconn_fd<0) {
             pconn_fd = open_http_socket();
             if (pconn_fd < 0) {
                 perror("socket");
@@ -327,24 +491,52 @@
             }
             nextr = Requests;
             Requests = NULL;
+	    noutstanding=0;
             while ((r = nextr) != NULL) {
                 nextr = r->next;
-		send_request(pconn_fd, r->url);
+		if (send_request(pconn_fd, r->url) != 0) {
+		    close(pconn_fd);
+		    pconn_fd=-1;
+		    nextr = r;
+		    for (r = Requests; r!=NULL && r->next; r=r->next);
+		    if (r != NULL)
+			r->next = nextr;
+		    else
+			Requests = nextr;
+		    break;
+		}
                 free(r);
-		noutstanding--;
             }
             timeouts = 0;
+	    if (pconn_fd <0)
+		continue;
         }
-	if (noutstanding < 10 && !done_reading_urls) {
+	if (timeouts == 200) {
+	    close(pconn_fd);
+	    pconn_fd = -1;
+	    r = Requests;
+	    Requests = Requests->next;
+	    fprintf(stderr, "ABORT %s\n", Requests->url);
+	    free(r);
+	    noutstanding--;
+	}
+	if (pconn_fd>=0 && noutstanding < max_outstanding && !done_reading_urls) {
             char *t;
             if (fgets(buf, 8191, stdin) == NULL) {
-		printf("Done Reading URLS\n");
+		fprintf(stderr, "Done Reading URLS\n");
                 done_reading_urls = 1;
-		break;
+		continue;
             }
+	    rrequests++;
             if ((t = strchr(buf, '\n')))
                 *t = '\0';
-	    send_request(pconn_fd, buf);
+	    if (send_request(pconn_fd, buf) != 0) {
+		close(pconn_fd);
+		pconn_fd=-1;
+		continue;
+	    }
+	    nrequests++;
+	    reqpersec++;
             timeouts = 0;
         }
         FD_ZERO(&R);
@@ -367,13 +559,31 @@
             if (read_reply(pconn_fd) != 0)
                 pconn_fd = -1;
         }
+	gettimeofday(&now, NULL);
+        if (now.tv_sec > last.tv_sec) {
+	    int dt;
+	    int nreq;
+	    last = now;
+	    dt = (int) (now.tv_sec - start.tv_sec);
+	    nreq=0;
+	    for (r=Requests; r ; r=r->next) nreq++;
+	    printf("T+ %6d: %9d req (%+4d), %4d pend, %3d/sec avg, %dmb, %dkb/sec avg\n",
+		    dt,
+		    nrequests,
+		    reqpersec,
+		    nreq,
+		    (int) (nrequests / dt),
+		    (int)total_bytes_read / 1024 / 1024,
+		    (int)total_bytes_read / 1024 / dt);
+	    reqpersec = 0;
+	}
     }
 }
 
 void
 usage(void)
 {
-    fprintf(stderr, "usage: %s: -p port -h host -n max\n", progname);
+    fprintf(stderr, "usage: %s: -p port -h host -n max -t tracefile -i -c -l lifetime\n", progname);
 }
 
 int
@@ -385,7 +595,7 @@
     setbuf(stdout, NULL);
     setbuf(stderr, NULL);
     progname = strdup(argv[0]);
-    while ((c = getopt(argc, argv, "p:h:n:il:")) != -1) {
+    while ((c = getopt(argc, argv, "p:h:n:t:icl:r")) != -1) {
         switch (c) {
         case 'p':
             proxy_port = atoi(optarg);
@@ -394,13 +604,22 @@
             proxy_addr = strdup(optarg);
             break;
         case 'n':
-	    max_connections = atoi(optarg);
+	    max_outstanding = atoi(optarg);
             break;
         case 'i':
             opt_ims = 1;
             break;
+	case 'c':
+	    opt_checksum = 1;
+	    break;
         case 'l':
             lifetime = (time_t) atoi(optarg);
+	    break;
+	case 't':
+	    trace_fd = open(optarg,O_WRONLY|O_CREAT|O_TRUNC,0666);
+	    break;
+	case 'r':
+	    opt_reopen = !opt_reopen;
             break;
         default:
             usage();
Index: squid/test-suite/tcp-banger2.c
diff -u squid/test-suite/tcp-banger2.c:1.1.1.3 squid/test-suite/tcp-banger2.c:1.1.1.3.22.2
--- squid/test-suite/tcp-banger2.c:1.1.1.3	Fri Jan  2 11:58:15 1998
+++ squid/test-suite/tcp-banger2.c	Mon May  4 21:19:53 1998
@@ -76,6 +76,12 @@
 #if HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_ASSERT_H
+#include <assert.h>
+#endif
 
 #define PROXY_PORT 3128
 #define PROXY_ADDR "127.0.0.1"
@@ -91,14 +97,29 @@
 static int max_connections = 64;
 static time_t lifetime = 60;
 static struct timeval now;
+static long total_bytes_written = 0;
+static long total_bytes_read = 0;
+static int opt_checksum = 0;
 
 typedef void (CB) (int, void *);
 
 struct _f {
     CB *cb;
+    CB *ccb;
     void *data;
     time_t start;
 };
+struct _request {
+    int fd;
+    char url[8192];
+    char buf[READ_BUF_SZ * 2 + 1];
+    int headfound;
+    long validsize;
+    long validsum;
+    long bodysize;
+    long sum;
+    int content_length;
+};
 
 struct _f FD[MAX_FDS];
 int nfds = 0;
@@ -120,6 +141,9 @@
 fd_close(int fd)
 {
     close(fd);
+    if (FD[fd].ccb)
+	FD[fd].ccb(fd, FD[fd].data);
+    FD[fd].ccb = NULL;
     FD[fd].cb = NULL;
     FD[fd].data = NULL;
     nfds--;
@@ -131,9 +155,10 @@
 }
 
 void
-fd_open(int fd, CB * cb, void *data)
+fd_open(int fd, CB * cb, void *data, CB *ccb)
 {
     FD[fd].cb = cb;
+    FD[fd].ccb = ccb;
     FD[fd].data = data;
     FD[fd].start = now.tv_sec;
     if (fd > maxfd)
@@ -145,6 +170,7 @@
 sig_intr(int sig)
 {
     fd_close(0);
+    nfds++;
     printf("\rWaiting for open connections to finish...\n");
     signal(sig, SIG_DFL);
 }
@@ -152,26 +178,104 @@
 void
 read_reply(int fd, void *data)
 {
-    static char buf[READ_BUF_SZ];
-    if (read(fd, buf, READ_BUF_SZ) <= 0) {
+    struct _request *r = data;
+    static unsigned char buf[READ_BUF_SZ];
+    int len;
+    char *p;
+    if ((len=read(fd, buf, READ_BUF_SZ)) <= 0) {
         fd_close(fd);
         reqpersec++;
         nrequests++;
+    } else {
+	int used=0;
+	total_bytes_read+=len;
+	if (r->headfound < 2) {
+	    char *p,*header = NULL;
+	    int oldlen = strlen(r->buf);
+	    int newlen = oldlen + len;
+	    assert(oldlen <= READ_BUF_SZ);
+	    memcpy(r->buf+oldlen, buf, len);
+	    r->buf[newlen+1]='\0';
+	    for(p=r->buf; r->headfound < 2 && used<newlen; p++,used++) {
+		switch(*p) {
+		case '\n':
+		    r->headfound++;
+		    if (header) {
+			/* Decode header */
+			if (strncasecmp(header,"Content-Length:",15)==0)
+			    r->content_length = atoi(header+15);
+			if (strncasecmp(header,"X-Request-URI:",14)==0) {
+			    /* Check URI */
+			    if (strncmp(r->url, header+15, strcspn(header+15,"\r\n"))) {
+				char url[8192];
+				strncpy(url, header+15, strcspn(header+15,"\r\n"));
+				url[strcspn(header+15, "\r\n")]='\n';
+				fprintf(stderr,"ERROR: Sent %s received %s\n",
+					r->url, url);
+			    }
+			}
+			header=NULL;
+		    }
+		    break;
+		case '\r':
+		    break;
+		default:
+		    r->headfound=0;
+		    if (!header)
+			header = p;
+		    break;
+		}
+	    }
+	    if (header) {
+		memmove(r->buf, header, newlen - (header - r->buf) + 1);
+	    }
+	}
+	r->bodysize+=len-used;
+	if (opt_checksum) {
+	    for (; used<len ; used++) {
+		r->sum += buf[used];
+	    }
+	}
     }
 }
 
-int
-request(url)
-     char *url;
+void
+reply_done(int fd, void *data)
 {
-    int s;
+    struct _request *r = data;
+    if (r->bodysize != r->content_length)
+	fprintf(stderr,"ERROR: %s expected %d bytes got %d\n",
+		r->url, r->content_length, r->bodysize);
+    else if (r->validsize >= 0) {
+	if (r->validsize != r->bodysize)
+	    fprintf(stderr,"WARNING: %s size mismatch wanted %d bytes got %d\n",
+		    r->url, r->validsize, r->bodysize);
+	else if (opt_checksum && r->validsum != r->sum)
+	    fprintf(stderr,"WARNING: %s invalid checksum wanted %d got %d\n",
+		    r->url, r->validsum, r->sum);
+    } else if (opt_checksum) {
+	fprintf(stderr,"DONE: %s checksum %d size %d\n",
+		r->url, r->sum, r->bodysize);
+    }
+    free(r);
+}
+
+struct _request *
+request(char *urlin)
+{
+    int s=-1,f=-1;
     char buf[4096];
-    int len;
+    char msg[8192];
+    char *method, *url, *file, *size, *checksum;
+    char urlbuf[8192];
+    int len,len2;
     time_t w;
+    struct stat st;
     struct sockaddr_in S;
+    struct _request *r;
     if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
         perror("socket");
-	return -1;
+	return NULL;
     }
     memset(&S, '\0', sizeof(struct sockaddr_in));
     S.sin_family = AF_INET;
@@ -180,52 +284,100 @@
     if (connect(s, (struct sockaddr *) &S, sizeof(S)) < 0) {
         close(s);
         perror("connect");
-	return -1;
+	return NULL;
     }
-    buf[0] = '\0';
-    strcat(buf, "GET ");
-    strcat(buf, url);
-    strcat(buf, " HTTP/1.0\r\n");
-    strcat(buf, "Accept: */*\r\n");
+    strcpy(urlbuf,urlin);
+    method=strtok(urlbuf," ");
+    url=strtok(NULL," ");
+    file=strtok(NULL," ");
+    size=strtok(NULL," ");
+    checksum=strtok(NULL," ");
+    if (!url) {
+	url=method;
+	method="GET";
+    }
+    r=calloc(1,sizeof *r);
+    assert(r!=NULL);
+    strcpy(r->url, url);
+    r->fd = s;
+    if (size && strcmp(size,"-")!=0)
+	r->validsize=atoi(size);
+    else
+	r->validsize=-1; /* Unknown */
+    if (checksum && strcmp(checksum,"-")!=0)
+	r->validsum=atoi(checksum);
+    msg[0] = '\0';
+    sprintf(buf,"%s %s HTTP/1.0\r\n", method, url);
+    strcat(msg, buf);
+    strcat(msg, "Accept: */*\r\n");
     if (opt_ims && (lrand48() & 0x03) == 0) {
         w = time(NULL) - (lrand48() & 0x3FFFF);
-	strcat(buf, "If-Modified-Since: ");
-	strcat(buf, mkrfc850(&w));
-	strcat(buf, "\r\n");
-    }
-    strcat(buf, "\r\n");
-    len = strlen(buf);
-    if (write(s, buf, len) < 0) {
+	sprintf(buf, "If-Modified-Since: %s\r\n", mkrfc850(&w));
+	strcat(msg,buf);
+    }
+    if (file && strcmp(file, "-")!=0) {
+	f = open(file,O_RDONLY);
+	if (f < 0) {
+	    perror("open file");
+	    exit(1);
+	}
+	fstat(f, &st);
+	sprintf(buf,"Content-Length: %d\r\n", st.st_size);
+	strcat(msg,buf);
+    }
+    strcat(msg, "\r\n");
+    len = strlen(msg);
+    if ((len2=write(s, msg, len)) != len) {
         close(s);
-	perror("write");
-	return -1;
+	perror("write request");
+	free(r);
+	return NULL;
+    } else
+	total_bytes_written += len2;
+    if (f>=0) {
+	while ((len = read(f, buf, sizeof(buf)))>0) {
+	    len2 = write(s, buf, len);
+	    if (len2 < 0) {
+		perror("write body");
+		close(s);
+		free(r);
+	    }
+	}
+	if (len < 0) {
+	    perror("read body");
+	    exit(1);
+	}
     }
+
 /*
  * if (fcntl(s, F_SETFL, O_NDELAY) < 0)
  * perror("fcntl O_NDELAY");
  */
-    return s;
+    return r;
 }
 
 void
 read_url(int fd, void *junk)
 {
+    struct _request *r;
     static char buf[8192];
     char *t;
     int s;
     if (fgets(buf, 8191, stdin) == NULL) {
         printf("Done Reading URLS\n");
         fd_close(0);
+	nfds++;
         return;
     }
     if ((t = strchr(buf, '\n')))
         *t = '\0';
-    s = request(buf);
-    if (s < 0) {
+    r = request(buf);
+    if (!r) {
         max_connections = nfds - 1;
         printf("NOTE: max_connections set at %d\n", max_connections);
+    } else {
+	fd_open(r->fd, read_reply, r, reply_done);
     }
-    fd_open(s, read_reply, NULL);
 }
 
 void
@@ -242,16 +394,17 @@
     int i;
     int c;
     int dt;
-    fd_set R;
+    int j;
+    fd_set R,R2;
     struct timeval start;
     struct timeval last;
     struct timeval to;
     setbuf(stdout, NULL);
     setbuf(stderr, NULL);
     progname = strdup(argv[0]);
-    gettimeofday(&start, NULL);
-    last = start;
-    while ((c = getopt(argc, argv, "p:h:n:il:")) != -1) {
+    gettimeofday(&now, NULL);
+    start = last = now;
+    while ((c = getopt(argc, argv, "p:h:n:icl:")) != -1) {
         switch (c) {
         case 'p':
             proxy_port = atoi(optarg);
@@ -268,15 +421,20 @@
         case 'l':
             lifetime = (time_t) atoi(optarg);
             break;
+	case 'c':
+	    opt_checksum = 1;
+	    break;
         default:
             usage();
             return 1;
         }
     }
-    fd_open(0, read_url, NULL);
+    fd_open(0, read_url, NULL, NULL);
+    nfds--;
     signal(SIGINT, sig_intr);
     signal(SIGPIPE, SIG_IGN);
-    while (nfds) {
+    FD_ZERO(&R2);
+    while (nfds || FD[0].cb) {
         FD_ZERO(&R);
         to.tv_sec = 0;
         to.tv_usec = 100000;
@@ -292,26 +450,36 @@
             FD_SET(i, &R);
         }
         if (select(maxfd + 1, &R, NULL, NULL, &to) < 0) {
-	    printf("maxfd=%d\n", maxfd);
+	    fprintf(stderr, "maxfd=%d\n", maxfd);
             if (errno != EINTR)
                 perror("select");
             continue;
         }
+	gettimeofday(&now, NULL);
         for (i = 0; i <= maxfd; i++) {
             if (!FD_ISSET(i, &R))
                 continue;
             FD[i].cb(i, FD[i].data);
+            if (nfds < max_connections && FD[0].cb) {
+		j=0;
+		FD_SET(0,&R2);
+		to.tv_sec=0;
+		to.tv_usec=0;
+		if(select(1,&R2,NULL,NULL,&to) == 1)
+		    FD[0].cb(0, FD[0].data);
+	    }
         }
-	gettimeofday(&now, NULL);
         if (now.tv_sec > last.tv_sec) {
             last = now;
             dt = (int) (now.tv_sec - start.tv_sec);
-	    printf("T+ %6d: %9d req (%+4d), %4d conn, %3d/sec avg\n",
+	    printf("T+ %6d: %9d req (%+4d), %4d conn, %3d/sec avg, %dmb, %dkb/sec avg\n",
                 dt,
                 nrequests,
                 reqpersec,
                 nfds,
-		(int) (nrequests / dt));
+		(int) (nrequests / dt),
+		(int)total_bytes_read / 1024 / 1024,
+		(int)total_bytes_read / 1024 / dt);
             reqpersec = 0;
         }
     }
--------------2CFF1B1D14F41B9A5DA44F7F
Content-Type: application/x-perl; name="build_file_list.pl"
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="build_file_list.pl"
IyEvdXNyL2Jpbi9wZXJsIC13CgpkaWUgIlVzYWdlOiBidWlsZF9maWxlX2xpc3QgdXJsX2Zp
bGUgdGNwLWJhbmdlci10cmFjZVxuIgogICAgaWYgKEBBUkdWICE9IDIpOwoKJHVybF9maWxl
PXNoaWZ0IEBBUkdWOwokdHJhY2U9c2hpZnQgQEFSR1Y7Cgolc2l6ZT0oKTsKJWNoZWNrc3Vt
PSgpOwoKb3BlbihUUkFDRSwiPCR0cmFjZSIpIHx8IGRpZSgib3BlbiAkdHJhY2UiKTsKd2hp
bGUoPFRSQUNFPikgewogICAgbmV4dCBpZiAhL15ET05FOi87CiAgICBteSgkdXJsLCRjaGVj
a3N1bSwkc2l6ZSkgPSBtL15ET05FOiAoXFMqKSBjaGVja3N1bSAoXGQrKSBzaXplIChcZCsp
LzsKICAgIGRpZSBpZiAhZGVmaW5lZCAkY2hlY2tzdW07CiAgICAkc2l6ZXskdXJsfT0kc2l6
ZTsKICAgICRjaGVja3N1bXskdXJsfT0kY2hlY2tzdW07Cn0KY2xvc2UoVFJBQ0UpOwoKb3Bl
bihVUkxTLCI8JHVybF9maWxlIikgfHwgZGllKCJvcGVuICR1cmxfZmlsZSIpOwp3aGlsZSg8
VVJMUz4pIHsKICAgIG15ICgkbWV0aG9kLCAkdXJsLCAkZmlsZSwgJHNpemUsICRjaGVja3N1
bSkgPSBzcGxpdDsKCiAgICBpZiAoJHVybCBlcSAiIikgewoJJHVybCA9ICRtZXRob2Q7Cgkk
bWV0aG9kID0gIkdFVCI7CgkkZmlsZSA9ICItIjsKCSRzaXplID0gIi0iOwoJJGNoZWNrc3Vt
ID0gIi0iOwogICAgfQogICAgJHNpemUgPSAkc2l6ZXskdXJsfSBpZiBkZWZpbmVkICRzaXpl
eyR1cmx9OwogICAgJGNoZWNrc3VtID0gJGNoZWNrc3VteyR1cmx9IGlmIGRlZmluZWQgJGNo
ZWNrc3VteyR1cmx9OwogICAgCiAgICBwcmludCAiJG1ldGhvZCAkdXJsICRmaWxlICRzaXpl
ICRjaGVja3N1bVxuIjsKfQpjbG9zZShVUkxTKTsK
--------------2CFF1B1D14F41B9A5DA44F7F
Content-Type: text/plain; charset=us-ascii; name="pconn-banger.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="pconn-banger.c"
#include "config.h"
/*
 * On some systems, FD_SETSIZE is set to something lower than the
 * actual number of files which can be opened.  IRIX is one case,
 * NetBSD is another.  So here we increase FD_SETSIZE to our
 * configure-discovered maximum *before* any system includes.
 */
#define CHANGE_FD_SETSIZE 1
/* Cannot increase FD_SETSIZE on Linux */
#if defined(_SQUID_LINUX_)
#undef CHANGE_FD_SETSIZE
#define CHANGE_FD_SETSIZE 0
#endif
/* Cannot increase FD_SETSIZE on FreeBSD before 2.2.0, causes select(2)
 * to return EINVAL. */
/* Marian Durkovic <marian@svf.stuba.sk> */
/* Peter Wemm <peter@spinner.DIALix.COM> */
#if defined(_SQUID_FREEBSD_)
#include <osreldate.h>
#if __FreeBSD_version < 220000
#undef CHANGE_FD_SETSIZE
#define CHANGE_FD_SETSIZE 0
#endif
#endif
/* Increase FD_SETSIZE if SQUID_MAXFD is bigger */
#if CHANGE_FD_SETSIZE && SQUID_MAXFD > DEFAULT_FD_SETSIZE
#define FD_SETSIZE SQUID_MAXFD
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef HAVE_BSTRING_H
#include <bstring.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
#if HAVE_TIME_H
#include <time.h>
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
#if HAVE_ASSERT_H
#include <assert.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#define PROXY_PORT 3128
#define PROXY_ADDR "127.0.0.1"
#define MAX_FDS 1024
#define READ_BUF_SZ 4096
#define min(x,y) ((x)<(y)? (x) : (y))
static int proxy_port = PROXY_PORT;
static char *proxy_addr = PROXY_ADDR;
static char *progname;
static int noutstanding = 0;
static int done_reading_urls = 0;
static int opt_ims = 0;
static int opt_checksum = 0;
static int opt_reopen = 1;
static int max_outstanding = 10;
static time_t lifetime = 60;
static const char *const crlf = "\r\n";
static int trace_fd = -1;
static int total_bytes_read = 0;
#define REPLY_HDR_SZ 8192
struct _r {
    char url[1024];
    int content_length;
    int hdr_length;
    int hdr_offset;
    int bytes_read;
    char reply_hdrs[REPLY_HDR_SZ];
    struct _r *next;
    long sum;
    long validsize;
    long validsum;
};
static struct _r *Requests;
char *
mkrfc850(t)
     time_t *t;
{
    static char buf[128];
    struct tm *gmt = gmtime(t);
    buf[0] = '\0';
    (void) strftime(buf, 127, "%A, %d-%b-%y %H:%M:%S GMT", gmt);
    return buf;
}
char *
mime_headers_end(const char *mime)
{
    const char *p1, *p2;
    const char *end = NULL;
    p1 = strstr(mime, "\n\r\n");
    p2 = strstr(mime, "\n\n");
    if (p1 && p2)
        end = p1 < p2 ? p1 : p2;
    else
        end = p1 ? p1 : p2;
    if (end)
        end += (end == p1 ? 3 : 2);
    return (char *) end;
}
void
sig_intr(int sig)
{
    fprintf(stderr, "\rWaiting for open connections to finish...\n");
    signal(sig, SIG_DFL);
    done_reading_urls = 1;
}
int
open_http_socket(void)
{
    int s;
    struct sockaddr_in S;
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        return -1;
    }
    memset(&S, '\0', sizeof(struct sockaddr_in));
    S.sin_family = AF_INET;
    S.sin_port = htons(proxy_port);
    S.sin_addr.s_addr = inet_addr(proxy_addr);
    if (connect(s, (struct sockaddr *) &S, sizeof(S)) < 0) {
        close(s);
        perror("connect");
        return -1;
    }
    return s;
}
int
send_request(int fd, const char *data)
{
    char msg[4096],buf[4096];
    int len;
    time_t w;
    struct _r *r;
    struct _r **R;
    char *method, *url, *file, *size, *checksum;
    char *tmp = strdup(data);
    struct stat st;
    int file_fd = -1;
    method=strtok(tmp, " ");
    url=strtok(NULL, " ");
    file=strtok(NULL, " ");
    size=strtok(NULL, " ");
    checksum=strtok(NULL, " ");
    if (!url) {
      url=method;
      method="GET";
    }
    if (file && strcmp(file,"-")==0)
        file=NULL;
    if (size && strcmp(size,"-")==0)
        size=NULL;
    if (checksum && strcmp(checksum,"-")==0)
        checksum=NULL;
    msg[0] = '\0';
    sprintf(buf, "%s %s HTTP/1.0\r\n", method, url);
    strcat(msg,buf);
    strcat(msg, "Accept: */*\r\n");
    strcat(msg, "Proxy-Connection: Keep-Alive\r\n");
    if (opt_ims && (lrand48() & 0x03) == 0) {
        w = time(NULL) - (lrand48() & 0x3FFFF);
        sprintf(buf, "If-Modified-Since: %s\r\n", mkrfc850(&w));
        strcat(msg, buf);
    }
    if (file) {
        if ( (file_fd = open(file,O_RDONLY)) < 0) {
            perror("open");
            return -1;
        }
        if ( fstat(file_fd, &st) ) {
            perror("fstat");
            close(file_fd);
            return -1;
        }
        sprintf(buf, "Content-length: %d\r\n", st.st_size);
        strcat(msg, buf);
    }
    strcat(msg, "\r\n");
    len = strlen(msg);
    if (write(fd, msg, len) < 0) {
        close(fd);
        perror("request write");
        close(file_fd);
        return -1;
    }
    if (file) {
        while((len=read(file_fd, buf, sizeof buf)) > 0) {
            if (write(fd, buf, len) < 0) {
                close(fd);
                perror("body write");
                close(file_fd);
                return -1;
            }
        }
        if (len < 0) {
            perror("file read");
            close(file_fd);
            return -1;
        }
        close(file_fd);
    }
    r = calloc(1, sizeof(struct _r));
    strcpy(r->url, url);
    if (size)
        r->validsize = atoi(size);
    else
        r->validsize = -1;
    if (checksum)
        r->validsum = atoi(checksum);
    for (R = &Requests; *R; R = &(*R)->next);
    *R = r;
/*    fprintf(stderr, "REQUESTED %s\n", url); */
    noutstanding++;
    return 0;
}
static int
get_header_int_value(const char *hdr, const char *buf, const char *end)
{
    const char *t;
    for (t = buf; t < end; t += strcspn(t, crlf), t += strspn(t, crlf)) {
        if (strncasecmp(t, hdr, strlen(hdr)) == 0) {
            t += strlen(hdr);
            while (isspace(*t))
                t++;
            return atoi(t);
        }
    }
    return -1;
}
static const char *
get_header_string_value(const char *hdr, const char *buf, const char *end)
{
    const char *t;
    static char result[8192];
    for (t = buf; t < end; t += strcspn(t, crlf), t += strspn(t, crlf)) {
        if (strncasecmp(t, hdr, strlen(hdr)) == 0) {
            t += strlen(hdr);
            while (isspace(*t))
                t++;
            strcpy(result,"");
            strncat(result,t,strcspn(t, crlf));
            return result;
        }
    }
    return NULL;
}
void
request_done(struct _r *r)
{
#if 0
    fprintf(stderr, "DONE: %s, (%d+%d)\n",
            r->url,
            r->hdr_length,
            r->content_length);
#endif
    if (r->content_length != r->bytes_read)
        fprintf(stderr, "ERROR! Short reply, expected %d bytes got %d\n",
            r->content_length, r->bytes_read);
    else if (r->validsize >= 0) {
        if (r->validsize != r->bytes_read)
            fprintf(stderr, "WARNING: %s Object size mismatch, expected %d got %d\n",
                    r->url, r->validsize, r->bytes_read);
        else if (opt_checksum && r->sum != r->validsum)
            fprintf(stderr, "WARNING: %s Checksum error. Expected %d got %d\n",
                    r->url, r->validsum, r->sum);
    }
}
int
handle_read(char *inbuf, int len)
{
    struct _r *r = Requests;
    const char *end;
    const char *url;
    static char buf[READ_BUF_SZ];
    int hlen,blen;
    if (len < 0 ) {
        perror("read");
        Requests = r->next;
        request_done(r);
        free(r);
        noutstanding--;
        if (trace_fd >= 0)
            write(trace_fd,"\n[CLOSED]\n",10);
        return -1;
    }
    total_bytes_read += len;
    xmemcpy(buf,inbuf,len);
    if (len == 0) {
        fprintf(stderr, "WARNING: %s, server closed socket after %d+%d bytes\n", r->url, r->hdr_offset, r->bytes_read);
        /* XXX, If no data was received and it isn't the first request on this
         * connection then the request should be restarted rather than aborted
         * but this is a simple test program an not a full blown HTTP client.
         */
        request_done(r);
        Requests = r->next;
        free(r);
        noutstanding--;
        return -1;
    }
    if (trace_fd > 0)
        write(trace_fd, buf, len);
    while (len > 0) {
        /* Build headers */
        if (r->hdr_length == 0) {
            hlen = min(len, REPLY_HDR_SZ - r->hdr_offset - 1);
            xmemcpy(r->reply_hdrs + r->hdr_offset, buf, hlen);
            r->hdr_offset += hlen;
            r->reply_hdrs[r->hdr_offset] = '\0';
            len -= hlen;
            /* Save any remaining read data */
            xmemmove(buf, buf + hlen, len);
        }
        /* Process headers */
        if (r->hdr_length == 0 && (end = mime_headers_end(r->reply_hdrs)) != NULL) {
#if 0
            fprintf(stderr, "FOUND EOH FOR %s\n", r->url); */
#endif
            r->hdr_length = end - r->reply_hdrs;
#if 0
             fprintf(stderr, "HDR_LENGTH = %d\n", r->hdr_length);
#endif
            /* "unread" any body contents received */
            blen = r->hdr_offset - r->hdr_length;
            assert(blen >= 0);
            if (blen > 0) {
                xmemmove(buf + blen, buf, len);
                xmemcpy(buf, r->reply_hdrs + r->hdr_length, blen);
                len += blen;
            }
            r->reply_hdrs[r->hdr_length]='\0'; /* Null terminate headers */
            /* Parse headers */
            r->content_length = get_header_int_value("content-length:", r->reply_hdrs, end);
/*	    fprintf(stderr, "CONTENT_LENGTH = %d\n", r->content_length); */
            url = get_header_string_value("X-Request-URI:", r->reply_hdrs, end);
            if (url != NULL && strcmp(r->url, url) != 0)
                fprintf(stderr, "WARNING: %s got reply %s\n", r->url, url);
#if XREQUESTURI || 0
            fprintf(stderr, "LOCATION = %s\n", get_header_string_value("X-Request-URI:", r->reply_hdrs, end));  
#endif
        }
        if ( !(len==0 || r->hdr_length > 0) ) {
            fprintf(stderr, "ERROR!!!\n");
            assert((len==0 || r->hdr_length > 0));
        }
        /* Process body */
        if (r->hdr_length != 0) {
            int i;
            int bytes_left, bytes_used;
            if (r->content_length >= 0) {
                bytes_left = r->content_length - r->bytes_read;
                assert(bytes_left >= 0);
                    bytes_used = len < bytes_left ? len : bytes_left;
            } else {
                bytes_left = len + 1; /* Unknown end... */
                bytes_used = len;
            }
            if (opt_checksum) {
                for(i=0; i<bytes_used; i++)
                    r->sum += (int)buf[i] & 0xFF;
            }
            r->bytes_read += bytes_used;
            len -= bytes_used;
            if (bytes_left == bytes_used) {
                request_done(r);
                Requests = r->next;
                free(r);
                noutstanding--;
                r = Requests;
            } else {
                assert(r->bytes_read < r->content_length);
            }
            xmemmove(buf, buf + bytes_used, len);
        }
    }
    return 0;
}
int
read_reply(int fd)
{
    static char buf[READ_BUF_SZ];
    int len;
    int x;
    len = read(fd, buf, READ_BUF_SZ);
    x = handle_read(buf, len);
    if (x < 0) {
        perror("read reply");
        close(fd);
    }
    return x;
}
void
main_loop(void)
{
    static int pconn_fd = -1;
    static char buf[8192];
    struct timeval to;
    struct timeval now,last,start;
    fd_set R;
    struct _r *r;
    struct _r *nextr;
    int x;
    int timeouts;
    int nrequests = 0, rrequests = 0, reqpersec = 0;
    gettimeofday(&start, NULL);
    last = start;
    pconn_fd = open_http_socket();
    if (pconn_fd < 0) {
        perror("socket");
        exit(1);
    }
    while (!done_reading_urls || noutstanding) {
        if (!opt_reopen && pconn_fd < 0) {
            fprintf(stderr,"TERMINATED: Connection closed\n");
            break;
        }
        if (pconn_fd<0) {
            pconn_fd = open_http_socket();
            if (pconn_fd < 0) {
                perror("socket");
                exit(1);
            }
            nextr = Requests;
            Requests = NULL;
            noutstanding=0;
            while ((r = nextr) != NULL) {
                nextr = r->next;
                if (send_request(pconn_fd, r->url) != 0) {
                    close(pconn_fd);
                    pconn_fd=-1;
                    nextr = r;
                    for (r = Requests; r!=NULL && r->next; r=r->next);
                    if (r != NULL)
                        r->next = nextr;
                    else
                        Requests = nextr;
                    break;
                }
                free(r);
            }
            timeouts = 0;
            if (pconn_fd <0)
                continue;
        }
        if (timeouts == 200) {
            close(pconn_fd);
            pconn_fd = -1;
            r = Requests;
            Requests = Requests->next;
            fprintf(stderr, "ABORT %s\n", Requests->url);
            free(r);
            noutstanding--;
        }
        if (pconn_fd>=0 && noutstanding < max_outstanding && !done_reading_urls) {
            char *t;
            if (fgets(buf, 8191, stdin) == NULL) {
                fprintf(stderr, "Done Reading URLS\n");
                done_reading_urls = 1;
                continue;
            }
            rrequests++;
            if ((t = strchr(buf, '\n')))
                *t = '\0';
            if (send_request(pconn_fd, buf) != 0) {
                close(pconn_fd);
                pconn_fd=-1;
                continue;
            }
            nrequests++;
            reqpersec++;
            timeouts = 0;
        }
        FD_ZERO(&R);
        to.tv_sec = 1;
        to.tv_usec = 0;
        FD_SET(pconn_fd, &R);
        x = select(pconn_fd + 1, &R, NULL, NULL, &to);
        if (x < 0) {
            if (errno != EINTR)
                perror("select");
            continue;
        } else if (x == 0) {
            assert(Requests != NULL);
            fprintf(stderr, "TIMEOUT %s; %d, %d\n", Requests->url,
                ++timeouts, noutstanding);
            continue;
        }
        if (FD_ISSET(pconn_fd, &R)) {
            timeouts = 0;
            if (read_reply(pconn_fd) != 0)
                pconn_fd = -1;
        }
        gettimeofday(&now, NULL);
        if (now.tv_sec > last.tv_sec) {
            int dt;
            int nreq;
            last = now;
            dt = (int) (now.tv_sec - start.tv_sec);
            nreq=0;
            for (r=Requests; r ; r=r->next) nreq++;
            printf("T+ %6d: %9d req (%+4d), %4d pend, %3d/sec avg, %dmb, %dkb/sec avg\n",
                    dt,
                    nrequests,
                    reqpersec,
                    nreq,
                    (int) (nrequests / dt),
                    (int)total_bytes_read / 1024 / 1024,
                    (int)total_bytes_read / 1024 / dt);
            reqpersec = 0;
        }
    }
}
void
usage(void)
{
    fprintf(stderr, "usage: %s: -p port -h host -n max -t tracefile -i -c -l lifetime\n", progname);
}
int
main(argc, argv)
     int argc;
     char *argv[];
{
    int c;
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    progname = strdup(argv[0]);
    while ((c = getopt(argc, argv, "p:h:n:t:icl:r")) != -1) {
        switch (c) {
        case 'p':
            proxy_port = atoi(optarg);
            break;
        case 'h':
            proxy_addr = strdup(optarg);
            break;
        case 'n':
            max_outstanding = atoi(optarg);
            break;
        case 'i':
            opt_ims = 1;
            break;
        case 'c':
            opt_checksum = 1;
            break;
        case 'l':
            lifetime = (time_t) atoi(optarg);
            break;
        case 't':
            trace_fd = open(optarg,O_WRONLY|O_CREAT|O_TRUNC,0666);
            break;
        case 'r':
            opt_reopen = !opt_reopen;
            break;
        default:
            usage();
            return 1;
        }
    }
    signal(SIGINT, sig_intr);
    signal(SIGPIPE, SIG_IGN);
    main_loop();
    return 0;
}
--------------2CFF1B1D14F41B9A5DA44F7F
Content-Type: text/plain; charset=us-ascii; name="tcp-banger2.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="tcp-banger2.c"
#include "config.h"
/*
 * On some systems, FD_SETSIZE is set to something lower than the
 * actual number of files which can be opened.  IRIX is one case,
 * NetBSD is another.  So here we increase FD_SETSIZE to our
 * configure-discovered maximum *before* any system includes.
 */
#define CHANGE_FD_SETSIZE 1
/* Cannot increase FD_SETSIZE on Linux */
#if defined(_SQUID_LINUX_)
#undef CHANGE_FD_SETSIZE
#define CHANGE_FD_SETSIZE 0
#endif
/* Cannot increase FD_SETSIZE on FreeBSD before 2.2.0, causes select(2)
 * to return EINVAL. */
/* Marian Durkovic <marian@svf.stuba.sk> */
/* Peter Wemm <peter@spinner.DIALix.COM> */
#if defined(_SQUID_FREEBSD_)
#include <osreldate.h>
#if __FreeBSD_version < 220000
#undef CHANGE_FD_SETSIZE
#define CHANGE_FD_SETSIZE 0
#endif
#endif
/* Increase FD_SETSIZE if SQUID_MAXFD is bigger */
#if CHANGE_FD_SETSIZE && SQUID_MAXFD > DEFAULT_FD_SETSIZE
#define FD_SETSIZE SQUID_MAXFD
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
#if HAVE_TIME_H
#include <time.h>
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_ASSERT_H
#include <assert.h>
#endif
#define PROXY_PORT 3128
#define PROXY_ADDR "127.0.0.1"
#define MAX_FDS 1024
#define READ_BUF_SZ 4096
static int proxy_port = PROXY_PORT;
static char *proxy_addr = PROXY_ADDR;
static char *progname;
static int reqpersec;
static int nrequests;
static int opt_ims = 0;
static int max_connections = 64;
static time_t lifetime = 60;
static struct timeval now;
static long total_bytes_written = 0;
static long total_bytes_read = 0;
static int opt_checksum = 0;
typedef void (CB) (int, void *);
struct _f {
    CB *cb;
    CB *ccb;
    void *data;
    time_t start;
};
struct _request {
    int fd;
    char url[8192];
    char buf[READ_BUF_SZ * 2 + 1];
    int headfound;
    long validsize;
    long validsum;
    long bodysize;
    long sum;
    int content_length;
};
struct _f FD[MAX_FDS];
int nfds = 0;
int maxfd = 0;
char *
mkrfc850(t)
     time_t *t;
{
    static char buf[128];
    struct tm *gmt = gmtime(t);
    buf[0] = '\0';
    (void) strftime(buf, 127, "%A, %d-%b-%y %H:%M:%S GMT", gmt);
    return buf;
}
void
fd_close(int fd)
{
    close(fd);
    if (FD[fd].ccb)
        FD[fd].ccb(fd, FD[fd].data);
    FD[fd].ccb = NULL;
    FD[fd].cb = NULL;
    FD[fd].data = NULL;
    nfds--;
    if (fd == maxfd) {
        while (fd > 0 && FD[fd].cb == NULL)
            fd--;
        maxfd = fd;
    }
}
void
fd_open(int fd, CB * cb, void *data, CB *ccb)
{
    FD[fd].cb = cb;
    FD[fd].ccb = ccb;
    FD[fd].data = data;
    FD[fd].start = now.tv_sec;
    if (fd > maxfd)
        maxfd = fd;
    nfds++;
}
void
sig_intr(int sig)
{
    fd_close(0);
    nfds++;
    printf("\rWaiting for open connections to finish...\n");
    signal(sig, SIG_DFL);
}
void
read_reply(int fd, void *data)
{
    struct _request *r = data;
    static unsigned char buf[READ_BUF_SZ];
    int len;
    char *p;
    if ((len=read(fd, buf, READ_BUF_SZ)) <= 0) {
        fd_close(fd);
        reqpersec++;
        nrequests++;
    } else {
        int used=0;
        total_bytes_read+=len;
        if (r->headfound < 2) {
            char *p,*header = NULL;
            int oldlen = strlen(r->buf);
            int newlen = oldlen + len;
            assert(oldlen <= READ_BUF_SZ);
            memcpy(r->buf+oldlen, buf, len);
            r->buf[newlen+1]='\0';
            for(p=r->buf; r->headfound < 2 && used<newlen; p++,used++) {
                switch(*p) {
                case '\n':
                    r->headfound++;
                    if (header) {
                        /* Decode header */
                        if (strncasecmp(header,"Content-Length:",15)==0)
                            r->content_length = atoi(header+15);
                        if (strncasecmp(header,"X-Request-URI:",14)==0) {
                            /* Check URI */
                            if (strncmp(r->url, header+15, strcspn(header+15,"\r\n"))) {
                                char url[8192];
                                strncpy(url, header+15, strcspn(header+15,"\r\n"));
                                url[strcspn(header+15, "\r\n")]='\n';
                                fprintf(stderr,"ERROR: Sent %s received %s\n",
                                        r->url, url);
                            }
                        }
                        header=NULL;
                    }
                    break;
                case '\r':
                    break;
                default:
                    r->headfound=0;
                    if (!header)
                        header = p;
                    break;
                }
            }
            if (header) {
                memmove(r->buf, header, newlen - (header - r->buf) + 1);
            }
        }
        r->bodysize+=len-used;
        if (opt_checksum) {
            for (; used<len ; used++) {
                r->sum += buf[used];
            }
        }
    }
}
void
reply_done(int fd, void *data)
{
    struct _request *r = data;
    if (r->bodysize != r->content_length)
        fprintf(stderr,"ERROR: %s expected %d bytes got %d\n",
                r->url, r->content_length, r->bodysize);
    else if (r->validsize >= 0) {
        if (r->validsize != r->bodysize)
            fprintf(stderr,"WARNING: %s size mismatch wanted %d bytes got %d\n",
                    r->url, r->validsize, r->bodysize);
        else if (opt_checksum && r->validsum != r->sum)
            fprintf(stderr,"WARNING: %s invalid checksum wanted %d got %d\n",
                    r->url, r->validsum, r->sum);
    } else if (opt_checksum) {
        fprintf(stderr,"DONE: %s checksum %d size %d\n",
                r->url, r->sum, r->bodysize);
    }
    free(r);
}
struct _request *
request(char *urlin)
{
    int s=-1,f=-1;
    char buf[4096];
    char msg[8192];
    char *method, *url, *file, *size, *checksum;
    char urlbuf[8192];
    int len,len2;
    time_t w;
    struct stat st;
    struct sockaddr_in S;
    struct _request *r;
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        return NULL;
    }
    memset(&S, '\0', sizeof(struct sockaddr_in));
    S.sin_family = AF_INET;
    S.sin_port = htons(proxy_port);
    S.sin_addr.s_addr = inet_addr(proxy_addr);
    if (connect(s, (struct sockaddr *) &S, sizeof(S)) < 0) {
        close(s);
        perror("connect");
        return NULL;
    }
    strcpy(urlbuf,urlin);
    method=strtok(urlbuf," ");
    url=strtok(NULL," ");
    file=strtok(NULL," ");
    size=strtok(NULL," ");
    checksum=strtok(NULL," ");
    if (!url) {
        url=method;
        method="GET";
    }
    r=calloc(1,sizeof *r);
    assert(r!=NULL);
    strcpy(r->url, url);
    r->fd = s;
    if (size && strcmp(size,"-")!=0)
        r->validsize=atoi(size);
    else
        r->validsize=-1; /* Unknown */
    if (checksum && strcmp(checksum,"-")!=0)
        r->validsum=atoi(checksum);
    msg[0] = '\0';
    sprintf(buf,"%s %s HTTP/1.0\r\n", method, url);
    strcat(msg, buf);
    strcat(msg, "Accept: */*\r\n");
    if (opt_ims && (lrand48() & 0x03) == 0) {
        w = time(NULL) - (lrand48() & 0x3FFFF);
        sprintf(buf, "If-Modified-Since: %s\r\n", mkrfc850(&w));
        strcat(msg,buf);
    }
    if (file && strcmp(file, "-")!=0) {
        f = open(file,O_RDONLY);
        if (f < 0) {
            perror("open file");
            exit(1);
        }
        fstat(f, &st);
        sprintf(buf,"Content-Length: %d\r\n", st.st_size);
        strcat(msg,buf);
    }
    strcat(msg, "\r\n");
    len = strlen(msg);
    if ((len2=write(s, msg, len)) != len) {
        close(s);
        perror("write request");
        free(r);
        return NULL;
    } else
        total_bytes_written += len2;
    if (f>=0) {
        while ((len = read(f, buf, sizeof(buf)))>0) {
            len2 = write(s, buf, len);
            if (len2 < 0) {
                perror("write body");
                close(s);
                free(r);
            }
        }
        if (len < 0) {
            perror("read body");
            exit(1);
        }
    }
/*
 * if (fcntl(s, F_SETFL, O_NDELAY) < 0)
 * perror("fcntl O_NDELAY");
 */
    return r;
}
void
read_url(int fd, void *junk)
{
    struct _request *r;
    static char buf[8192];
    char *t;
    int s;
    if (fgets(buf, 8191, stdin) == NULL) {
        printf("Done Reading URLS\n");
        fd_close(0);
        nfds++;
        return;
    }
    if ((t = strchr(buf, '\n')))
        *t = '\0';
    r = request(buf);
    if (!r) {
        max_connections = nfds - 1;
        printf("NOTE: max_connections set at %d\n", max_connections);
    } else {
        fd_open(r->fd, read_reply, r, reply_done);
    }
}
void
usage(void)
{
    fprintf(stderr, "usage: %s: -p port -h host -n max\n", progname);
}
int
main(argc, argv)
     int argc;
     char *argv[];
{
    int i;
    int c;
    int dt;
    int j;
    fd_set R,R2;
    struct timeval start;
    struct timeval last;
    struct timeval to;
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    progname = strdup(argv[0]);
    gettimeofday(&now, NULL);
    start = last = now;
    while ((c = getopt(argc, argv, "p:h:n:icl:")) != -1) {
        switch (c) {
        case 'p':
            proxy_port = atoi(optarg);
            break;
        case 'h':
            proxy_addr = strdup(optarg);
            break;
        case 'n':
            max_connections = atoi(optarg);
            break;
        case 'i':
            opt_ims = 1;
            break;
        case 'l':
            lifetime = (time_t) atoi(optarg);
            break;
        case 'c':
            opt_checksum = 1;
            break;
        default:
            usage();
            return 1;
        }
    }
    fd_open(0, read_url, NULL, NULL);
    nfds--;
    signal(SIGINT, sig_intr);
    signal(SIGPIPE, SIG_IGN);
    FD_ZERO(&R2);
    while (nfds || FD[0].cb) {
        FD_ZERO(&R);
        to.tv_sec = 0;
        to.tv_usec = 100000;
        if (nfds < max_connections && FD[0].cb)
            FD_SET(0, &R);
        for (i = 1; i <= maxfd; i++) {
            if (FD[i].cb == NULL)
                continue;
            if (now.tv_sec - FD[i].start > lifetime) {
                fd_close(i);
                continue;
            }
            FD_SET(i, &R);
        }
        if (select(maxfd + 1, &R, NULL, NULL, &to) < 0) {
            fprintf(stderr, "maxfd=%d\n", maxfd);
            if (errno != EINTR)
                perror("select");
            continue;
        }
        gettimeofday(&now, NULL);
        for (i = 0; i <= maxfd; i++) {
            if (!FD_ISSET(i, &R))
                continue;
            FD[i].cb(i, FD[i].data);
#if 0
            /* This is counterproductive. To maximize generated load we need
             * utilize non-blocking transmission of requests..
             */
            if (nfds < max_connections && FD[0].cb) {
                j=0;
                FD_SET(0,&R2);
                to.tv_sec=0;
                to.tv_usec=0;
                if(select(1,&R2,NULL,NULL,&to) == 1)
                    FD[0].cb(0, FD[0].data);
            }
#endif
        }
        if (now.tv_sec > last.tv_sec) {
            last = now;
            dt = (int) (now.tv_sec - start.tv_sec);
            printf("T+ %6d: %9d req (%+4d), %4d conn, %3d/sec avg, %dmb, %dkb/sec avg\n",
                dt,
                nrequests,
                reqpersec,
                nfds,
                (int) (nrequests / dt),
                (int)total_bytes_read / 1024 / 1024,
                (int)total_bytes_read / 1024 / dt);
            reqpersec = 0;
        }
    }
    return 0;
}
--------------2CFF1B1D14F41B9A5DA44F7F--
Received on Tue Jul 29 2003 - 13:15:48 MDT
This archive was generated by hypermail pre-2.1.9 : Tue Dec 09 2003 - 16:11:46 MST