pconn-banger.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:14k
- #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 = "rn";
- 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] = ' ';
- (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, "nrn");
- p2 = strstr(mime, "nn");
- 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, ' ', 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] = ' ';
- sprintf(buf, "%s %s HTTP/1.0rn", method, url);
- strcat(msg,buf);
- strcat(msg, "Accept: */*rn");
- strcat(msg, "Proxy-Connection: Keep-Alivern");
- if (opt_ims && (lrand48() & 0x03) == 0) {
- w = time(NULL) - (lrand48() & 0x3FFFF);
- sprintf(buf, "If-Modified-Since: %srn", 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: %drn", st.st_size);
- strcat(msg, buf);
- }
- strcat(msg, "rn");
- 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 %sn", 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 %dn",
- 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 %dn",
- r->url, r->validsize, r->bytes_read);
- else if (opt_checksum && r->sum != r->validsum)
- fprintf(stderr, "WARNING: %s Checksum error. Expected %d got %dn",
- 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 bytesn", 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] = ' ';
- 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 %sn", r->url); */
- #endif
- r->hdr_length = end - r->reply_hdrs;
- #if 0
- fprintf(stderr, "HDR_LENGTH = %dn", 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]=' '; /* Null terminate headers */
- /* Parse headers */
- r->content_length = get_header_int_value("content-length:", r->reply_hdrs, end);
- /* fprintf(stderr, "CONTENT_LENGTH = %dn", 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 %sn", r->url, url);
- #if XREQUESTURI || 0
- fprintf(stderr, "LOCATION = %sn", 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 if (r->content_length > -1) {
- 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 closedn");
- 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 %sn", 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 URLSn");
- done_reading_urls = 1;
- continue;
- }
- rrequests++;
- if ((t = strchr(buf, 'n')))
- *t = ' ';
- 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, %dn", 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 avgn",
- 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 lifetimen", 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;
- }