1.2b20-1: Updated test suite

From: Henrik Nordstrom <hno@dont-contact.us>
Date: Mon, 04 May 1998 20:20:08 +0000

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