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