]> git.ipfire.org Git - thirdparty/squid.git/blob - test-suite/tcp-banger2.c
- added missing else to "skip size checks for now"
[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
105 typedef void (CB) (int, void *);
106
107 struct _f {
108 CB *cb;
109 CB *ccb;
110 void *data;
111 time_t start;
112 };
113 struct _request {
114 int fd;
115 char url[8192];
116 char buf[READ_BUF_SZ * 2 + 1];
117 int headfound;
118 long validsize;
119 long validsum;
120 long bodysize;
121 long sum;
122 int content_length;
123 };
124
125 struct _f FD[MAX_FDS];
126 int nfds = 0;
127 int maxfd = 0;
128
129
130 char *
131 mkrfc850(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 void
142 fd_close(int fd)
143 {
144 close(fd);
145 if (FD[fd].ccb)
146 FD[fd].ccb(fd, FD[fd].data);
147 FD[fd].ccb = NULL;
148 FD[fd].cb = NULL;
149 FD[fd].data = NULL;
150 nfds--;
151 if (fd == maxfd) {
152 while (fd > 0 && FD[fd].cb == NULL)
153 fd--;
154 maxfd = fd;
155 }
156 }
157
158 void
159 fd_open(int fd, CB * cb, void *data, CB *ccb)
160 {
161 FD[fd].cb = cb;
162 FD[fd].ccb = ccb;
163 FD[fd].data = data;
164 FD[fd].start = now.tv_sec;
165 if (fd > maxfd)
166 maxfd = fd;
167 nfds++;
168 }
169
170 void
171 sig_intr(int sig)
172 {
173 fd_close(0);
174 nfds++;
175 printf("\rWaiting for open connections to finish...\n");
176 signal(sig, SIG_DFL);
177 }
178
179 void
180 read_reply(int fd, void *data)
181 {
182 struct _request *r = data;
183 static unsigned char buf[READ_BUF_SZ];
184 int len;
185 if ((len=read(fd, buf, READ_BUF_SZ)) <= 0) {
186 fd_close(fd);
187 reqpersec++;
188 nrequests++;
189 } else {
190 int used=0;
191 total_bytes_read+=len;
192 if (r->headfound < 2) {
193 char *p,*header = NULL;
194 int oldlen = strlen(r->buf);
195 int newlen = oldlen + len;
196 assert(oldlen <= READ_BUF_SZ);
197 memcpy(r->buf+oldlen, buf, len);
198 r->buf[newlen+1]='\0';
199 for(p=r->buf; r->headfound < 2 && used<newlen; p++,used++) {
200 switch(*p) {
201 case '\n':
202 r->headfound++;
203 if (header) {
204 /* Decode header */
205 if (strncasecmp(header,"Content-Length:",15)==0)
206 r->content_length = atoi(header+15);
207 if (strncasecmp(header,"X-Request-URI:",14)==0) {
208 /* Check URI */
209 if (strncmp(r->url, header+15, strcspn(header+15,"\r\n"))) {
210 char url[8192];
211 strncpy(url, header+15, strcspn(header+15,"\r\n"));
212 url[strcspn(header+15, "\r\n")]='\n';
213 fprintf(stderr,"ERROR: Sent %s received %s\n",
214 r->url, url);
215 }
216 }
217 header=NULL;
218 }
219 break;
220 case '\r':
221 break;
222 default:
223 r->headfound=0;
224 if (!header)
225 header = p;
226 break;
227 }
228 }
229 if (header) {
230 memmove(r->buf, header, newlen - (header - r->buf) + 1);
231 }
232 }
233 r->bodysize+=len-used;
234 if (opt_checksum) {
235 for (; used<len ; used++) {
236 r->sum += buf[used];
237 }
238 }
239 }
240 }
241
242 void
243 reply_done(int fd, void *data)
244 {
245 struct _request *r = data;
246 if (opt_range)
247 ; /* skip size checks for now */
248 else
249 if (r->bodysize != r->content_length)
250 fprintf(stderr,"ERROR: %s expected %d bytes got %d\n",
251 r->url, r->content_length, r->bodysize);
252 else if (r->validsize >= 0) {
253 if (r->validsize != r->bodysize)
254 fprintf(stderr,"WARNING: %s size mismatch wanted %d bytes got %d\n",
255 r->url, r->validsize, r->bodysize);
256 else if (opt_checksum && r->validsum != r->sum)
257 fprintf(stderr,"WARNING: %s invalid checksum wanted %d got %d\n",
258 r->url, r->validsum, r->sum);
259 } else if (opt_checksum) {
260 fprintf(stderr,"DONE: %s checksum %d size %d\n",
261 r->url, r->sum, r->bodysize);
262 }
263 free(r);
264 }
265
266 struct _request *
267 request(char *urlin)
268 {
269 int s=-1,f=-1;
270 char buf[4096];
271 char msg[8192];
272 char *method, *url, *file, *size, *checksum;
273 char urlbuf[8192];
274 int len,len2;
275 time_t w;
276 struct stat st;
277 struct sockaddr_in S;
278 struct _request *r;
279 if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
280 perror("socket");
281 return NULL;
282 }
283 memset(&S, '\0', sizeof(struct sockaddr_in));
284 S.sin_family = AF_INET;
285 S.sin_port = htons(proxy_port);
286 S.sin_addr.s_addr = inet_addr(proxy_addr);
287 if (connect(s, (struct sockaddr *) &S, sizeof(S)) < 0) {
288 close(s);
289 perror("connect");
290 return NULL;
291 }
292 strcpy(urlbuf,urlin);
293 method=strtok(urlbuf," ");
294 url=strtok(NULL," ");
295 file=strtok(NULL," ");
296 size=strtok(NULL," ");
297 checksum=strtok(NULL," ");
298 if (!url) {
299 url=method;
300 method="GET";
301 }
302 r=calloc(1,sizeof *r);
303 assert(r!=NULL);
304 strcpy(r->url, url);
305 r->fd = s;
306 if (size && strcmp(size,"-")!=0)
307 r->validsize=atoi(size);
308 else
309 r->validsize=-1; /* Unknown */
310 if (checksum && strcmp(checksum,"-")!=0)
311 r->validsum=atoi(checksum);
312 msg[0] = '\0';
313 sprintf(buf,"%s %s HTTP/1.0\r\n", method, url);
314 strcat(msg, buf);
315 strcat(msg, "Accept: */*\r\n");
316 if (opt_ims && (lrand48() & 0x03) == 0) {
317 w = time(NULL) - (lrand48() & 0x3FFFF);
318 sprintf(buf, "If-Modified-Since: %s\r\n", mkrfc850(&w));
319 strcat(msg,buf);
320 }
321 if (file && strcmp(file, "-")!=0) {
322 f = open(file,O_RDONLY);
323 if (f < 0) {
324 perror("open file");
325 exit(1);
326 }
327 fstat(f, &st);
328 sprintf(buf,"Content-Length: %d\r\n", st.st_size);
329 strcat(msg,buf);
330 }
331 if (opt_range && (lrand48() & 0x03) == 0) {
332 int len;
333 int count = 0;
334 strcat(msg, "Range: bytes=");
335 while (((len = (int)lrand48()) & 0x03) == 0 || !count) {
336 const int offset = (int) lrand48();
337 if (count)
338 strcat(msg, ",");
339 switch (lrand48() & 0x03) {
340 case 0:
341 sprintf(buf, "-%d", len);
342 break;
343 case 1:
344 sprintf(buf, "%d-", offset);
345 break;
346 default:
347 sprintf(buf, "%d-%d", offset, offset+len);
348 break;
349 }
350 strcat(msg,buf);
351 count++;
352 }
353 strcat(msg,"\r\n");
354 }
355 strcat(msg, "\r\n");
356 len = strlen(msg);
357 if ((len2=write(s, msg, len)) != len) {
358 close(s);
359 perror("write request");
360 free(r);
361 return NULL;
362 } else
363 total_bytes_written += len2;
364 if (f>=0) {
365 while ((len = read(f, buf, sizeof(buf)))>0) {
366 len2 = write(s, buf, len);
367 if (len2 < 0) {
368 perror("write body");
369 close(s);
370 free(r);
371 }
372 }
373 if (len < 0) {
374 perror("read body");
375 exit(1);
376 }
377 }
378
379 /*
380 * if (fcntl(s, F_SETFL, O_NDELAY) < 0)
381 * perror("fcntl O_NDELAY");
382 */
383 return r;
384 }
385
386 void
387 read_url(int fd, void *junk)
388 {
389 struct _request *r;
390 static char buf[8192];
391 char *t;
392 if (fgets(buf, 8191, stdin) == NULL) {
393 printf("Done Reading URLS\n");
394 fd_close(0);
395 nfds++;
396 return;
397 }
398 if ((t = strchr(buf, '\n')))
399 *t = '\0';
400 r = request(buf);
401 if (!r) {
402 max_connections = nfds - 1;
403 printf("NOTE: max_connections set at %d\n", max_connections);
404 } else {
405 fd_open(r->fd, read_reply, r, reply_done);
406 }
407 }
408
409 void
410 usage(void)
411 {
412 fprintf(stderr, "usage: %s: [-cir] -p port -h host -n max\n", progname);
413 }
414
415 int
416 main(argc, argv)
417 int argc;
418 char *argv[];
419 {
420 int i;
421 int c;
422 int dt;
423 int j;
424 fd_set R,R2;
425 struct timeval start;
426 struct timeval last;
427 struct timeval to;
428 setbuf(stdout, NULL);
429 setbuf(stderr, NULL);
430 progname = strdup(argv[0]);
431 gettimeofday(&now, NULL);
432 start = last = now;
433 while ((c = getopt(argc, argv, "p:h:n:icrl:")) != -1) {
434 switch (c) {
435 case 'p':
436 proxy_port = atoi(optarg);
437 break;
438 case 'h':
439 proxy_addr = strdup(optarg);
440 break;
441 case 'n':
442 max_connections = atoi(optarg);
443 break;
444 case 'i':
445 opt_ims = 1;
446 break;
447 case 'l':
448 lifetime = (time_t) atoi(optarg);
449 break;
450 case 'c':
451 opt_checksum = 1;
452 break;
453 case 'r':
454 opt_range = 1;
455 break;
456 default:
457 usage();
458 return 1;
459 }
460 }
461 fd_open(0, read_url, NULL, NULL);
462 nfds--;
463 signal(SIGINT, sig_intr);
464 signal(SIGPIPE, SIG_IGN);
465 FD_ZERO(&R2);
466 while (nfds || FD[0].cb) {
467 FD_ZERO(&R);
468 to.tv_sec = 0;
469 to.tv_usec = 100000;
470 if (nfds < max_connections && FD[0].cb)
471 FD_SET(0, &R);
472 for (i = 1; i <= maxfd; i++) {
473 if (FD[i].cb == NULL)
474 continue;
475 if (now.tv_sec - FD[i].start > lifetime) {
476 fprintf(stderr, "WARNING: fd %d lifetime timeout\n", i);
477 fd_close(i);
478 continue;
479 }
480 FD_SET(i, &R);
481 }
482 if (select(maxfd + 1, &R, NULL, NULL, &to) < 0) {
483 fprintf(stderr, "maxfd=%d\n", maxfd);
484 if (errno != EINTR)
485 perror("select");
486 continue;
487 }
488 gettimeofday(&now, NULL);
489 for (i = 0; i <= maxfd; i++) {
490 if (!FD_ISSET(i, &R))
491 continue;
492 FD[i].cb(i, FD[i].data);
493 if (nfds < max_connections && FD[0].cb) {
494 j=0;
495 FD_SET(0,&R2);
496 to.tv_sec=0;
497 to.tv_usec=0;
498 if(select(1,&R2,NULL,NULL,&to) == 1)
499 FD[0].cb(0, FD[0].data);
500 }
501 }
502 if (now.tv_sec > last.tv_sec) {
503 last = now;
504 dt = (int) (now.tv_sec - start.tv_sec);
505 printf("T+ %6d: %9d req (%+4d), %4d conn, %3d/sec avg, %dmb, %dkb/sec avg\n",
506 dt,
507 nrequests,
508 reqpersec,
509 nfds,
510 (int) (nrequests / dt),
511 (int)total_bytes_read / 1024 / 1024,
512 (int)total_bytes_read / 1024 / dt);
513 reqpersec = 0;
514 }
515 }
516 return 0;
517 }