]> git.ipfire.org Git - thirdparty/squid.git/blob - test-suite/tcp-banger3.c
SourceFormat Enforcement
[thirdparty/squid.git] / test-suite / tcp-banger3.c
1 /*
2 * Copyright (C) 1996-2017 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 #if 0
137 if ((int) port != 80)
138 return 0;
139 #endif
140 t = strchr(url + 7, '/');
141 strncpy(path, (t ? t : "/"), URL_BUF_SZ);
142 memset(&S, '\0', sizeof(S));
143 h = gethostbyname(host);
144 if (!h)
145 return 0;
146 memcpy(&S.sin_addr.s_addr, h->h_addr_list[0], sizeof(S.sin_addr.s_addr));
147 S.sin_port = htons(port);
148 S.sin_family = AF_INET;
149 if (debug) {
150 char tmp[16];
151 fprintf(stderr, "%s (%s) %d %s\n", host, inet_ntop(AF_INET, &S.sin_addr,tmp,sizeof(tmp)), (int) port, path);
152 }
153 s = socket(PF_INET, SOCK_STREAM, 0);
154 if (s < 0) {
155 perror("socket");
156 return -errno;
157 }
158 x = connect(s, (struct sockaddr *) &S, sizeof(S));
159 if (x < 0) {
160 perror(host);
161 return -errno;
162 }
163 snprintf(request, URL_BUF_SZ,
164 "GET %s HTTP/1.1\r\n"
165 "Accept: */*\r\n"
166 "Host: %s\r\n"
167 "Connection: close\r\n"
168 "\r\n",
169 path,
170 host);
171 x = write(s, request, strlen(request));
172 if (x < 0) {
173 perror("write");
174 return -errno;
175 }
176 do {
177 x = read(s, reply, READ_BUF_SZ);
178 if (x > 0)
179 nr += x;
180 } while (x > 0);
181 close(s);
182 return nr;
183 }
184
185 static void
186 child_main_loop(void)
187 {
188 char buf[URL_BUF_SZ];
189 char *t;
190 int n;
191 struct timeval t1;
192 struct timeval t2;
193 if (debug)
194 fprintf(stderr, "Child PID %d entering child_main_loop\n", (int) getpid());
195 setbuf(stdin, NULL);
196 setbuf(stdout, NULL);
197 setbuf(stderr, NULL);
198 while (fgets(buf, URL_BUF_SZ, stdin)) {
199 t = strchr(buf, '\n');
200 if (t == NULL)
201 continue;
202 *t = '\0';
203 if (strncmp(buf, "http://", 7))
204 continue;
205 gettimeofday(&t1, NULL);
206 n = get_url(buf);
207 gettimeofday(&t2, NULL);
208 printf("%d %d\n", n, tvSubMsec(t1, t2));
209 }
210 }
211
212 static thing *
213 create_a_thing(char *argv[])
214 {
215 int p2c[2];
216 int c2p[2];
217 int prfd, pwfd, crfd, cwfd;
218 pid_t pid;
219 thing *t;
220 if (pipe(p2c) < 0)
221 abort();
222 if (pipe(c2p) < 0)
223 abort();
224 prfd = p2c[0];
225 cwfd = p2c[1];
226 crfd = c2p[0];
227 pwfd = c2p[1];
228 if ((pid = fork()) < 0)
229 abort();
230 if (pid > 0) { /* parent */
231 /* close shared socket with child */
232 close(crfd);
233 close(cwfd);
234 t = calloc(1, sizeof(*t));
235 t->wfd = pwfd;
236 t->rfd = prfd;
237 if (pwfd > maxfd)
238 maxfd = pwfd;
239 if (prfd > maxfd)
240 maxfd = prfd;
241 t->pid = pid;
242 return t;
243 }
244 /* child */
245 close(prfd);
246 close(pwfd);
247 dup2(crfd, 0);
248 dup2(cwfd, 1);
249 close(crfd);
250 close(cwfd);
251 child_main_loop();
252 exit(0);
253 }
254
255 static void
256 create_children(char *argv[])
257 {
258 thing *t;
259 thing **T = &things;
260 int i;
261 for (i = 0; i < 20; i++) {
262 t = create_a_thing(argv);
263 assert(t);
264 if (debug)
265 fprintf(stderr, "Thing #%d on FD %d/%d\n",
266 i, t->rfd, t->wfd);
267 *T = t;
268 T = &t->next;
269 }
270 }
271
272 char *
273 parent_read_url(void)
274 {
275 static char buf[URL_BUF_SZ];
276 while (fgets(buf, URL_BUF_SZ, stdin)) {
277 if (strncmp(buf, "http://", 7))
278 continue;
279 return buf;
280 }
281 return NULL;
282 }
283
284 static thing *
285 get_idle_thing(void)
286 {
287 thing *t;
288 thing *n = things;
289 while ((t = n)) {
290 n = t->next;
291 if (t->state == 0)
292 break;
293 }
294 return t;
295 }
296
297 static void
298 dispatch(thing * t, char *url)
299 {
300 int x;
301 char *s;
302 assert(t->state == 0);
303 x = write(t->wfd, url, strlen(url));
304 if (x < 0)
305 perror("write");
306 if (debug)
307 fprintf(stderr, "dispatched URL to thing PID %d, %d bytes\n", (int) t->pid, x);
308 strncpy(t->url, url, URL_BUF_SZ);
309 if ((s = strchr(t->url, '\n')))
310 *s = '\0';
311 t->state = 1;
312 FD_SET(t->rfd, &R1);
313 }
314
315 static void
316 read_reply(thing * t)
317 {
318 char buf[128];
319 int i;
320 int x;
321 int j;
322 x = read(t->rfd, buf, 128);
323 if (x < 0) {
324 perror("read");
325 } else if (2 == sscanf(buf, "%d %d", &i, &j)) {
326 gettimeofday(&now, NULL);
327 printf("%d.%06d %9d %9d %s\n", (int) now.tv_sec, (int) now.tv_usec, i, j, t->url);
328 }
329 t->state = 0;
330 FD_CLR(t->rfd, &R1);
331 }
332
333 static void
334 parent_main_loop(void)
335 {
336 thing *t;
337 char *url;
338 fd_set R2;
339 int x;
340 struct timeval to;
341 FD_ZERO(&R1);
342 for (;;) {
343 while ((t = get_idle_thing()) && (url = parent_read_url()))
344 dispatch(t, url);
345 R2 = R1;
346 to.tv_sec = 60;
347 to.tv_usec = 0;
348 x = select(maxfd + 1, &R2, NULL, NULL, &to);
349 if (x < 0) {
350 perror("select");
351 continue;
352 } else if (x == 0) {
353 return;
354 }
355 for (t = things; t; t = t->next) {
356 if (t->state != 1)
357 continue;
358 if (!FD_ISSET(t->rfd, &R2))
359 continue;
360 read_reply(t);
361 }
362 }
363 }
364
365 static void
366 sig_child(int sig)
367 {
368 int status;
369 pid_t pid;
370 do {
371 pid = waitpid(-1, &status, WNOHANG);
372 } while (pid > 0 || (pid < 0 && errno == EINTR));
373 signal(sig, sig_child);
374 }
375
376 int
377 main(int argc, char *argv[])
378 {
379 int i;
380 signal(SIGCHLD, sig_child);
381 create_children(argv);
382 parent_main_loop();
383 for (i = 3; i <= maxfd; i++)
384 close(i);
385 sleep(1);
386 }
387