📄 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 8192struct _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;}voidsig_intr(int sig){ fprintf(stderr, "\rWaiting for open connections to finish...\n"); signal(sig, SIG_DFL); done_reading_urls = 1;}intopen_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;}intsend_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 intget_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;}voidrequest_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); }}inthandle_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 if (r->content_length > -1) { assert(r->bytes_read < r->content_length); } xmemmove(buf, buf + bytes_used, len); } } return 0;}intread_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;}voidmain_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; } }}voidusage(void){ fprintf(stderr, "usage: %s: -p port -h host -n max -t tracefile -i -c -l lifetime\n", progname);}intmain(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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -