]>
Commit | Line | Data |
---|---|---|
47130615 | 1 | |
eb5f55b3 | 2 | #include "config.h" |
3 | ||
4 | /* | |
5 | * On some systems, FD_SETSIZE is set to something lower than the | |
6 | * actual number of files which can be opened. IRIX is one case, | |
7 | * NetBSD is another. So here we increase FD_SETSIZE to our | |
8 | * configure-discovered maximum *before* any system includes. | |
9 | */ | |
10 | #define CHANGE_FD_SETSIZE 1 | |
11 | ||
12 | /* Cannot increase FD_SETSIZE on Linux */ | |
13 | #if defined(_SQUID_LINUX_) | |
14 | #undef CHANGE_FD_SETSIZE | |
15 | #define CHANGE_FD_SETSIZE 0 | |
16 | #endif | |
17 | ||
18 | /* Cannot increase FD_SETSIZE on FreeBSD before 2.2.0, causes select(2) | |
19 | * to return EINVAL. */ | |
20 | /* Marian Durkovic <marian@svf.stuba.sk> */ | |
21 | /* Peter Wemm <peter@spinner.DIALix.COM> */ | |
22 | #if defined(_SQUID_FREEBSD_) | |
23 | #include <osreldate.h> | |
24 | #if __FreeBSD_version < 220000 | |
25 | #undef CHANGE_FD_SETSIZE | |
26 | #define CHANGE_FD_SETSIZE 0 | |
27 | #endif | |
28 | #endif | |
29 | ||
30 | /* Increase FD_SETSIZE if SQUID_MAXFD is bigger */ | |
31 | #if CHANGE_FD_SETSIZE && SQUID_MAXFD > DEFAULT_FD_SETSIZE | |
32 | #define FD_SETSIZE SQUID_MAXFD | |
33 | #endif | |
34 | ||
35 | #if HAVE_UNISTD_H | |
36 | #include <unistd.h> | |
37 | #endif | |
38 | #if HAVE_STDLIB_H | |
39 | #include <stdlib.h> | |
40 | #endif | |
41 | #if HAVE_STDIO_H | |
42 | #include <stdio.h> | |
43 | #endif | |
44 | #if HAVE_FCNTL_H | |
45 | #include <fcntl.h> | |
46 | #endif | |
47 | #ifdef HAVE_STRING_H | |
48 | #include <string.h> | |
49 | #endif | |
50 | #ifdef HAVE_STRINGS_H | |
51 | #include <strings.h> | |
52 | #endif | |
53 | #ifdef HAVE_BSTRING_H | |
54 | #include <bstring.h> | |
55 | #endif | |
56 | #if HAVE_SYS_TYPES_H | |
57 | #include <sys/types.h> | |
58 | #endif | |
59 | #if HAVE_SYS_SELECT_H | |
60 | #include <sys/select.h> | |
61 | #endif | |
62 | #if HAVE_SIGNAL_H | |
63 | #include <signal.h> | |
64 | #endif | |
65 | #if HAVE_TIME_H | |
66 | #include <time.h> | |
67 | #endif | |
68 | #if HAVE_SYS_TIME_H | |
69 | #include <sys/time.h> | |
70 | #endif | |
71 | #if HAVE_SYS_SOCKET_H | |
72 | #include <sys/socket.h> | |
73 | #endif | |
74 | #if HAVE_NETINET_IN_H | |
75 | #include <netinet/in.h> | |
76 | #endif | |
77 | #if HAVE_ARPA_INET_H | |
78 | #include <arpa/inet.h> | |
79 | #endif | |
80 | #if HAVE_ERRNO_H | |
81 | #include <errno.h> | |
82 | #endif | |
83 | #if HAVE_CTYPE_H | |
84 | #include <ctype.h> | |
85 | #endif | |
86 | #if HAVE_ASSERT_H | |
87 | #include <assert.h> | |
88 | #endif | |
14ff08f1 | 89 | #if HAVE_SYS_STAT_H |
90 | #include <sys/stat.h> | |
91 | #endif | |
eb5f55b3 | 92 | |
cc192b50 | 93 | #include "getaddrinfo.h" |
94 | ||
95 | #define PROXY_PORT "3128" | |
eb5f55b3 | 96 | #define PROXY_ADDR "127.0.0.1" |
97 | #define MAX_FDS 1024 | |
98 | #define READ_BUF_SZ 4096 | |
99 | #define min(x,y) ((x)<(y)? (x) : (y)) | |
100 | ||
101 | static int proxy_port = PROXY_PORT; | |
102 | static char *proxy_addr = PROXY_ADDR; | |
103 | static char *progname; | |
104 | static int noutstanding = 0; | |
105 | static int done_reading_urls = 0; | |
106 | static int opt_ims = 0; | |
14ff08f1 | 107 | static int opt_checksum = 0; |
108 | static int opt_reopen = 1; | |
109 | static int max_outstanding = 10; | |
eb5f55b3 | 110 | static time_t lifetime = 60; |
111 | static const char *const crlf = "\r\n"; | |
14ff08f1 | 112 | static int trace_fd = -1; |
113 | static int total_bytes_read = 0; | |
eb5f55b3 | 114 | |
115 | #define REPLY_HDR_SZ 8192 | |
116 | ||
117 | struct _r { | |
14ff08f1 | 118 | char url[1024]; |
eb5f55b3 | 119 | int content_length; |
120 | int hdr_length; | |
121 | int hdr_offset; | |
122 | int bytes_read; | |
123 | char reply_hdrs[REPLY_HDR_SZ]; | |
124 | struct _r *next; | |
14ff08f1 | 125 | long sum; |
126 | long validsize; | |
127 | long validsum; | |
eb5f55b3 | 128 | }; |
129 | ||
130 | static struct _r *Requests; | |
131 | ||
132 | char * | |
133 | mkrfc850(t) | |
134 | time_t *t; | |
135 | { | |
136 | static char buf[128]; | |
137 | struct tm *gmt = gmtime(t); | |
138 | buf[0] = '\0'; | |
139 | (void) strftime(buf, 127, "%A, %d-%b-%y %H:%M:%S GMT", gmt); | |
140 | return buf; | |
141 | } | |
142 | ||
143 | ||
144 | char * | |
145 | mime_headers_end(const char *mime) | |
146 | { | |
147 | const char *p1, *p2; | |
148 | const char *end = NULL; | |
149 | ||
150 | p1 = strstr(mime, "\n\r\n"); | |
151 | p2 = strstr(mime, "\n\n"); | |
152 | ||
153 | if (p1 && p2) | |
154 | end = p1 < p2 ? p1 : p2; | |
155 | else | |
156 | end = p1 ? p1 : p2; | |
157 | if (end) | |
158 | end += (end == p1 ? 3 : 2); | |
159 | ||
160 | return (char *) end; | |
161 | } | |
162 | ||
163 | void | |
164 | sig_intr(int sig) | |
165 | { | |
14ff08f1 | 166 | fprintf(stderr, "\rWaiting for open connections to finish...\n"); |
eb5f55b3 | 167 | signal(sig, SIG_DFL); |
14ff08f1 | 168 | done_reading_urls = 1; |
eb5f55b3 | 169 | } |
170 | ||
171 | int | |
172 | open_http_socket(void) | |
173 | { | |
174 | int s; | |
cc192b50 | 175 | struct addrinfo *AI = NULL; |
176 | struct addrinfo hints; | |
177 | ||
178 | memset(&hints, '\0', sizeof(struct addrinfo)); | |
179 | hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV; | |
180 | hints.ai_family = AF_UNSPEC; | |
181 | hints.ai_socktype = SOCK_STREAM; | |
182 | ||
183 | xgetaddrinfo(proxy_addr, proxy_port, &hints, AI); | |
184 | ||
185 | if ((s = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) { | |
eb5f55b3 | 186 | perror("socket"); |
cc192b50 | 187 | xfreeaddrinfo(AI); |
eb5f55b3 | 188 | return -1; |
189 | } | |
cc192b50 | 190 | |
191 | if (connect(s, AI->ai_addr, AI->ai_addrlen) < 0) { | |
eb5f55b3 | 192 | close(s); |
193 | perror("connect"); | |
cc192b50 | 194 | xfreeaddrinfo(AI); |
eb5f55b3 | 195 | return -1; |
196 | } | |
cc192b50 | 197 | |
198 | xfreeaddrinfo(AI); | |
eb5f55b3 | 199 | return s; |
200 | } | |
201 | ||
202 | int | |
14ff08f1 | 203 | send_request(int fd, const char *data) |
eb5f55b3 | 204 | { |
468ae12b | 205 | char msg[4096], buf[4096]; |
eb5f55b3 | 206 | int len; |
207 | time_t w; | |
208 | struct _r *r; | |
209 | struct _r **R; | |
14ff08f1 | 210 | char *method, *url, *file, *size, *checksum; |
211 | char *tmp = strdup(data); | |
212 | struct stat st; | |
213 | int file_fd = -1; | |
468ae12b | 214 | method = strtok(tmp, " "); |
215 | url = strtok(NULL, " "); | |
216 | file = strtok(NULL, " "); | |
217 | size = strtok(NULL, " "); | |
218 | checksum = strtok(NULL, " "); | |
14ff08f1 | 219 | if (!url) { |
468ae12b | 220 | url = method; |
221 | method = "GET"; | |
14ff08f1 | 222 | } |
468ae12b | 223 | if (file && strcmp(file, "-") == 0) |
224 | file = NULL; | |
225 | if (size && strcmp(size, "-") == 0) | |
226 | size = NULL; | |
227 | if (checksum && strcmp(checksum, "-") == 0) | |
228 | checksum = NULL; | |
14ff08f1 | 229 | msg[0] = '\0'; |
230 | sprintf(buf, "%s %s HTTP/1.0\r\n", method, url); | |
468ae12b | 231 | strcat(msg, buf); |
14ff08f1 | 232 | strcat(msg, "Accept: */*\r\n"); |
233 | strcat(msg, "Proxy-Connection: Keep-Alive\r\n"); | |
eb5f55b3 | 234 | if (opt_ims && (lrand48() & 0x03) == 0) { |
235 | w = time(NULL) - (lrand48() & 0x3FFFF); | |
14ff08f1 | 236 | sprintf(buf, "If-Modified-Since: %s\r\n", mkrfc850(&w)); |
237 | strcat(msg, buf); | |
eb5f55b3 | 238 | } |
14ff08f1 | 239 | if (file) { |
468ae12b | 240 | if ((file_fd = open(file, O_RDONLY)) < 0) { |
14ff08f1 | 241 | perror("open"); |
242 | return -1; | |
243 | } | |
468ae12b | 244 | if (fstat(file_fd, &st)) { |
14ff08f1 | 245 | perror("fstat"); |
246 | close(file_fd); | |
247 | return -1; | |
248 | } | |
249 | sprintf(buf, "Content-length: %d\r\n", st.st_size); | |
250 | strcat(msg, buf); | |
251 | } | |
252 | strcat(msg, "\r\n"); | |
253 | len = strlen(msg); | |
254 | if (write(fd, msg, len) < 0) { | |
eb5f55b3 | 255 | close(fd); |
14ff08f1 | 256 | perror("request write"); |
257 | close(file_fd); | |
eb5f55b3 | 258 | return -1; |
259 | } | |
14ff08f1 | 260 | if (file) { |
468ae12b | 261 | while ((len = read(file_fd, buf, sizeof buf)) > 0) { |
14ff08f1 | 262 | if (write(fd, buf, len) < 0) { |
263 | close(fd); | |
264 | perror("body write"); | |
265 | close(file_fd); | |
266 | return -1; | |
267 | } | |
268 | } | |
269 | if (len < 0) { | |
270 | perror("file read"); | |
271 | close(file_fd); | |
272 | return -1; | |
273 | } | |
274 | close(file_fd); | |
275 | } | |
eb5f55b3 | 276 | r = calloc(1, sizeof(struct _r)); |
14ff08f1 | 277 | strcpy(r->url, url); |
278 | if (size) | |
279 | r->validsize = atoi(size); | |
280 | else | |
281 | r->validsize = -1; | |
282 | if (checksum) | |
283 | r->validsum = atoi(checksum); | |
eb5f55b3 | 284 | for (R = &Requests; *R; R = &(*R)->next); |
285 | *R = r; | |
14ff08f1 | 286 | /* fprintf(stderr, "REQUESTED %s\n", url); */ |
eb5f55b3 | 287 | noutstanding++; |
288 | return 0; | |
289 | } | |
290 | ||
291 | static int | |
292 | get_header_int_value(const char *hdr, const char *buf, const char *end) | |
293 | { | |
294 | const char *t; | |
295 | for (t = buf; t < end; t += strcspn(t, crlf), t += strspn(t, crlf)) { | |
296 | if (strncasecmp(t, hdr, strlen(hdr)) == 0) { | |
297 | t += strlen(hdr); | |
e4755e29 | 298 | while (xisspace(*t)) |
eb5f55b3 | 299 | t++; |
300 | return atoi(t); | |
301 | } | |
302 | } | |
14ff08f1 | 303 | return -1; |
eb5f55b3 | 304 | } |
305 | ||
14ff08f1 | 306 | static const char * |
307 | get_header_string_value(const char *hdr, const char *buf, const char *end) | |
308 | { | |
309 | const char *t; | |
310 | static char result[8192]; | |
311 | for (t = buf; t < end; t += strcspn(t, crlf), t += strspn(t, crlf)) { | |
312 | if (strncasecmp(t, hdr, strlen(hdr)) == 0) { | |
313 | t += strlen(hdr); | |
e4755e29 | 314 | while (xisspace(*t)) |
14ff08f1 | 315 | t++; |
468ae12b | 316 | strcpy(result, ""); |
317 | strncat(result, t, strcspn(t, crlf)); | |
14ff08f1 | 318 | return result; |
319 | } | |
320 | } | |
321 | return NULL; | |
322 | } | |
323 | ||
324 | void | |
325 | request_done(struct _r *r) | |
326 | { | |
327 | #if 0 | |
328 | fprintf(stderr, "DONE: %s, (%d+%d)\n", | |
468ae12b | 329 | r->url, |
330 | r->hdr_length, | |
331 | r->content_length); | |
14ff08f1 | 332 | #endif |
333 | if (r->content_length != r->bytes_read) | |
334 | fprintf(stderr, "ERROR! Short reply, expected %d bytes got %d\n", | |
335 | r->content_length, r->bytes_read); | |
336 | else if (r->validsize >= 0) { | |
337 | if (r->validsize != r->bytes_read) | |
338 | fprintf(stderr, "WARNING: %s Object size mismatch, expected %d got %d\n", | |
468ae12b | 339 | r->url, r->validsize, r->bytes_read); |
14ff08f1 | 340 | else if (opt_checksum && r->sum != r->validsum) |
341 | fprintf(stderr, "WARNING: %s Checksum error. Expected %d got %d\n", | |
468ae12b | 342 | r->url, r->validsum, r->sum); |
14ff08f1 | 343 | } |
344 | } | |
eb5f55b3 | 345 | int |
14ff08f1 | 346 | handle_read(char *inbuf, int len) |
eb5f55b3 | 347 | { |
348 | struct _r *r = Requests; | |
349 | const char *end; | |
14ff08f1 | 350 | const char *url; |
351 | static char buf[READ_BUF_SZ]; | |
468ae12b | 352 | int hlen, blen; |
353 | if (len < 0) { | |
eb5f55b3 | 354 | perror("read"); |
355 | Requests = r->next; | |
14ff08f1 | 356 | request_done(r); |
e3fc4f10 | 357 | free(r); |
358 | noutstanding--; | |
14ff08f1 | 359 | if (trace_fd >= 0) |
468ae12b | 360 | write(trace_fd, "\n[CLOSED]\n", 10); |
eb5f55b3 | 361 | return -1; |
362 | } | |
14ff08f1 | 363 | total_bytes_read += len; |
468ae12b | 364 | xmemcpy(buf, inbuf, len); |
eb5f55b3 | 365 | if (len == 0) { |
14ff08f1 | 366 | fprintf(stderr, "WARNING: %s, server closed socket after %d+%d bytes\n", r->url, r->hdr_offset, r->bytes_read); |
367 | /* XXX, If no data was received and it isn't the first request on this | |
368 | * connection then the request should be restarted rather than aborted | |
369 | * but this is a simple test program an not a full blown HTTP client. | |
370 | */ | |
371 | request_done(r); | |
eb5f55b3 | 372 | Requests = r->next; |
373 | free(r); | |
374 | noutstanding--; | |
375 | return -1; | |
376 | } | |
14ff08f1 | 377 | if (trace_fd > 0) |
378 | write(trace_fd, buf, len); | |
379 | while (len > 0) { | |
380 | /* Build headers */ | |
381 | if (r->hdr_length == 0) { | |
382 | hlen = min(len, REPLY_HDR_SZ - r->hdr_offset - 1); | |
383 | xmemcpy(r->reply_hdrs + r->hdr_offset, buf, hlen); | |
384 | r->hdr_offset += hlen; | |
385 | r->reply_hdrs[r->hdr_offset] = '\0'; | |
386 | len -= hlen; | |
387 | /* Save any remaining read data */ | |
388 | xmemmove(buf, buf + hlen, len); | |
389 | } | |
390 | /* Process headers */ | |
391 | if (r->hdr_length == 0 && (end = mime_headers_end(r->reply_hdrs)) != NULL) { | |
392 | #if 0 | |
468ae12b | 393 | fprintf(stderr, "FOUND EOH FOR %s\n", r->url); |
394 | */ | |
14ff08f1 | 395 | #endif |
468ae12b | 396 | r->hdr_length = end - r->reply_hdrs; |
14ff08f1 | 397 | #if 0 |
468ae12b | 398 | fprintf(stderr, "HDR_LENGTH = %d\n", r->hdr_length); |
14ff08f1 | 399 | #endif |
400 | /* "unread" any body contents received */ | |
401 | blen = r->hdr_offset - r->hdr_length; | |
402 | assert(blen >= 0); | |
403 | if (blen > 0) { | |
404 | xmemmove(buf + blen, buf, len); | |
405 | xmemcpy(buf, r->reply_hdrs + r->hdr_length, blen); | |
406 | len += blen; | |
407 | } | |
468ae12b | 408 | r->reply_hdrs[r->hdr_length] = '\0'; /* Null terminate headers */ |
14ff08f1 | 409 | /* Parse headers */ |
410 | r->content_length = get_header_int_value("content-length:", r->reply_hdrs, end); | |
468ae12b | 411 | /* fprintf(stderr, "CONTENT_LENGTH = %d\n", r->content_length); */ |
14ff08f1 | 412 | url = get_header_string_value("X-Request-URI:", r->reply_hdrs, end); |
413 | if (url != NULL && strcmp(r->url, url) != 0) | |
414 | fprintf(stderr, "WARNING: %s got reply %s\n", r->url, url); | |
415 | #if XREQUESTURI || 0 | |
468ae12b | 416 | fprintf(stderr, "LOCATION = %s\n", get_header_string_value("X-Request-URI:", r->reply_hdrs, end)); |
14ff08f1 | 417 | #endif |
418 | } | |
468ae12b | 419 | if (!(len == 0 || r->hdr_length > 0)) { |
14ff08f1 | 420 | fprintf(stderr, "ERROR!!!\n"); |
468ae12b | 421 | assert((len == 0 || r->hdr_length > 0)); |
eb5f55b3 | 422 | } |
14ff08f1 | 423 | /* Process body */ |
424 | if (r->hdr_length != 0) { | |
425 | int i; | |
426 | int bytes_left, bytes_used; | |
427 | if (r->content_length >= 0) { | |
428 | bytes_left = r->content_length - r->bytes_read; | |
429 | assert(bytes_left >= 0); | |
468ae12b | 430 | bytes_used = len < bytes_left ? len : bytes_left; |
14ff08f1 | 431 | } else { |
468ae12b | 432 | bytes_left = len + 1; /* Unknown end... */ |
14ff08f1 | 433 | bytes_used = len; |
434 | } | |
435 | if (opt_checksum) { | |
468ae12b | 436 | for (i = 0; i < bytes_used; i++) |
437 | r->sum += (int) buf[i] & 0xFF; | |
14ff08f1 | 438 | } |
439 | r->bytes_read += bytes_used; | |
440 | len -= bytes_used; | |
441 | if (bytes_left == bytes_used) { | |
442 | request_done(r); | |
443 | Requests = r->next; | |
444 | free(r); | |
445 | noutstanding--; | |
446 | r = Requests; | |
5a91f458 | 447 | } else if (r->content_length > -1) { |
14ff08f1 | 448 | assert(r->bytes_read < r->content_length); |
449 | } | |
dbfed404 | 450 | xmemmove(buf, buf + bytes_used, len); |
eb5f55b3 | 451 | } |
452 | } | |
453 | return 0; | |
454 | } | |
455 | ||
456 | int | |
457 | read_reply(int fd) | |
458 | { | |
459 | static char buf[READ_BUF_SZ]; | |
460 | int len; | |
461 | int x; | |
462 | len = read(fd, buf, READ_BUF_SZ); | |
463 | x = handle_read(buf, len); | |
14ff08f1 | 464 | if (x < 0) { |
465 | perror("read reply"); | |
eb5f55b3 | 466 | close(fd); |
14ff08f1 | 467 | } |
eb5f55b3 | 468 | return x; |
469 | } | |
470 | ||
471 | void | |
472 | main_loop(void) | |
473 | { | |
474 | static int pconn_fd = -1; | |
475 | static char buf[8192]; | |
476 | struct timeval to; | |
468ae12b | 477 | struct timeval now, last, start; |
eb5f55b3 | 478 | fd_set R; |
479 | struct _r *r; | |
480 | struct _r *nextr; | |
481 | int x; | |
e3fc4f10 | 482 | int timeouts; |
14ff08f1 | 483 | int nrequests = 0, rrequests = 0, reqpersec = 0; |
484 | ||
485 | gettimeofday(&start, NULL); | |
486 | last = start; | |
487 | ||
488 | pconn_fd = open_http_socket(); | |
489 | if (pconn_fd < 0) { | |
490 | perror("socket"); | |
491 | exit(1); | |
492 | } | |
eb5f55b3 | 493 | while (!done_reading_urls || noutstanding) { |
14ff08f1 | 494 | if (!opt_reopen && pconn_fd < 0) { |
468ae12b | 495 | fprintf(stderr, "TERMINATED: Connection closed\n"); |
14ff08f1 | 496 | break; |
e3fc4f10 | 497 | } |
468ae12b | 498 | if (pconn_fd < 0) { |
eb5f55b3 | 499 | pconn_fd = open_http_socket(); |
500 | if (pconn_fd < 0) { | |
501 | perror("socket"); | |
502 | exit(1); | |
503 | } | |
504 | nextr = Requests; | |
505 | Requests = NULL; | |
468ae12b | 506 | noutstanding = 0; |
eb5f55b3 | 507 | while ((r = nextr) != NULL) { |
508 | nextr = r->next; | |
14ff08f1 | 509 | if (send_request(pconn_fd, r->url) != 0) { |
510 | close(pconn_fd); | |
468ae12b | 511 | pconn_fd = -1; |
14ff08f1 | 512 | nextr = r; |
468ae12b | 513 | for (r = Requests; r != NULL && r->next; r = r->next); |
14ff08f1 | 514 | if (r != NULL) |
515 | r->next = nextr; | |
516 | else | |
517 | Requests = nextr; | |
518 | break; | |
519 | } | |
eb5f55b3 | 520 | free(r); |
eb5f55b3 | 521 | } |
e3fc4f10 | 522 | timeouts = 0; |
468ae12b | 523 | if (pconn_fd < 0) |
14ff08f1 | 524 | continue; |
eb5f55b3 | 525 | } |
14ff08f1 | 526 | if (timeouts == 200) { |
527 | close(pconn_fd); | |
528 | pconn_fd = -1; | |
529 | r = Requests; | |
530 | Requests = Requests->next; | |
531 | fprintf(stderr, "ABORT %s\n", Requests->url); | |
532 | free(r); | |
533 | noutstanding--; | |
534 | } | |
468ae12b | 535 | if (pconn_fd >= 0 && noutstanding < max_outstanding && !done_reading_urls) { |
eb5f55b3 | 536 | char *t; |
537 | if (fgets(buf, 8191, stdin) == NULL) { | |
14ff08f1 | 538 | fprintf(stderr, "Done Reading URLS\n"); |
eb5f55b3 | 539 | done_reading_urls = 1; |
14ff08f1 | 540 | continue; |
eb5f55b3 | 541 | } |
14ff08f1 | 542 | rrequests++; |
eb5f55b3 | 543 | if ((t = strchr(buf, '\n'))) |
544 | *t = '\0'; | |
14ff08f1 | 545 | if (send_request(pconn_fd, buf) != 0) { |
546 | close(pconn_fd); | |
468ae12b | 547 | pconn_fd = -1; |
14ff08f1 | 548 | continue; |
549 | } | |
550 | nrequests++; | |
551 | reqpersec++; | |
e3fc4f10 | 552 | timeouts = 0; |
eb5f55b3 | 553 | } |
554 | FD_ZERO(&R); | |
555 | to.tv_sec = 1; | |
556 | to.tv_usec = 0; | |
557 | FD_SET(pconn_fd, &R); | |
558 | x = select(pconn_fd + 1, &R, NULL, NULL, &to); | |
559 | if (x < 0) { | |
560 | if (errno != EINTR) | |
561 | perror("select"); | |
562 | continue; | |
563 | } else if (x == 0) { | |
564 | assert(Requests != NULL); | |
e3fc4f10 | 565 | fprintf(stderr, "TIMEOUT %s; %d, %d\n", Requests->url, |
566 | ++timeouts, noutstanding); | |
eb5f55b3 | 567 | continue; |
568 | } | |
569 | if (FD_ISSET(pconn_fd, &R)) { | |
e3fc4f10 | 570 | timeouts = 0; |
eb5f55b3 | 571 | if (read_reply(pconn_fd) != 0) |
572 | pconn_fd = -1; | |
573 | } | |
14ff08f1 | 574 | gettimeofday(&now, NULL); |
468ae12b | 575 | if (now.tv_sec > last.tv_sec) { |
14ff08f1 | 576 | int dt; |
577 | int nreq; | |
578 | last = now; | |
579 | dt = (int) (now.tv_sec - start.tv_sec); | |
468ae12b | 580 | nreq = 0; |
581 | for (r = Requests; r; r = r->next) | |
582 | nreq++; | |
14ff08f1 | 583 | printf("T+ %6d: %9d req (%+4d), %4d pend, %3d/sec avg, %dmb, %dkb/sec avg\n", |
468ae12b | 584 | dt, |
585 | nrequests, | |
586 | reqpersec, | |
587 | nreq, | |
588 | (int) (nrequests / dt), | |
589 | (int) total_bytes_read / 1024 / 1024, | |
590 | (int) total_bytes_read / 1024 / dt); | |
14ff08f1 | 591 | reqpersec = 0; |
592 | } | |
eb5f55b3 | 593 | } |
594 | } | |
595 | ||
596 | void | |
597 | usage(void) | |
598 | { | |
14ff08f1 | 599 | fprintf(stderr, "usage: %s: -p port -h host -n max -t tracefile -i -c -l lifetime\n", progname); |
eb5f55b3 | 600 | } |
601 | ||
602 | int | |
603 | main(argc, argv) | |
604 | int argc; | |
605 | char *argv[]; | |
606 | { | |
607 | int c; | |
608 | setbuf(stdout, NULL); | |
609 | setbuf(stderr, NULL); | |
610 | progname = strdup(argv[0]); | |
14ff08f1 | 611 | while ((c = getopt(argc, argv, "p:h:n:t:icl:r")) != -1) { |
eb5f55b3 | 612 | switch (c) { |
613 | case 'p': | |
614 | proxy_port = atoi(optarg); | |
615 | break; | |
616 | case 'h': | |
617 | proxy_addr = strdup(optarg); | |
618 | break; | |
619 | case 'n': | |
14ff08f1 | 620 | max_outstanding = atoi(optarg); |
eb5f55b3 | 621 | break; |
622 | case 'i': | |
623 | opt_ims = 1; | |
624 | break; | |
14ff08f1 | 625 | case 'c': |
626 | opt_checksum = 1; | |
627 | break; | |
eb5f55b3 | 628 | case 'l': |
629 | lifetime = (time_t) atoi(optarg); | |
630 | break; | |
14ff08f1 | 631 | case 't': |
468ae12b | 632 | trace_fd = open(optarg, O_WRONLY | O_CREAT | O_TRUNC, 0666); |
14ff08f1 | 633 | break; |
634 | case 'r': | |
635 | opt_reopen = !opt_reopen; | |
636 | break; | |
eb5f55b3 | 637 | default: |
638 | usage(); | |
639 | return 1; | |
640 | } | |
641 | } | |
642 | signal(SIGINT, sig_intr); | |
5616e319 | 643 | signal(SIGPIPE, SIG_IGN); |
eb5f55b3 | 644 | main_loop(); |
645 | return 0; | |
646 | } |