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