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