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