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