]> git.ipfire.org Git - thirdparty/squid.git/blame - test-suite/tcp-banger2.c
Import of fix-ranges branch
[thirdparty/squid.git] / test-suite / tcp-banger2.c
CommitLineData
58a96f63 1#include "config.h"
6a54c60e 2
528b2c61 3/* $Id: tcp-banger2.c,v 1.24 2003/01/23 00:38:34 robertc Exp $ */
58a96f63 4
5/* Increase FD_SETSIZE if SQUID_MAXFD is bigger */
6#if CHANGE_FD_SETSIZE && SQUID_MAXFD > DEFAULT_FD_SETSIZE
7#define FD_SETSIZE SQUID_MAXFD
8#endif
9
10#if HAVE_UNISTD_H
735246e8 11#include <unistd.h>
58a96f63 12#endif
13#if HAVE_STDLIB_H
735246e8 14#include <stdlib.h>
58a96f63 15#endif
16#if HAVE_STDIO_H
17#include <stdio.h>
18#endif
19#if HAVE_FCNTL_H
735246e8 20#include <fcntl.h>
58a96f63 21#endif
22#ifdef HAVE_STRING_H
735246e8 23#include <string.h>
58a96f63 24#endif
25#ifdef HAVE_STRINGS_H
735246e8 26#include <strings.h>
58a96f63 27#endif
28#if HAVE_SYS_TYPES_H
735246e8 29#include <sys/types.h>
58a96f63 30#endif
31#if HAVE_SYS_SELECT_H
735246e8 32#include <sys/select.h>
58a96f63 33#endif
34#if HAVE_SIGNAL_H
735246e8 35#include <signal.h>
58a96f63 36#endif
37#if HAVE_TIME_H
735246e8 38#include <time.h>
58a96f63 39#endif
40#if HAVE_SYS_TIME_H
735246e8 41#include <sys/time.h>
58a96f63 42#endif
43#if HAVE_SYS_SOCKET_H
735246e8 44#include <sys/socket.h>
58a96f63 45#endif
46#if HAVE_NETINET_IN_H
735246e8 47#include <netinet/in.h>
58a96f63 48#endif
49#if HAVE_ARPA_INET_H
735246e8 50#include <arpa/inet.h>
58a96f63 51#endif
52#if HAVE_ERRNO_H
735246e8 53#include <errno.h>
58a96f63 54#endif
14ff08f1 55#if HAVE_SYS_STAT_H
56#include <sys/stat.h>
57#endif
58#if HAVE_ASSERT_H
59#include <assert.h>
60#endif
b6a2f15e 61#if HAVE_CTYPE_H
62#include <ctype.h>
63#endif
735246e8 64
65#define PROXY_PORT 3128
66#define PROXY_ADDR "127.0.0.1"
735246e8 67#define READ_BUF_SZ 4096
68
69static int proxy_port = PROXY_PORT;
70static char *proxy_addr = PROXY_ADDR;
71static char *progname;
72static int reqpersec;
73static int nrequests;
74static int opt_ims = 0;
c4248266 75static int opt_range = 0;
6f821399 76static int opt_accel = 0;
735246e8 77static int max_connections = 64;
33fda8cd 78static time_t lifetime = 60;
15dd95c1 79static time_t process_lifetime = 86400;
33fda8cd 80static struct timeval now;
14ff08f1 81static long total_bytes_written = 0;
82static long total_bytes_read = 0;
83static int opt_checksum = 0;
ed2ab7db 84FILE *trace_file = NULL;
735246e8 85
86typedef void (CB) (int, void *);
87
88struct _f {
89 CB *cb;
14ff08f1 90 CB *ccb;
735246e8 91 void *data;
33fda8cd 92 time_t start;
735246e8 93};
14ff08f1 94struct _request {
95 int fd;
7d97d03c 96 char *url;
ed2ab7db 97 char method[16];
98 char requestbodyfile[256];
14ff08f1 99 char buf[READ_BUF_SZ * 2 + 1];
100 int headfound;
2444b689 101 int validsize;
102 int bodysize;
103 int content_length;
55095043 104 int status;
14ff08f1 105 long validsum;
14ff08f1 106 long sum;
14ff08f1 107};
735246e8 108
b61d6f3d 109struct _f FD[SQUID_MAXFD];
735246e8 110int nfds = 0;
111int maxfd = 0;
112
113
7d97d03c 114static void
115free_request(struct _request *r)
116{
55095043 117 if (r->url)
118 free(r->url);
119 free(r);
7d97d03c 120}
121
528b2c61 122#define RFC1123_STRFTIME "%a, %d %b %Y %H:%M:%S GMT"
735246e8 123char *
528b2c61 124mkrfc1123(t)
6a54c60e 125 time_t *t;
735246e8 126{
127 static char buf[128];
128 struct tm *gmt = gmtime(t);
129 buf[0] = '\0';
528b2c61 130 (void) strftime(buf, 127, RFC1123_STRFTIME, gmt);
735246e8 131 return buf;
132}
133
134void
135fd_close(int fd)
136{
137 close(fd);
14ff08f1 138 if (FD[fd].ccb)
139 FD[fd].ccb(fd, FD[fd].data);
140 FD[fd].ccb = NULL;
735246e8 141 FD[fd].cb = NULL;
142 FD[fd].data = NULL;
143 nfds--;
144 if (fd == maxfd) {
aeb649da 145 while (fd > 0 && FD[fd].cb == NULL)
6a54c60e 146 fd--;
735246e8 147 maxfd = fd;
148 }
149}
150
151void
3cd80ef8 152fd_open(int fd, CB * cb, void *data, CB * ccb)
735246e8 153{
b61d6f3d 154 assert(fd < SQUID_MAXFD);
735246e8 155 FD[fd].cb = cb;
14ff08f1 156 FD[fd].ccb = ccb;
735246e8 157 FD[fd].data = data;
33fda8cd 158 FD[fd].start = now.tv_sec;
735246e8 159 if (fd > maxfd)
160 maxfd = fd;
161 nfds++;
162}
163
164void
165sig_intr(int sig)
166{
6a54c60e 167 fd_close(0);
14ff08f1 168 nfds++;
6a54c60e 169 printf("\rWaiting for open connections to finish...\n");
170 signal(sig, SIG_DFL);
735246e8 171}
172
6a54c60e 173void
735246e8 174read_reply(int fd, void *data)
175{
14ff08f1 176 struct _request *r = data;
177 static unsigned char buf[READ_BUF_SZ];
178 int len;
1707acbe 179 int used = 0;
3cd80ef8 180 if ((len = read(fd, buf, READ_BUF_SZ)) <= 0) {
6a54c60e 181 fd_close(fd);
182 reqpersec++;
183 nrequests++;
1707acbe 184 return;
185 }
186 total_bytes_read += len;
187 if (r->headfound < 2) {
188 char *p, *header = NULL;
189 int oldlen = strlen(r->buf);
190 int newlen = oldlen + len;
191 assert(oldlen <= READ_BUF_SZ);
192 memcpy(r->buf + oldlen, buf, len);
193 r->buf[newlen + 1] = '\0';
194 for (p = r->buf; r->headfound < 2 && used < newlen; p++, used++) {
195 switch (*p) {
196 case '\n':
197 r->headfound++;
198 if (!header)
14ff08f1 199 break;
1707acbe 200 /* Decode header */
b6a2f15e 201 if (strncmp(header, "HTTP", 4) == 0)
202 r->status = atoi(header + 8);
203 else if (strncasecmp(header, "Content-Length:", 15) == 0)
1707acbe 204 r->content_length = atoi(header + 15);
b6a2f15e 205 else if (strncasecmp(header, "X-Request-URI:", 14) == 0) {
1707acbe 206 /* Check URI */
207 if (strncmp(r->url, header + 15, strcspn(header + 15, "\r\n"))) {
208 char url[8192];
209 strncpy(url, header + 15, strcspn(header + 15, "\r\n"));
210 url[strcspn(header + 15, "\r\n")] = '\n';
211 fprintf(stderr, "ERROR: Sent %s received %s\n",
212 r->url, url);
213 }
14ff08f1 214 }
1707acbe 215 header = NULL;
216 break;
217 case '\r':
218 break;
219 default:
220 r->headfound = 0;
221 if (!header)
222 header = p;
223 break;
14ff08f1 224 }
14ff08f1 225 }
1707acbe 226 if (header) {
227 memmove(r->buf, header, newlen - (header - r->buf) + 1);
228 }
229 assert(used >= oldlen);
230 used -= oldlen;
231 }
232 r->bodysize += len - used;
233 if (opt_checksum) {
234 for (; used < len; used++) {
235 r->sum += buf[used];
14ff08f1 236 }
6a54c60e 237 }
735246e8 238}
239
14ff08f1 240void
241reply_done(int fd, void *data)
735246e8 242{
14ff08f1 243 struct _request *r = data;
3cd80ef8 244 if (opt_range); /* skip size checks for now */
2444b689 245 else if (r->bodysize != r->content_length && r->content_length >= 0)
3cd80ef8 246 fprintf(stderr, "ERROR: %s got %d of %d bytes\n",
247 r->url, r->bodysize, r->content_length);
14ff08f1 248 else if (r->validsize >= 0) {
249 if (r->validsize != r->bodysize)
3cd80ef8 250 fprintf(stderr, "WARNING: %s size mismatch wanted %d bytes got %d\n",
251 r->url, r->validsize, r->bodysize);
14ff08f1 252 else if (opt_checksum && r->validsum != r->sum)
3cd80ef8 253 fprintf(stderr, "WARNING: %s invalid checksum wanted 0x%lx got 0x%lx\n",
254 r->url, r->validsum, r->sum);
ed2ab7db 255 }
256 if (trace_file) {
b6a2f15e 257 if (opt_checksum)
258 fprintf(trace_file, "%s %s %d %s %d 0x%lx\n",
259 r->method, r->url, r->status, r->requestbodyfile, r->bodysize, r->sum);
260 else
261 fprintf(trace_file, "%s %s %d %s %d\n",
262 r->method, r->url, r->status, r->requestbodyfile, r->bodysize);
14ff08f1 263 }
7d97d03c 264 free_request(r);
14ff08f1 265}
266
267struct _request *
268request(char *urlin)
269{
3cd80ef8 270 int s = -1, f = -1;
735246e8 271 char buf[4096];
14ff08f1 272 char msg[8192];
b6a2f15e 273 char *method, *url, *file, *size, *checksum;
6f821399 274 char *host;
14ff08f1 275 char urlbuf[8192];
3cd80ef8 276 int len, len2;
735246e8 277 time_t w;
14ff08f1 278 struct stat st;
735246e8 279 struct sockaddr_in S;
14ff08f1 280 struct _request *r;
206b24db 281 if (*urlin == '\0')
282 return NULL;
735246e8 283 if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
284 perror("socket");
14ff08f1 285 return NULL;
735246e8 286 }
287 memset(&S, '\0', sizeof(struct sockaddr_in));
288 S.sin_family = AF_INET;
289 S.sin_port = htons(proxy_port);
290 S.sin_addr.s_addr = inet_addr(proxy_addr);
6a54c60e 291 if (connect(s, (struct sockaddr *) &S, sizeof(S)) < 0) {
735246e8 292 close(s);
293 perror("connect");
14ff08f1 294 return NULL;
735246e8 295 }
3cd80ef8 296 strcpy(urlbuf, urlin);
297 method = strtok(urlbuf, " ");
298 url = strtok(NULL, " ");
299 file = strtok(NULL, " ");
300 size = strtok(NULL, " ");
301 checksum = strtok(NULL, " ");
14ff08f1 302 if (!url) {
3cd80ef8 303 url = method;
304 method = "GET";
14ff08f1 305 }
ed2ab7db 306 if (!file)
3cd80ef8 307 file = "-";
ed2ab7db 308 if (!size)
3cd80ef8 309 size = "-";
ed2ab7db 310 if (!checksum)
3cd80ef8 311 checksum = "-";
312 r = calloc(1, sizeof *r);
313 assert(r != NULL);
7d97d03c 314 r->url = strdup(url);
315 assert(r->url);
ed2ab7db 316 strcpy(r->method, method);
317 strcpy(r->requestbodyfile, file);
14ff08f1 318 r->fd = s;
3cd80ef8 319 if (size && strcmp(size, "-") != 0)
320 r->validsize = atoi(size);
14ff08f1 321 else
3cd80ef8 322 r->validsize = -1; /* Unknown */
323 if (checksum && strcmp(checksum, "-") != 0)
324 r->validsum = strtoul(checksum, NULL, 0);
325 r->content_length = -1; /* Unknown */
6f821399 326 if (opt_accel) {
327 host = strchr(url, '/') + 2;
328 url = strchr(host, '/');
329 } else {
330 host = NULL;
331 }
332 sprintf(msg, "%s %s HTTP/1.0\r\n", method, url);
333 if (host) {
334 url[0] = '\0';
335 sprintf(buf, "Host: %s\r\n", host);
336 strcat(msg, buf);
337 url[0] = '/';
338 }
14ff08f1 339 strcat(msg, "Accept: */*\r\n");
735246e8 340 if (opt_ims && (lrand48() & 0x03) == 0) {
341 w = time(NULL) - (lrand48() & 0x3FFFF);
528b2c61 342 sprintf(buf, "If-Modified-Since: %s\r\n", mkrfc1123(&w));
3cd80ef8 343 strcat(msg, buf);
735246e8 344 }
3cd80ef8 345 if (file && strcmp(file, "-") != 0) {
346 f = open(file, O_RDONLY);
14ff08f1 347 if (f < 0) {
348 perror("open file");
349 exit(1);
350 }
351 fstat(f, &st);
3cd80ef8 352 sprintf(buf, "Content-Length: %d\r\n", (int) st.st_size);
353 strcat(msg, buf);
14ff08f1 354 }
c4248266 355 if (opt_range && (lrand48() & 0x03) == 0) {
356 int len;
357 int count = 0;
358 strcat(msg, "Range: bytes=");
3cd80ef8 359 while (((len = (int) lrand48()) & 0x03) == 0 || !count) {
c4248266 360 const int offset = (int) lrand48();
361 if (count)
362 strcat(msg, ",");
363 switch (lrand48() & 0x03) {
3cd80ef8 364 case 0:
365 sprintf(buf, "-%d", len);
366 break;
367 case 1:
368 sprintf(buf, "%d-", offset);
369 break;
370 default:
371 sprintf(buf, "%d-%d", offset, offset + len);
372 break;
c4248266 373 }
3cd80ef8 374 strcat(msg, buf);
c4248266 375 count++;
376 }
3cd80ef8 377 strcat(msg, "\r\n");
c4248266 378 }
14ff08f1 379 strcat(msg, "\r\n");
380 len = strlen(msg);
3cd80ef8 381 if ((len2 = write(s, msg, len)) != len) {
735246e8 382 close(s);
14ff08f1 383 perror("write request");
7d97d03c 384 free_request(r);
14ff08f1 385 return NULL;
386 } else
387 total_bytes_written += len2;
3cd80ef8 388 if (f >= 0) {
389 while ((len = read(f, buf, sizeof(buf))) > 0) {
14ff08f1 390 len2 = write(s, buf, len);
391 if (len2 < 0) {
392 perror("write body");
393 close(s);
7d97d03c 394 free_request(r);
14ff08f1 395 }
396 }
397 if (len < 0) {
398 perror("read body");
399 exit(1);
400 }
735246e8 401 }
402/*
6a54c60e 403 * if (fcntl(s, F_SETFL, O_NDELAY) < 0)
404 * perror("fcntl O_NDELAY");
405 */
14ff08f1 406 return r;
735246e8 407}
408
409void
410read_url(int fd, void *junk)
411{
14ff08f1 412 struct _request *r;
735246e8 413 static char buf[8192];
414 char *t;
206b24db 415 buf[0] = '\0';
735246e8 416 if (fgets(buf, 8191, stdin) == NULL) {
417 printf("Done Reading URLS\n");
418 fd_close(0);
14ff08f1 419 nfds++;
735246e8 420 return;
421 }
206b24db 422 if (buf[0] == '\0')
423 return;
735246e8 424 if ((t = strchr(buf, '\n')))
425 *t = '\0';
14ff08f1 426 r = request(buf);
427 if (!r) {
6a54c60e 428 max_connections = nfds - 1;
735246e8 429 printf("NOTE: max_connections set at %d\n", max_connections);
14ff08f1 430 } else {
431 fd_open(r->fd, read_reply, r, reply_done);
735246e8 432 }
735246e8 433}
434
435void
436usage(void)
437{
ed2ab7db 438 fprintf(stderr, "usage: %s: -p port -h host -n max\n", progname);
439 fprintf(stderr, " -t <tracefile> Save request trace\n");
440 fprintf(stderr, " -c Check checksum agains trace\n");
441 fprintf(stderr, " -i Send random If-Modified-Since times\n");
442 fprintf(stderr, " -l <seconds> Connection lifetime timeout (default 60)\n");
6f821399 443 fprintf(stderr, " -a Accelerator mode\n");
735246e8 444}
445
6a54c60e 446int
735246e8 447main(argc, argv)
6a54c60e 448 int argc;
449 char *argv[];
735246e8 450{
451 int i;
452 int c;
453 int dt;
14ff08f1 454 int j;
3cd80ef8 455 fd_set R, R2;
735246e8 456 struct timeval start;
735246e8 457 struct timeval last;
458 struct timeval to;
459 setbuf(stdout, NULL);
460 setbuf(stderr, NULL);
461 progname = strdup(argv[0]);
14ff08f1 462 gettimeofday(&now, NULL);
463 start = last = now;
6f821399 464 while ((c = getopt(argc, argv, "ap:h:n:icrl:L:t:")) != -1) {
6a54c60e 465 switch (c) {
6f821399 466 case 'a':
467 opt_accel = 1;
468 break;
735246e8 469 case 'p':
6a54c60e 470 proxy_port = atoi(optarg);
471 break;
735246e8 472 case 'h':
6a54c60e 473 proxy_addr = strdup(optarg);
474 break;
735246e8 475 case 'n':
6a54c60e 476 max_connections = atoi(optarg);
477 break;
735246e8 478 case 'i':
6a54c60e 479 opt_ims = 1;
480 break;
33fda8cd 481 case 'l':
482 lifetime = (time_t) atoi(optarg);
483 break;
15dd95c1 484 case 'L':
485 process_lifetime = (time_t) atoi(optarg);
486 break;
14ff08f1 487 case 'c':
488 opt_checksum = 1;
489 break;
ed2ab7db 490 case 't':
b6a2f15e 491 trace_file = fopen(optarg, "a");
ed2ab7db 492 assert(trace_file);
b6a2f15e 493 setbuf(trace_file, NULL);
ed2ab7db 494 break;
c4248266 495 case 'r':
496 opt_range = 1;
497 break;
735246e8 498 default:
6a54c60e 499 usage();
500 return 1;
501 }
735246e8 502 }
14ff08f1 503 fd_open(0, read_url, NULL, NULL);
504 nfds--;
735246e8 505 signal(SIGINT, sig_intr);
5616e319 506 signal(SIGPIPE, SIG_IGN);
14ff08f1 507 FD_ZERO(&R2);
508 while (nfds || FD[0].cb) {
735246e8 509 FD_ZERO(&R);
510 to.tv_sec = 0;
511 to.tv_usec = 100000;
512 if (nfds < max_connections && FD[0].cb)
513 FD_SET(0, &R);
514 for (i = 1; i <= maxfd; i++) {
515 if (FD[i].cb == NULL)
516 continue;
33fda8cd 517 if (now.tv_sec - FD[i].start > lifetime) {
a19d9329 518 fprintf(stderr, "WARNING: fd %d lifetime timeout\n", i);
33fda8cd 519 fd_close(i);
520 continue;
521 }
735246e8 522 FD_SET(i, &R);
523 }
524 if (select(maxfd + 1, &R, NULL, NULL, &to) < 0) {
14ff08f1 525 fprintf(stderr, "maxfd=%d\n", maxfd);
735246e8 526 if (errno != EINTR)
6a54c60e 527 perror("select");
735246e8 528 continue;
529 }
14ff08f1 530 gettimeofday(&now, NULL);
735246e8 531 for (i = 0; i <= maxfd; i++) {
532 if (!FD_ISSET(i, &R))
533 continue;
534 FD[i].cb(i, FD[i].data);
3cd80ef8 535 if (nfds < max_connections && FD[0].cb) {
536 j = 0;
537 FD_SET(0, &R2);
538 to.tv_sec = 0;
539 to.tv_usec = 0;
540 if (select(1, &R2, NULL, NULL, &to) == 1)
14ff08f1 541 FD[0].cb(0, FD[0].data);
542 }
735246e8 543 }
735246e8 544 if (now.tv_sec > last.tv_sec) {
6a54c60e 545 last = now;
546 dt = (int) (now.tv_sec - start.tv_sec);
14ff08f1 547 printf("T+ %6d: %9d req (%+4d), %4d conn, %3d/sec avg, %dmb, %dkb/sec avg\n",
6a54c60e 548 dt,
549 nrequests,
550 reqpersec,
551 nfds,
14ff08f1 552 (int) (nrequests / dt),
3cd80ef8 553 (int) total_bytes_read / 1024 / 1024,
554 (int) total_bytes_read / 1024 / dt);
6a54c60e 555 reqpersec = 0;
b6a2f15e 556 /*
557 * if (dt > process_lifetime)
558 * exit(0);
559 */
735246e8 560 }
561 }
b6a2f15e 562 printf("Exiting normally\n");
735246e8 563 return 0;
564}