]> git.ipfire.org Git - thirdparty/squid.git/blame - test-suite/tcp-banger3.c
Docs: Copyright updates for 2018 (#114)
[thirdparty/squid.git] / test-suite / tcp-banger3.c
CommitLineData
4e0938ef 1/*
5b74111a 2 * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
4e0938ef
AJ
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
f7f3304a 9#include "squid.h"
2742510a 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 */
8a09e810 20#if _SQUID_LINUX_
2742510a 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> */
8a09e810 29#if _SQUID_FREEBSD_
2742510a 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
2742510a 45#if HAVE_FCNTL_H
46#include <fcntl.h>
47#endif
32d002cb 48#if HAVE_STRING_H
2742510a 49#include <string.h>
50#endif
32d002cb 51#if HAVE_STRINGS_H
2742510a 52#include <strings.h>
53#endif
2742510a 54#if HAVE_SIGNAL_H
55#include <signal.h>
56#endif
57#if HAVE_TIME_H
58#include <time.h>
59#endif
2742510a 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
ef364f64 78#if HAVE_NETDB_H
2742510a 79#include <netdb.h>
ef364f64
AJ
80#endif
81#if HAVE_SYS_WAIT_H
2742510a 82#include <sys/wait.h>
ef364f64 83#endif
2742510a 84
85#define READ_BUF_SZ 4096
86#define URL_BUF_SZ 4096
87
88struct _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};
96typedef struct _thing thing;
97
98static thing *things = NULL;
99static fd_set R1;
100static int maxfd = 0;
101static struct timeval now;
102#if DEBUG
103static int debug = 1;
104#else
105static int debug = 0;
106#endif
107
2327c45c 108int
109tvSubMsec(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
2742510a 114static int
115get_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, '/')))
26ac0430 131 *t = '\0';
2742510a 132 if ((t = strchr(host, ':'))) {
26ac0430
AJ
133 *t = '\0';
134 port = (unsigned short) atoi(t + 1);
2742510a 135 }
b6a2f15e 136#if 0
2742510a 137 if ((int) port != 80)
26ac0430 138 return 0;
b6a2f15e 139#endif
2742510a 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)
26ac0430 145 return 0;
2742510a 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;
2f0b84f7
AJ
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 }
2742510a 153 s = socket(PF_INET, SOCK_STREAM, 0);
2327c45c 154 if (s < 0) {
26ac0430
AJ
155 perror("socket");
156 return -errno;
2327c45c 157 }
2742510a 158 x = connect(s, (struct sockaddr *) &S, sizeof(S));
159 if (x < 0) {
26ac0430
AJ
160 perror(host);
161 return -errno;
2742510a 162 }
163 snprintf(request, URL_BUF_SZ,
26ac0430
AJ
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);
2742510a 171 x = write(s, request, strlen(request));
172 if (x < 0) {
26ac0430
AJ
173 perror("write");
174 return -errno;
2742510a 175 }
176 do {
26ac0430
AJ
177 x = read(s, reply, READ_BUF_SZ);
178 if (x > 0)
179 nr += x;
2742510a 180 } while (x > 0);
181 close(s);
182 return nr;
183}
184
185static void
186child_main_loop(void)
187{
188 char buf[URL_BUF_SZ];
189 char *t;
190 int n;
2327c45c 191 struct timeval t1;
192 struct timeval t2;
2742510a 193 if (debug)
26ac0430 194 fprintf(stderr, "Child PID %d entering child_main_loop\n", (int) getpid());
2742510a 195 setbuf(stdin, NULL);
196 setbuf(stdout, NULL);
197 setbuf(stderr, NULL);
198 while (fgets(buf, URL_BUF_SZ, stdin)) {
26ac0430
AJ
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));
2742510a 209 }
210}
211
212static thing *
213create_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)
26ac0430 221 abort();
2742510a 222 if (pipe(c2p) < 0)
26ac0430 223 abort();
2742510a 224 prfd = p2c[0];
225 cwfd = p2c[1];
226 crfd = c2p[0];
227 pwfd = c2p[1];
228 if ((pid = fork()) < 0)
26ac0430 229 abort();
f53969cc 230 if (pid > 0) { /* parent */
26ac0430
AJ
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;
2742510a 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
255static void
256create_children(char *argv[])
257{
258 thing *t;
259 thing **T = &things;
260 int i;
261 for (i = 0; i < 20; i++) {
26ac0430
AJ
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;
2742510a 269 }
270}
271
272char *
273parent_read_url(void)
274{
275 static char buf[URL_BUF_SZ];
276 while (fgets(buf, URL_BUF_SZ, stdin)) {
26ac0430
AJ
277 if (strncmp(buf, "http://", 7))
278 continue;
279 return buf;
2742510a 280 }
281 return NULL;
282}
283
284static thing *
285get_idle_thing(void)
286{
287 thing *t;
288 thing *n = things;
289 while ((t = n)) {
26ac0430
AJ
290 n = t->next;
291 if (t->state == 0)
292 break;
2742510a 293 }
294 return t;
295}
296
297static void
298dispatch(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)
26ac0430 305 perror("write");
2742510a 306 if (debug)
26ac0430 307 fprintf(stderr, "dispatched URL to thing PID %d, %d bytes\n", (int) t->pid, x);
2742510a 308 strncpy(t->url, url, URL_BUF_SZ);
309 if ((s = strchr(t->url, '\n')))
26ac0430 310 *s = '\0';
2742510a 311 t->state = 1;
312 FD_SET(t->rfd, &R1);
313}
314
315static void
316read_reply(thing * t)
317{
318 char buf[128];
319 int i;
320 int x;
2327c45c 321 int j;
2742510a 322 x = read(t->rfd, buf, 128);
323 if (x < 0) {
26ac0430 324 perror("read");
2327c45c 325 } else if (2 == sscanf(buf, "%d %d", &i, &j)) {
26ac0430
AJ
326 gettimeofday(&now, NULL);
327 printf("%d.%06d %9d %9d %s\n", (int) now.tv_sec, (int) now.tv_usec, i, j, t->url);
2742510a 328 }
329 t->state = 0;
330 FD_CLR(t->rfd, &R1);
331}
332
333static void
334parent_main_loop(void)
335{
336 thing *t;
337 char *url;
338 fd_set R2;
339 int x;
cae16863 340 struct timeval to;
2742510a 341 FD_ZERO(&R1);
342 for (;;) {
26ac0430
AJ
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 }
2742510a 362 }
363}
364
365static void
366sig_child(int sig)
367{
368 int status;
369 pid_t pid;
370 do {
26ac0430 371 pid = waitpid(-1, &status, WNOHANG);
2742510a 372 } while (pid > 0 || (pid < 0 && errno == EINTR));
373 signal(sig, sig_child);
374}
375
2742510a 376int
377main(int argc, char *argv[])
378{
8d1ef8ff 379 int i;
2742510a 380 signal(SIGCHLD, sig_child);
381 create_children(argv);
382 parent_main_loop();
468ae12b 383 for (i = 3; i <= maxfd; i++)
26ac0430 384 close(i);
8d1ef8ff 385 sleep(1);
2742510a 386}
f53969cc 387