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