tcp-banger3.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2021 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_NETDB_H
79 #include <netdb.h>
80 #endif
81 #if HAVE_SYS_WAIT_H
82 #include <sys/wait.h>
83 #endif
84 
85 #define READ_BUF_SZ 4096
86 #define URL_BUF_SZ 4096
87 
88 struct _thing {
89  int rfd;
90  int wfd;
91  int state;
92  pid_t pid;
93  char url[URL_BUF_SZ];
94  struct _thing *next;
95 };
96 typedef struct _thing thing;
97 
98 static thing *things = NULL;
99 static fd_set R1;
100 static int maxfd = 0;
101 static struct timeval now;
102 #if DEBUG
103 static int debug = 1;
104 #else
105 static int debug = 0;
106 #endif
107 
108 int
109 tvSubMsec(struct timeval t1, struct timeval t2)
110 {
111  return (t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec) / 1000;
112 }
113 
114 static int
115 get_url(const char *url)
116 {
117  char host[URL_BUF_SZ];
118  char path[URL_BUF_SZ];
119  char request[URL_BUF_SZ];
120  char reply[READ_BUF_SZ];
121  char *t;
122  int x;
123  int s;
124  int nr = 0;
125  struct hostent *h;
126  struct sockaddr_in S;
127  unsigned short port = 80;
128  assert(!strncmp(url, "http://", 7));
129  strncpy(host, url + 7, URL_BUF_SZ);
130  if ((t = strchr(host, '/')))
131  *t = '\0';
132  if ((t = strchr(host, ':'))) {
133  *t = '\0';
134  port = (unsigned short) atoi(t + 1);
135  }
136  t = strchr(url + 7, '/');
137  strncpy(path, (t ? t : "/"), URL_BUF_SZ);
138  memset(&S, '\0', sizeof(S));
139  h = gethostbyname(host);
140  if (!h)
141  return 0;
142  memcpy(&S.sin_addr.s_addr, h->h_addr_list[0], sizeof(S.sin_addr.s_addr));
143  S.sin_port = htons(port);
144  S.sin_family = AF_INET;
145  if (debug) {
146  char tmp[16];
147  fprintf(stderr, "%s (%s) %d %s\n", host, inet_ntop(AF_INET, &S.sin_addr,tmp,sizeof(tmp)), (int) port, path);
148  }
149  s = socket(PF_INET, SOCK_STREAM, 0);
150  if (s < 0) {
151  perror("socket");
152  return -errno;
153  }
154  x = connect(s, (struct sockaddr *) &S, sizeof(S));
155  if (x < 0) {
156  perror(host);
157  return -errno;
158  }
159  snprintf(request, URL_BUF_SZ,
160  "GET %s HTTP/1.1\r\n"
161  "Accept: */*\r\n"
162  "Host: %s\r\n"
163  "Connection: close\r\n"
164  "\r\n",
165  path,
166  host);
167  x = write(s, request, strlen(request));
168  if (x < 0) {
169  perror("write");
170  return -errno;
171  }
172  do {
173  x = read(s, reply, READ_BUF_SZ);
174  if (x > 0)
175  nr += x;
176  } while (x > 0);
177  close(s);
178  return nr;
179 }
180 
181 static void
183 {
184  char buf[URL_BUF_SZ];
185  char *t;
186  int n;
187  struct timeval t1;
188  struct timeval t2;
189  if (debug)
190  fprintf(stderr, "Child PID %d entering child_main_loop\n", (int) getpid());
191  setbuf(stdin, NULL);
192  setbuf(stdout, NULL);
193  setbuf(stderr, NULL);
194  while (fgets(buf, URL_BUF_SZ, stdin)) {
195  t = strchr(buf, '\n');
196  if (t == NULL)
197  continue;
198  *t = '\0';
199  if (strncmp(buf, "http://", 7))
200  continue;
201  gettimeofday(&t1, NULL);
202  n = get_url(buf);
203  gettimeofday(&t2, NULL);
204  printf("%d %d\n", n, tvSubMsec(t1, t2));
205  }
206 }
207 
208 static thing *
209 create_a_thing(char *argv[])
210 {
211  int p2c[2];
212  int c2p[2];
213  int prfd, pwfd, crfd, cwfd;
214  pid_t pid;
215  thing *t;
216  if (pipe(p2c) < 0)
217  abort();
218  if (pipe(c2p) < 0)
219  abort();
220  prfd = p2c[0];
221  cwfd = p2c[1];
222  crfd = c2p[0];
223  pwfd = c2p[1];
224  if ((pid = fork()) < 0)
225  abort();
226  if (pid > 0) { /* parent */
227  /* close shared socket with child */
228  close(crfd);
229  close(cwfd);
230  t = calloc(1, sizeof(*t));
231  t->wfd = pwfd;
232  t->rfd = prfd;
233  if (pwfd > maxfd)
234  maxfd = pwfd;
235  if (prfd > maxfd)
236  maxfd = prfd;
237  t->pid = pid;
238  return t;
239  }
240  /* child */
241  close(prfd);
242  close(pwfd);
243  dup2(crfd, 0);
244  dup2(cwfd, 1);
245  close(crfd);
246  close(cwfd);
247  child_main_loop();
248  exit(0);
249 }
250 
251 static void
252 create_children(char *argv[])
253 {
254  thing *t;
255  thing **T = &things;
256  int i;
257  for (i = 0; i < 20; i++) {
258  t = create_a_thing(argv);
259  assert(t);
260  if (debug)
261  fprintf(stderr, "Thing #%d on FD %d/%d\n",
262  i, t->rfd, t->wfd);
263  *T = t;
264  T = &t->next;
265  }
266 }
267 
268 char *
270 {
271  static char buf[URL_BUF_SZ];
272  while (fgets(buf, URL_BUF_SZ, stdin)) {
273  if (strncmp(buf, "http://", 7))
274  continue;
275  return buf;
276  }
277  return NULL;
278 }
279 
280 static thing *
282 {
283  thing *t;
284  thing *n = things;
285  while ((t = n)) {
286  n = t->next;
287  if (t->state == 0)
288  break;
289  }
290  return t;
291 }
292 
293 static void
294 dispatch(thing * t, char *url)
295 {
296  int x;
297  char *s;
298  assert(t->state == 0);
299  x = write(t->wfd, url, strlen(url));
300  if (x < 0)
301  perror("write");
302  if (debug)
303  fprintf(stderr, "dispatched URL to thing PID %d, %d bytes\n", (int) t->pid, x);
304  strncpy(t->url, url, URL_BUF_SZ);
305  if ((s = strchr(t->url, '\n')))
306  *s = '\0';
307  t->state = 1;
308  FD_SET(t->rfd, &R1);
309 }
310 
311 static void
313 {
314  char buf[128];
315  int i;
316  int x;
317  int j;
318  x = read(t->rfd, buf, 128);
319  if (x < 0) {
320  perror("read");
321  } else if (2 == sscanf(buf, "%d %d", &i, &j)) {
322  gettimeofday(&now, NULL);
323  printf("%d.%06d %9d %9d %s\n", (int) now.tv_sec, (int) now.tv_usec, i, j, t->url);
324  }
325  t->state = 0;
326  FD_CLR(t->rfd, &R1);
327 }
328 
329 static void
331 {
332  thing *t;
333  char *url;
334  fd_set R2;
335  int x;
336  struct timeval to;
337  FD_ZERO(&R1);
338  for (;;) {
339  while ((t = get_idle_thing()) && (url = parent_read_url()))
340  dispatch(t, url);
341  R2 = R1;
342  to.tv_sec = 60;
343  to.tv_usec = 0;
344  x = select(maxfd + 1, &R2, NULL, NULL, &to);
345  if (x < 0) {
346  perror("select");
347  continue;
348  } else if (x == 0) {
349  return;
350  }
351  for (t = things; t; t = t->next) {
352  if (t->state != 1)
353  continue;
354  if (!FD_ISSET(t->rfd, &R2))
355  continue;
356  read_reply(t);
357  }
358  }
359 }
360 
361 static void
362 sig_child(int sig)
363 {
364  int status;
365  pid_t pid;
366  do {
367  pid = waitpid(-1, &status, WNOHANG);
368  } while (pid > 0 || (pid < 0 && errno == EINTR));
369  signal(sig, sig_child);
370 }
371 
372 int
373 main(int argc, char *argv[])
374 {
375  int i;
376  signal(SIGCHLD, sig_child);
377  create_children(argv);
379  for (i = 3; i <= maxfd; i++)
380  close(i);
381  sleep(1);
382 }
383 
int rfd
Definition: tcp-banger3.c:89
static thing * get_idle_thing(void)
Definition: tcp-banger3.c:281
#define URL_BUF_SZ
Definition: tcp-banger3.c:86
static void child_main_loop(void)
Definition: tcp-banger3.c:182
static int maxfd
Definition: tcp-banger3.c:100
static void dispatch(thing *t, char *url)
Definition: tcp-banger3.c:294
pid_t pid
Definition: tcp-banger3.c:92
struct hostent * gethostbyname()
int state
Definition: tcp-banger3.c:91
static int port
Definition: ldap_backend.cc:69
static void parent_main_loop(void)
Definition: tcp-banger3.c:330
static pid_t pid
Definition: IcmpSquid.cc:35
static int debug
Definition: tcp-banger3.c:105
struct _thing * next
Definition: tcp-banger3.c:94
#define NULL
Definition: types.h:166
char url[URL_BUF_SZ]
Definition: tcp-banger3.c:93
int wfd
Definition: tcp-banger3.c:90
static int get_url(const char *url)
Definition: tcp-banger3.c:115
static thing * things
Definition: tcp-banger3.c:98
#define READ_BUF_SZ
Definition: tcp-banger3.c:85
#define assert(EX)
Definition: assert.h:19
static void read_reply(thing *t)
Definition: tcp-banger3.c:312
int main(int argc, char *argv[])
Definition: tcp-banger3.c:373
static thing * create_a_thing(char *argv[])
Definition: tcp-banger3.c:209
static fd_set R1
Definition: tcp-banger3.c:99
static void create_children(char *argv[])
Definition: tcp-banger3.c:252
#define inet_ntop
Definition: inet_ntop.h:25
int tvSubMsec(struct timeval t1, struct timeval t2)
Definition: tcp-banger3.c:109
static void sig_child(int sig)
Definition: tcp-banger3.c:362
static StatHist s
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
static struct timeval now
Definition: tcp-banger3.c:101
char * parent_read_url(void)
Definition: tcp-banger3.c:269
char ** h_addr_list

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors