pconn-banger.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:14k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. #include "config.h"
  2. /*
  3.  * On some systems, FD_SETSIZE is set to something lower than the
  4.  * actual number of files which can be opened.  IRIX is one case,
  5.  * NetBSD is another.  So here we increase FD_SETSIZE to our
  6.  * configure-discovered maximum *before* any system includes.
  7.  */
  8. #define CHANGE_FD_SETSIZE 1
  9. /* Cannot increase FD_SETSIZE on Linux */
  10. #if defined(_SQUID_LINUX_)
  11. #undef CHANGE_FD_SETSIZE
  12. #define CHANGE_FD_SETSIZE 0
  13. #endif
  14. /* Cannot increase FD_SETSIZE on FreeBSD before 2.2.0, causes select(2)
  15.  * to return EINVAL. */
  16. /* Marian Durkovic <marian@svf.stuba.sk> */
  17. /* Peter Wemm <peter@spinner.DIALix.COM> */
  18. #if defined(_SQUID_FREEBSD_)
  19. #include <osreldate.h>
  20. #if __FreeBSD_version < 220000
  21. #undef CHANGE_FD_SETSIZE
  22. #define CHANGE_FD_SETSIZE 0
  23. #endif
  24. #endif
  25. /* Increase FD_SETSIZE if SQUID_MAXFD is bigger */
  26. #if CHANGE_FD_SETSIZE && SQUID_MAXFD > DEFAULT_FD_SETSIZE
  27. #define FD_SETSIZE SQUID_MAXFD
  28. #endif
  29. #if HAVE_UNISTD_H
  30. #include <unistd.h>
  31. #endif
  32. #if HAVE_STDLIB_H
  33. #include <stdlib.h>
  34. #endif
  35. #if HAVE_STDIO_H
  36. #include <stdio.h>
  37. #endif
  38. #if HAVE_FCNTL_H
  39. #include <fcntl.h>
  40. #endif
  41. #ifdef HAVE_STRING_H
  42. #include <string.h>
  43. #endif
  44. #ifdef HAVE_STRINGS_H
  45. #include <strings.h>
  46. #endif
  47. #ifdef HAVE_BSTRING_H
  48. #include <bstring.h>
  49. #endif
  50. #if HAVE_SYS_TYPES_H
  51. #include <sys/types.h>
  52. #endif
  53. #if HAVE_SYS_SELECT_H
  54. #include <sys/select.h>
  55. #endif
  56. #if HAVE_SIGNAL_H
  57. #include <signal.h>
  58. #endif
  59. #if HAVE_TIME_H
  60. #include <time.h>
  61. #endif
  62. #if HAVE_SYS_TIME_H
  63. #include <sys/time.h>
  64. #endif
  65. #if HAVE_SYS_SOCKET_H
  66. #include <sys/socket.h>
  67. #endif
  68. #if HAVE_NETINET_IN_H
  69. #include <netinet/in.h>
  70. #endif
  71. #if HAVE_ARPA_INET_H
  72. #include <arpa/inet.h>
  73. #endif
  74. #if HAVE_ERRNO_H
  75. #include <errno.h>
  76. #endif
  77. #if HAVE_CTYPE_H
  78. #include <ctype.h>
  79. #endif
  80. #if HAVE_ASSERT_H
  81. #include <assert.h>
  82. #endif
  83. #if HAVE_SYS_STAT_H
  84. #include <sys/stat.h>
  85. #endif
  86. #define PROXY_PORT 3128
  87. #define PROXY_ADDR "127.0.0.1"
  88. #define MAX_FDS 1024
  89. #define READ_BUF_SZ 4096
  90. #define min(x,y) ((x)<(y)? (x) : (y))
  91. static int proxy_port = PROXY_PORT;
  92. static char *proxy_addr = PROXY_ADDR;
  93. static char *progname;
  94. static int noutstanding = 0;
  95. static int done_reading_urls = 0;
  96. static int opt_ims = 0;
  97. static int opt_checksum = 0;
  98. static int opt_reopen = 1;
  99. static int max_outstanding = 10;
  100. static time_t lifetime = 60;
  101. static const char *const crlf = "rn";
  102. static int trace_fd = -1;
  103. static int total_bytes_read = 0;
  104. #define REPLY_HDR_SZ 8192
  105. struct _r {
  106.     char url[1024];
  107.     int content_length;
  108.     int hdr_length;
  109.     int hdr_offset;
  110.     int bytes_read;
  111.     char reply_hdrs[REPLY_HDR_SZ];
  112.     struct _r *next;
  113.     long sum;
  114.     long validsize;
  115.     long validsum;
  116. };
  117. static struct _r *Requests;
  118. char *
  119. mkrfc850(t)
  120.      time_t *t;
  121. {
  122.     static char buf[128];
  123.     struct tm *gmt = gmtime(t);
  124.     buf[0] = '';
  125.     (void) strftime(buf, 127, "%A, %d-%b-%y %H:%M:%S GMT", gmt);
  126.     return buf;
  127. }
  128. char *
  129. mime_headers_end(const char *mime)
  130. {
  131.     const char *p1, *p2;
  132.     const char *end = NULL;
  133.     p1 = strstr(mime, "nrn");
  134.     p2 = strstr(mime, "nn");
  135.     if (p1 && p2)
  136. end = p1 < p2 ? p1 : p2;
  137.     else
  138. end = p1 ? p1 : p2;
  139.     if (end)
  140. end += (end == p1 ? 3 : 2);
  141.     return (char *) end;
  142. }
  143. void
  144. sig_intr(int sig)
  145. {
  146.     fprintf(stderr, "rWaiting for open connections to finish...n");
  147.     signal(sig, SIG_DFL);
  148.     done_reading_urls = 1;
  149. }
  150. int
  151. open_http_socket(void)
  152. {
  153.     int s;
  154.     struct sockaddr_in S;
  155.     if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  156. perror("socket");
  157. return -1;
  158.     }
  159.     memset(&S, '', sizeof(struct sockaddr_in));
  160.     S.sin_family = AF_INET;
  161.     S.sin_port = htons(proxy_port);
  162.     S.sin_addr.s_addr = inet_addr(proxy_addr);
  163.     if (connect(s, (struct sockaddr *) &S, sizeof(S)) < 0) {
  164. close(s);
  165. perror("connect");
  166. return -1;
  167.     }
  168.     return s;
  169. }
  170. int
  171. send_request(int fd, const char *data)
  172. {
  173.     char msg[4096],buf[4096];
  174.     int len;
  175.     time_t w;
  176.     struct _r *r;
  177.     struct _r **R;
  178.     char *method, *url, *file, *size, *checksum;
  179.     char *tmp = strdup(data);
  180.     struct stat st;
  181.     int file_fd = -1;
  182.     method=strtok(tmp, " ");
  183.     url=strtok(NULL, " ");
  184.     file=strtok(NULL, " ");
  185.     size=strtok(NULL, " ");
  186.     checksum=strtok(NULL, " ");
  187.     if (!url) {
  188.       url=method;
  189.       method="GET";
  190.     }
  191.     if (file && strcmp(file,"-")==0)
  192. file=NULL;
  193.     if (size && strcmp(size,"-")==0)
  194. size=NULL;
  195.     if (checksum && strcmp(checksum,"-")==0)
  196. checksum=NULL;
  197.     msg[0] = '';
  198.     sprintf(buf, "%s %s HTTP/1.0rn", method, url);
  199.     strcat(msg,buf);
  200.     strcat(msg, "Accept: */*rn");
  201.     strcat(msg, "Proxy-Connection: Keep-Alivern");
  202.     if (opt_ims && (lrand48() & 0x03) == 0) {
  203. w = time(NULL) - (lrand48() & 0x3FFFF);
  204. sprintf(buf, "If-Modified-Since: %srn", mkrfc850(&w));
  205. strcat(msg, buf);
  206.     }
  207.     if (file) {
  208. if ( (file_fd = open(file,O_RDONLY)) < 0) {
  209.     perror("open");
  210.     return -1;
  211. }
  212. if ( fstat(file_fd, &st) ) {
  213.     perror("fstat");
  214.     close(file_fd);
  215.     return -1;
  216. }
  217. sprintf(buf, "Content-length: %drn", st.st_size);
  218. strcat(msg, buf);
  219.     }
  220.     strcat(msg, "rn");
  221.     len = strlen(msg);
  222.     if (write(fd, msg, len) < 0) {
  223. close(fd);
  224. perror("request write");
  225. close(file_fd);
  226. return -1;
  227.     }
  228.     if (file) {
  229. while((len=read(file_fd, buf, sizeof buf)) > 0) {
  230.     if (write(fd, buf, len) < 0) {
  231. close(fd);
  232. perror("body write");
  233. close(file_fd);
  234. return -1;
  235.     }
  236. }
  237. if (len < 0) {
  238.     perror("file read");
  239.     close(file_fd);
  240.     return -1;
  241. }
  242. close(file_fd);
  243.     }
  244.     r = calloc(1, sizeof(struct _r));
  245.     strcpy(r->url, url);
  246.     if (size)
  247. r->validsize = atoi(size);
  248.     else
  249. r->validsize = -1;
  250.     if (checksum)
  251. r->validsum = atoi(checksum);
  252.     for (R = &Requests; *R; R = &(*R)->next);
  253.     *R = r;
  254. /*    fprintf(stderr, "REQUESTED %sn", url); */
  255.     noutstanding++;
  256.     return 0;
  257. }
  258. static int
  259. get_header_int_value(const char *hdr, const char *buf, const char *end)
  260. {
  261.     const char *t;
  262.     for (t = buf; t < end; t += strcspn(t, crlf), t += strspn(t, crlf)) {
  263. if (strncasecmp(t, hdr, strlen(hdr)) == 0) {
  264.     t += strlen(hdr);
  265.     while (isspace(*t))
  266. t++;
  267.     return atoi(t);
  268. }
  269.     }
  270.     return -1;
  271. }
  272. static const char *
  273. get_header_string_value(const char *hdr, const char *buf, const char *end)
  274. {
  275.     const char *t;
  276.     static char result[8192];
  277.     for (t = buf; t < end; t += strcspn(t, crlf), t += strspn(t, crlf)) {
  278. if (strncasecmp(t, hdr, strlen(hdr)) == 0) {
  279.     t += strlen(hdr);
  280.     while (isspace(*t))
  281. t++;
  282.     strcpy(result,"");
  283.     strncat(result,t,strcspn(t, crlf));
  284.     return result;
  285. }
  286.     }
  287.     return NULL;
  288. }
  289. void
  290. request_done(struct _r *r)
  291. {
  292. #if 0
  293.     fprintf(stderr, "DONE: %s, (%d+%d)n",
  294.     r->url,
  295.     r->hdr_length,
  296.     r->content_length);
  297. #endif
  298.     if (r->content_length != r->bytes_read)
  299. fprintf(stderr, "ERROR! Short reply, expected %d bytes got %dn",
  300.     r->content_length, r->bytes_read);
  301.     else if (r->validsize >= 0) {
  302. if (r->validsize != r->bytes_read)
  303.     fprintf(stderr, "WARNING: %s Object size mismatch, expected %d got %dn",
  304.     r->url, r->validsize, r->bytes_read);
  305. else if (opt_checksum && r->sum != r->validsum)
  306.     fprintf(stderr, "WARNING: %s Checksum error. Expected %d got %dn",
  307.     r->url, r->validsum, r->sum);
  308.     }
  309. }
  310. int
  311. handle_read(char *inbuf, int len)
  312. {
  313.     struct _r *r = Requests;
  314.     const char *end;
  315.     const char *url;
  316.     static char buf[READ_BUF_SZ];
  317.     int hlen,blen;
  318.     if (len < 0 ) {
  319. perror("read");
  320. Requests = r->next;
  321. request_done(r);
  322. free(r);
  323. noutstanding--;
  324. if (trace_fd >= 0)
  325.     write(trace_fd,"n[CLOSED]n",10);
  326. return -1;
  327.     }
  328.     total_bytes_read += len;
  329.     xmemcpy(buf,inbuf,len);
  330.     if (len == 0) {
  331. fprintf(stderr, "WARNING: %s, server closed socket after %d+%d bytesn", r->url, r->hdr_offset, r->bytes_read);
  332. /* XXX, If no data was received and it isn't the first request on this
  333.  * connection then the request should be restarted rather than aborted
  334.  * but this is a simple test program an not a full blown HTTP client.
  335.  */
  336. request_done(r);
  337. Requests = r->next;
  338. free(r);
  339. noutstanding--;
  340. return -1;
  341.     }
  342.     if (trace_fd > 0)
  343. write(trace_fd, buf, len);
  344.     while (len > 0) {
  345. /* Build headers */
  346. if (r->hdr_length == 0) {
  347.     hlen = min(len, REPLY_HDR_SZ - r->hdr_offset - 1);
  348.     xmemcpy(r->reply_hdrs + r->hdr_offset, buf, hlen);
  349.     r->hdr_offset += hlen;
  350.     r->reply_hdrs[r->hdr_offset] = '';
  351.     len -= hlen;
  352.     /* Save any remaining read data */
  353.     xmemmove(buf, buf + hlen, len);
  354. }
  355. /* Process headers */
  356. if (r->hdr_length == 0 && (end = mime_headers_end(r->reply_hdrs)) != NULL) {
  357. #if 0
  358.     fprintf(stderr, "FOUND EOH FOR %sn", r->url); */
  359. #endif
  360.     r->hdr_length = end - r->reply_hdrs;
  361. #if 0
  362.       fprintf(stderr, "HDR_LENGTH = %dn", r->hdr_length);
  363. #endif
  364.     /* "unread" any body contents received */
  365.     blen = r->hdr_offset - r->hdr_length;
  366.     assert(blen >= 0);
  367.     if (blen > 0) {
  368. xmemmove(buf + blen, buf, len);
  369. xmemcpy(buf, r->reply_hdrs + r->hdr_length, blen);
  370. len += blen;
  371.     }
  372.     r->reply_hdrs[r->hdr_length]=''; /* Null terminate headers */
  373.     /* Parse headers */
  374.     r->content_length = get_header_int_value("content-length:", r->reply_hdrs, end);
  375. /*     fprintf(stderr, "CONTENT_LENGTH = %dn", r->content_length); */
  376.     url = get_header_string_value("X-Request-URI:", r->reply_hdrs, end);
  377.     if (url != NULL && strcmp(r->url, url) != 0)
  378. fprintf(stderr, "WARNING: %s got reply %sn", r->url, url);
  379. #if XREQUESTURI || 0
  380.     fprintf(stderr, "LOCATION = %sn", get_header_string_value("X-Request-URI:", r->reply_hdrs, end));  
  381. #endif
  382. }
  383. if ( !(len==0 || r->hdr_length > 0) ) {
  384.     fprintf(stderr, "ERROR!!!n");
  385.     assert((len==0 || r->hdr_length > 0));
  386. }
  387. /* Process body */
  388. if (r->hdr_length != 0) {
  389.     int i;
  390.     int bytes_left, bytes_used;
  391.     if (r->content_length >= 0) {
  392. bytes_left = r->content_length - r->bytes_read;
  393. assert(bytes_left >= 0);
  394.      bytes_used = len < bytes_left ? len : bytes_left;
  395.     } else {
  396. bytes_left = len + 1; /* Unknown end... */
  397. bytes_used = len;
  398.     }
  399.     if (opt_checksum) {
  400. for(i=0; i<bytes_used; i++)
  401.     r->sum += (int)buf[i] & 0xFF;
  402.     }
  403.     r->bytes_read += bytes_used;
  404.     len -= bytes_used;
  405.     if (bytes_left == bytes_used) {
  406. request_done(r);
  407. Requests = r->next;
  408. free(r);
  409. noutstanding--;
  410. r = Requests;
  411.     } else if (r->content_length > -1) {
  412. assert(r->bytes_read < r->content_length);
  413.     }
  414.     xmemmove(buf, buf + bytes_used, len);
  415. }
  416.     }
  417.     return 0;
  418. }
  419. int
  420. read_reply(int fd)
  421. {
  422.     static char buf[READ_BUF_SZ];
  423.     int len;
  424.     int x;
  425.     len = read(fd, buf, READ_BUF_SZ);
  426.     x = handle_read(buf, len);
  427.     if (x < 0) {
  428. perror("read reply");
  429. close(fd);
  430.     }
  431.     return x;
  432. }
  433. void
  434. main_loop(void)
  435. {
  436.     static int pconn_fd = -1;
  437.     static char buf[8192];
  438.     struct timeval to;
  439.     struct timeval now,last,start;
  440.     fd_set R;
  441.     struct _r *r;
  442.     struct _r *nextr;
  443.     int x;
  444.     int timeouts;
  445.     int nrequests = 0, rrequests = 0, reqpersec = 0;
  446.     gettimeofday(&start, NULL);
  447.     last = start;
  448.     pconn_fd = open_http_socket();
  449.     if (pconn_fd < 0) {
  450. perror("socket");
  451. exit(1);
  452.     }
  453.     while (!done_reading_urls || noutstanding) {
  454. if (!opt_reopen && pconn_fd < 0) {
  455.     fprintf(stderr,"TERMINATED: Connection closedn");
  456.     break;
  457. }
  458. if (pconn_fd<0) {
  459.     pconn_fd = open_http_socket();
  460.     if (pconn_fd < 0) {
  461. perror("socket");
  462. exit(1);
  463.     }
  464.     nextr = Requests;
  465.     Requests = NULL;
  466.     noutstanding=0;
  467.     while ((r = nextr) != NULL) {
  468. nextr = r->next;
  469. if (send_request(pconn_fd, r->url) != 0) {
  470.     close(pconn_fd);
  471.     pconn_fd=-1;
  472.     nextr = r;
  473.     for (r = Requests; r!=NULL && r->next; r=r->next);
  474.     if (r != NULL)
  475. r->next = nextr;
  476.     else
  477. Requests = nextr;
  478.     break;
  479. }
  480. free(r);
  481.     }
  482.     timeouts = 0;
  483.     if (pconn_fd <0)
  484. continue;
  485. }
  486. if (timeouts == 200) {
  487.     close(pconn_fd);
  488.     pconn_fd = -1;
  489.     r = Requests;
  490.     Requests = Requests->next;
  491.     fprintf(stderr, "ABORT %sn", Requests->url);
  492.     free(r);
  493.     noutstanding--;
  494. }
  495. if (pconn_fd>=0 && noutstanding < max_outstanding && !done_reading_urls) {
  496.     char *t;
  497.     if (fgets(buf, 8191, stdin) == NULL) {
  498. fprintf(stderr, "Done Reading URLSn");
  499. done_reading_urls = 1;
  500. continue;
  501.     }
  502.     rrequests++;
  503.     if ((t = strchr(buf, 'n')))
  504. *t = '';
  505.     if (send_request(pconn_fd, buf) != 0) {
  506. close(pconn_fd);
  507. pconn_fd=-1;
  508. continue;
  509.     }
  510.     nrequests++;
  511.     reqpersec++;
  512.     timeouts = 0;
  513. }
  514. FD_ZERO(&R);
  515. to.tv_sec = 1;
  516. to.tv_usec = 0;
  517. FD_SET(pconn_fd, &R);
  518. x = select(pconn_fd + 1, &R, NULL, NULL, &to);
  519. if (x < 0) {
  520.     if (errno != EINTR)
  521. perror("select");
  522.     continue;
  523. } else if (x == 0) {
  524.     assert(Requests != NULL);
  525.     fprintf(stderr, "TIMEOUT %s; %d, %dn", Requests->url,
  526. ++timeouts, noutstanding);
  527.     continue;
  528. }
  529. if (FD_ISSET(pconn_fd, &R)) {
  530.     timeouts = 0;
  531.     if (read_reply(pconn_fd) != 0)
  532. pconn_fd = -1;
  533. }
  534. gettimeofday(&now, NULL);
  535.         if (now.tv_sec > last.tv_sec) {
  536.     int dt;
  537.     int nreq;
  538.     last = now;
  539.     dt = (int) (now.tv_sec - start.tv_sec);
  540.     nreq=0;
  541.     for (r=Requests; r ; r=r->next) nreq++;
  542.     printf("T+ %6d: %9d req (%+4d), %4d pend, %3d/sec avg, %dmb, %dkb/sec avgn",
  543.     dt,
  544.     nrequests,
  545.     reqpersec,
  546.     nreq,
  547.     (int) (nrequests / dt),
  548.     (int)total_bytes_read / 1024 / 1024,
  549.     (int)total_bytes_read / 1024 / dt);
  550.     reqpersec = 0;
  551. }
  552.     }
  553. }
  554. void
  555. usage(void)
  556. {
  557.     fprintf(stderr, "usage: %s: -p port -h host -n max -t tracefile -i -c -l lifetimen", progname);
  558. }
  559. int
  560. main(argc, argv)
  561.      int argc;
  562.      char *argv[];
  563. {
  564.     int c;
  565.     setbuf(stdout, NULL);
  566.     setbuf(stderr, NULL);
  567.     progname = strdup(argv[0]);
  568.     while ((c = getopt(argc, argv, "p:h:n:t:icl:r")) != -1) {
  569. switch (c) {
  570. case 'p':
  571.     proxy_port = atoi(optarg);
  572.     break;
  573. case 'h':
  574.     proxy_addr = strdup(optarg);
  575.     break;
  576. case 'n':
  577.     max_outstanding = atoi(optarg);
  578.     break;
  579. case 'i':
  580.     opt_ims = 1;
  581.     break;
  582. case 'c':
  583.     opt_checksum = 1;
  584.     break;
  585. case 'l':
  586.     lifetime = (time_t) atoi(optarg);
  587.     break;
  588. case 't':
  589.     trace_fd = open(optarg,O_WRONLY|O_CREAT|O_TRUNC,0666);
  590.     break;
  591. case 'r':
  592.     opt_reopen = !opt_reopen;
  593.     break;
  594. default:
  595.     usage();
  596.     return 1;
  597. }
  598.     }
  599.     signal(SIGINT, sig_intr);
  600.     signal(SIGPIPE, SIG_IGN);
  601.     main_loop();
  602.     return 0;
  603. }