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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors