]>
Commit | Line | Data |
---|---|---|
30a4f2a8 | 1 | /* |
5ac5029d AJ |
2 | * $Id$ |
3 | * | |
30a4f2a8 | 4 | * DEBUG: section 0 WWW Client |
5 | * AUTHOR: Harvest Derived | |
6 | * | |
2b6662ba | 7 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 8 | * ---------------------------------------------------------- |
30a4f2a8 | 9 | * |
2b6662ba | 10 | * Squid is the result of efforts by numerous individuals from |
11 | * the Internet community; see the CONTRIBUTORS file for full | |
12 | * details. Many organizations have provided support for Squid's | |
13 | * development; see the SPONSORS file for full details. Squid is | |
14 | * Copyrighted (C) 2001 by the Regents of the University of | |
15 | * California; see the COPYRIGHT file for full details. Squid | |
16 | * incorporates software developed and/or copyrighted by other | |
17 | * sources; see the CREDITS file for full details. | |
30a4f2a8 | 18 | * |
19 | * This program is free software; you can redistribute it and/or modify | |
20 | * it under the terms of the GNU General Public License as published by | |
21 | * the Free Software Foundation; either version 2 of the License, or | |
22 | * (at your option) any later version. | |
3afd7aae | 23 | * |
30a4f2a8 | 24 | * This program is distributed in the hope that it will be useful, |
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
27 | * GNU General Public License for more details. | |
3afd7aae | 28 | * |
30a4f2a8 | 29 | * You should have received a copy of the GNU General Public License |
30 | * along with this program; if not, write to the Free Software | |
cbdec147 | 31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 32 | * |
30a4f2a8 | 33 | */ |
090089c4 | 34 | |
94ab55b0 | 35 | #include "config.h" |
36 | ||
15443eec | 37 | #ifdef _SQUID_MSWIN_ |
63be0a78 | 38 | /** \cond AUTODOCS-IGNORE */ |
15443eec | 39 | using namespace Squid; |
63be0a78 | 40 | /** \endcond */ |
15443eec | 41 | #endif |
42 | ||
b55fa77d | 43 | #ifdef _SQUID_WIN32_ |
44 | #include <io.h> | |
45 | #endif | |
815f9118 | 46 | #if HAVE_STDIO_H |
94ab55b0 | 47 | #include <stdio.h> |
815f9118 | 48 | #endif |
815f9118 | 49 | #if HAVE_SYS_SOCKET_H |
94ab55b0 | 50 | #include <sys/socket.h> |
815f9118 | 51 | #endif |
52 | #if HAVE_STRING_H | |
94ab55b0 | 53 | #include <string.h> |
815f9118 | 54 | #endif |
55 | #if HAVE_UNISTD_H | |
94ab55b0 | 56 | #include <unistd.h> |
815f9118 | 57 | #endif |
489520a9 | 58 | #if HAVE_NETDB_H |
94ab55b0 | 59 | #include <netdb.h> |
815f9118 | 60 | #endif |
61 | #if HAVE_SIGNAL_H | |
94ab55b0 | 62 | #include <signal.h> |
815f9118 | 63 | #endif |
64 | #if HAVE_ERRNO_H | |
94ab55b0 | 65 | #include <errno.h> |
815f9118 | 66 | #endif |
67 | #if HAVE_SYS_STAT_H | |
94ab55b0 | 68 | #include <sys/stat.h> |
815f9118 | 69 | #endif |
70 | #if HAVE_FCNTL_H | |
94ab55b0 | 71 | #include <fcntl.h> |
815f9118 | 72 | #endif |
73 | #if HAVE_NETINET_IN_H | |
c7f83c7a | 74 | #include <netinet/in.h> |
815f9118 | 75 | #endif |
d3e3ff4f | 76 | #if HAVE_GETOPT_H |
77 | #include <getopt.h> | |
78 | #endif | |
94ab55b0 | 79 | |
80 | #include "util.h" | |
9837e5f0 | 81 | #include "ip/IpAddress.h" |
090089c4 | 82 | |
83 | #ifndef BUFSIZ | |
7ed62376 AJ |
84 | #define BUFSIZ 8192 |
85 | #endif | |
86 | #ifndef MESSAGELEN | |
87 | #define MESSAGELEN 65536 | |
88 | #endif | |
89 | #ifndef HEADERLEN | |
90 | #define HEADERLEN 65536 | |
090089c4 | 91 | #endif |
92 | ||
94ab55b0 | 93 | typedef void SIGHDLR(int sig); |
94 | ||
090089c4 | 95 | /* Local functions */ |
ad61a2b4 | 96 | static int client_comm_bind(int, const IpAddress &); |
62e76326 | 97 | |
ad61a2b4 | 98 | static int client_comm_connect(int, const IpAddress &, struct timeval *); |
f5b8bbc4 | 99 | static void usage(const char *progname); |
62e76326 | 100 | |
899bab3f | 101 | static int Now(struct timeval *); |
e6ccf245 | 102 | static SIGHDLR catchSignal; |
54220df8 | 103 | static SIGHDLR pipe_handler; |
d6d09e02 | 104 | static void set_our_signal(void); |
20cbfe5a | 105 | static ssize_t myread(int fd, void *buf, size_t len); |
106 | static ssize_t mywrite(int fd, void *buf, size_t len); | |
cca89eeb | 107 | static int put_fd; |
108 | static char *put_file = NULL; | |
62e76326 | 109 | |
b6c6bcef | 110 | static struct stat sb; |
111 | int total_bytes = 0; | |
20cbfe5a | 112 | int io_timeout = 120; |
090089c4 | 113 | |
ec556193 GS |
114 | #ifdef _SQUID_MSWIN_ |
115 | void | |
116 | Win32SockCleanup(void) | |
117 | { | |
118 | WSACleanup(); | |
119 | return; | |
120 | } | |
121 | #endif /* ifdef _SQUID_MSWIN_ */ | |
122 | ||
b8d8561b | 123 | static void |
0ee4272b | 124 | usage(const char *progname) |
090089c4 | 125 | { |
0ee4272b | 126 | fprintf(stderr, |
3afd7aae | 127 | "Version: %s\n" |
4f16e7af | 128 | "Usage: %s [-arsv] [-g count] [-h remote host] [-H 'string'] [-i IMS] [-I ping-interval] [-j 'Host-header']" |
51d94d10 | 129 | "[-k] [-l local-host] [-m method] [-p port] [-P file] [-t count] [-T timeout] [-u proxy-user] [-U www-user] " |
4f16e7af AJ |
130 | "[-V version] [-w proxy-password] [-W www-password] url\n" |
131 | "\n" | |
3afd7aae | 132 | "Options:\n" |
3afd7aae | 133 | " -a Do NOT include Accept: header.\n" |
4f16e7af | 134 | " -g count Ping mode, perform \"count\" iterations (0 to loop until interrupted).\n" |
3afd7aae | 135 | " -h host Retrieve URL from cache on hostname. Default is localhost.\n" |
4f16e7af AJ |
136 | " -H 'string' Extra headers to send. Use '\\n' for new lines.\n" |
137 | " -i IMS If-Modified-Since time (in Epoch seconds).\n" | |
138 | " -I interval Ping interval in seconds (default 1 second).\n" | |
5ac5029d | 139 | " -j hosthdr Host header content\n" |
51d94d10 | 140 | " -k Keep the connection active. Default is to do only one request then close.\n" |
4f16e7af | 141 | " -l host Specify a local IP address to bind to. Default is none.\n" |
3afd7aae | 142 | " -m method Request method, default is GET.\n" |
4f16e7af AJ |
143 | " -p port Port number of cache. Default is %d.\n" |
144 | " -P file PUT request. Using the named file\n" | |
145 | " -r Force cache to reload URL.\n" | |
146 | " -s Silent. Do not print data to stdout.\n" | |
3afd7aae | 147 | " -t count Trace count cache-hops\n" |
3afd7aae AJ |
148 | " -T timeout Timeout value (seconds) for read/write operations.\n" |
149 | " -u user Proxy authentication username\n" | |
3afd7aae | 150 | " -U user WWW authentication username\n" |
4f16e7af | 151 | " -v Verbose. Print outgoing message to stderr.\n" |
5ac5029d | 152 | " -V version HTTP Version. Use '-' for HTTP/0.9 omitted case\n", |
4f16e7af AJ |
153 | " -w password Proxy authentication password\n" |
154 | " -W password WWW authentication password\n" | |
3afd7aae | 155 | VERSION, progname, CACHE_HTTP_PORT); |
090089c4 | 156 | exit(1); |
157 | } | |
158 | ||
899bab3f | 159 | static int interrupted = 0; |
b8d8561b | 160 | int |
161 | main(int argc, char *argv[]) | |
090089c4 | 162 | { |
163 | int conn, c, len, bytesWritten; | |
164 | int port, to_stdout, reload; | |
899bab3f | 165 | int ping, pcount; |
599eadbe | 166 | int keep_alive = 0; |
88738790 | 167 | int opt_noaccept = 0; |
63259c34 | 168 | int opt_verbose = 0; |
a2c963ae | 169 | const char *hostname, *localhost; |
ad61a2b4 | 170 | IpAddress iaddr; |
7ed62376 AJ |
171 | char url[BUFSIZ], msg[MESSAGELEN], buf[BUFSIZ]; |
172 | char extra_hdrs[HEADERLEN]; | |
0ee4272b | 173 | const char *method = "GET"; |
090089c4 | 174 | extern char *optarg; |
234967c9 | 175 | time_t ims = 0; |
b3b64e58 | 176 | int max_forwards = -1; |
62e76326 | 177 | |
899bab3f | 178 | struct timeval tv1, tv2; |
179 | int i = 0, loops; | |
180 | long ping_int; | |
181 | long ping_min = 0, ping_max = 0, ping_sum = 0, ping_mean = 0; | |
5ac5029d AJ |
182 | const char *proxy_user = NULL; |
183 | const char *proxy_password = NULL; | |
184 | const char *www_user = NULL; | |
185 | const char *www_password = NULL; | |
186 | const char *host = NULL; | |
187 | const char *version = "1.0"; | |
090089c4 | 188 | |
189 | /* set the defaults */ | |
2c08acd9 | 190 | hostname = "localhost"; |
191 | localhost = NULL; | |
63259c34 | 192 | extra_hdrs[0] = '\0'; |
090089c4 | 193 | port = CACHE_HTTP_PORT; |
194 | to_stdout = 1; | |
195 | reload = 0; | |
899bab3f | 196 | ping = 0; |
197 | pcount = 0; | |
198 | ping_int = 1 * 1000; | |
090089c4 | 199 | |
200 | if (argc < 2) { | |
3afd7aae | 201 | usage(argv[0]); /* need URL */ |
090089c4 | 202 | } else if (argc >= 2) { |
3afd7aae AJ |
203 | strncpy(url, argv[argc - 1], BUFSIZ); |
204 | url[BUFSIZ - 1] = '\0'; | |
62e76326 | 205 | |
3afd7aae AJ |
206 | if (url[0] == '-') |
207 | usage(argv[0]); | |
62e76326 | 208 | |
5ac5029d | 209 | while ((c = getopt(argc, argv, "ah:j:V:l:P:i:km:p:rsvt:g:p:I:H:T:u:U:w:W:?")) != -1) |
3afd7aae | 210 | switch (c) { |
62e76326 | 211 | |
3afd7aae AJ |
212 | case 'a': |
213 | opt_noaccept = 1; | |
214 | break; | |
62e76326 | 215 | |
3afd7aae | 216 | case 'h': /* remote host */ |
3afd7aae AJ |
217 | if (optarg != NULL) |
218 | hostname = optarg; | |
5ac5029d | 219 | break; |
62e76326 | 220 | |
5ac5029d | 221 | case 'j': |
af6a12ee AJ |
222 | host = optarg; |
223 | break; | |
5ac5029d AJ |
224 | |
225 | case 'V': | |
226 | if (optarg != NULL) | |
227 | version = optarg; | |
3afd7aae | 228 | break; |
62e76326 | 229 | |
3afd7aae AJ |
230 | case 'l': /* local host */ |
231 | if (optarg != NULL) | |
232 | localhost = optarg; | |
3afd7aae | 233 | break; |
62e76326 | 234 | |
3afd7aae AJ |
235 | case 's': /* silent */ |
236 | to_stdout = 0; | |
3afd7aae | 237 | break; |
62e76326 | 238 | |
3afd7aae AJ |
239 | case 'k': /* backward compat */ |
240 | keep_alive = 1; | |
3afd7aae | 241 | break; |
62e76326 | 242 | |
3afd7aae AJ |
243 | case 'r': /* reload */ |
244 | reload = 1; | |
3afd7aae | 245 | break; |
62e76326 | 246 | |
3afd7aae AJ |
247 | case 'p': /* port number */ |
248 | sscanf(optarg, "%d", &port); | |
3afd7aae AJ |
249 | if (port < 1) |
250 | port = CACHE_HTTP_PORT; /* default */ | |
3afd7aae | 251 | break; |
62e76326 | 252 | |
3afd7aae AJ |
253 | case 'P': |
254 | put_file = xstrdup(optarg); | |
3afd7aae | 255 | break; |
62e76326 | 256 | |
3afd7aae AJ |
257 | case 'i': /* IMS */ |
258 | ims = (time_t) atoi(optarg); | |
3afd7aae | 259 | break; |
62e76326 | 260 | |
3afd7aae AJ |
261 | case 'm': |
262 | method = xstrdup(optarg); | |
3afd7aae | 263 | break; |
62e76326 | 264 | |
3afd7aae AJ |
265 | case 't': |
266 | method = xstrdup("TRACE"); | |
3afd7aae | 267 | max_forwards = atoi(optarg); |
3afd7aae | 268 | break; |
62e76326 | 269 | |
3afd7aae AJ |
270 | case 'g': |
271 | ping = 1; | |
3afd7aae | 272 | pcount = atoi(optarg); |
3afd7aae | 273 | to_stdout = 0; |
3afd7aae | 274 | break; |
62e76326 | 275 | |
3afd7aae AJ |
276 | case 'I': |
277 | if ((ping_int = atoi(optarg) * 1000) <= 0) | |
278 | usage(argv[0]); | |
3afd7aae | 279 | break; |
62e76326 | 280 | |
3afd7aae AJ |
281 | case 'H': |
282 | if (strlen(optarg)) { | |
283 | char *t; | |
284 | strncpy(extra_hdrs, optarg, sizeof(extra_hdrs)); | |
3afd7aae AJ |
285 | while ((t = strstr(extra_hdrs, "\\n"))) |
286 | *t = '\r', *(t + 1) = '\n'; | |
287 | } | |
288 | break; | |
62e76326 | 289 | |
3afd7aae AJ |
290 | case 'T': |
291 | io_timeout = atoi(optarg); | |
292 | break; | |
62e76326 | 293 | |
3afd7aae AJ |
294 | case 'u': |
295 | proxy_user = optarg; | |
296 | break; | |
62e76326 | 297 | |
3afd7aae AJ |
298 | case 'w': |
299 | proxy_password = optarg; | |
300 | break; | |
62e76326 | 301 | |
3afd7aae AJ |
302 | case 'U': |
303 | www_user = optarg; | |
304 | break; | |
62e76326 | 305 | |
3afd7aae AJ |
306 | case 'W': |
307 | www_password = optarg; | |
308 | break; | |
62e76326 | 309 | |
3afd7aae AJ |
310 | case 'v': |
311 | /* undocumented: may increase verb-level by giving more -v's */ | |
312 | opt_verbose++; | |
313 | break; | |
62e76326 | 314 | |
3afd7aae | 315 | case '?': /* usage */ |
62e76326 | 316 | |
3afd7aae AJ |
317 | default: |
318 | usage(argv[0]); | |
319 | break; | |
320 | } | |
090089c4 | 321 | } |
0ef0f1de | 322 | #ifdef _SQUID_MSWIN_ |
323 | { | |
3afd7aae AJ |
324 | WSADATA wsaData; |
325 | WSAStartup(2, &wsaData); | |
326 | atexit(Win32SockCleanup); | |
0ef0f1de | 327 | } |
328 | #endif | |
090089c4 | 329 | /* Build the HTTP request */ |
8a9b6b94 | 330 | if (strncmp(url, "mgr:", 4) == 0) { |
3afd7aae AJ |
331 | char *t = xstrdup(url + 4); |
332 | snprintf(url, BUFSIZ, "cache_object://%s/%s", hostname, t); | |
333 | xfree(t); | |
8a9b6b94 | 334 | } |
cca89eeb | 335 | if (put_file) { |
3afd7aae AJ |
336 | put_fd = open(put_file, O_RDONLY); |
337 | set_our_signal(); | |
338 | ||
339 | if (put_fd < 0) { | |
340 | fprintf(stderr, "%s: can't open file (%s)\n", argv[0], | |
341 | xstrerror()); | |
342 | exit(-1); | |
343 | } | |
ec4daaa5 | 344 | #ifdef _SQUID_WIN32_ |
3afd7aae | 345 | setmode(put_fd, O_BINARY); |
62e76326 | 346 | |
c4aefe96 | 347 | #endif |
62e76326 | 348 | |
3afd7aae | 349 | fstat(put_fd, &sb); |
cca89eeb | 350 | } |
5ac5029d AJ |
351 | |
352 | if (!host) { | |
af6a12ee AJ |
353 | char *newhost = strstr(url, "://"); |
354 | if (newhost) { | |
355 | char *t; | |
356 | newhost += 3; | |
dc47f531 | 357 | newhost = xstrdup(newhost); |
af6a12ee AJ |
358 | t = newhost + strcspn(newhost, "@/?"); |
359 | if (*t == '@') { | |
360 | newhost = t + 1; | |
361 | t = newhost + strcspn(newhost, "@/?"); | |
362 | } | |
363 | *t = '\0'; | |
364 | host = newhost; | |
365 | } | |
5ac5029d AJ |
366 | } |
367 | ||
af6a12ee AJ |
368 | if (version[0] == '-' || !version[0] || version[0] == '0') { |
369 | /* HTTP/0.9, no headers, no version */ | |
5ac5029d AJ |
370 | snprintf(msg, BUFSIZ, "%s %s\r\n", method, url); |
371 | } else { | |
372 | snprintf(msg, BUFSIZ, "%s %s HTTP/%s\r\n", method, url, version); | |
62e76326 | 373 | |
af6a12ee AJ |
374 | if (host) { |
375 | snprintf(buf, BUFSIZ, "Host: %s\r\n", host); | |
376 | strcat(msg,buf); | |
377 | } | |
378 | ||
379 | if (reload) { | |
380 | snprintf(buf, BUFSIZ, "Pragma: no-cache\r\n"); | |
381 | strcat(msg, buf); | |
382 | } | |
383 | if (put_fd > 0) { | |
173bc2bf | 384 | snprintf(buf, BUFSIZ, "Content-length: %" PRId64 "\r\n", (int64_t) sb.st_size); |
af6a12ee AJ |
385 | strcat(msg, buf); |
386 | } | |
387 | if (opt_noaccept == 0) { | |
388 | snprintf(buf, BUFSIZ, "Accept: */*\r\n"); | |
389 | strcat(msg, buf); | |
390 | } | |
391 | if (ims) { | |
392 | snprintf(buf, BUFSIZ, "If-Modified-Since: %s\r\n", mkrfc1123(ims)); | |
393 | strcat(msg, buf); | |
394 | } | |
395 | if (max_forwards > -1) { | |
396 | snprintf(buf, BUFSIZ, "Max-Forwards: %d\r\n", max_forwards); | |
397 | strcat(msg, buf); | |
398 | } | |
399 | if (proxy_user) { | |
400 | const char *user = proxy_user; | |
401 | const char *password = proxy_password; | |
230c091c | 402 | #if HAVE_GETPASS |
af6a12ee AJ |
403 | if (!password) |
404 | password = getpass("Proxy password: "); | |
230c091c | 405 | #endif |
af6a12ee AJ |
406 | if (!password) { |
407 | fprintf(stderr, "ERROR: Proxy password missing\n"); | |
408 | exit(1); | |
409 | } | |
410 | snprintf(buf, BUFSIZ, "%s:%s", user, password); | |
411 | snprintf(buf, BUFSIZ, "Proxy-Authorization: Basic %s\r\n", base64_encode(buf)); | |
412 | strcat(msg, buf); | |
413 | } | |
414 | if (www_user) { | |
415 | const char *user = www_user; | |
416 | const char *password = www_password; | |
230c091c | 417 | #if HAVE_GETPASS |
af6a12ee AJ |
418 | if (!password) |
419 | password = getpass("WWW password: "); | |
230c091c | 420 | #endif |
af6a12ee AJ |
421 | if (!password) { |
422 | fprintf(stderr, "ERROR: WWW password missing\n"); | |
423 | exit(1); | |
424 | } | |
425 | snprintf(buf, BUFSIZ, "%s:%s", user, password); | |
426 | snprintf(buf, BUFSIZ, "Authorization: Basic %s\r\n", base64_encode(buf)); | |
427 | strcat(msg, buf); | |
428 | } | |
429 | ||
430 | /* HTTP/1.0 may need keep-alive */ | |
431 | if (strcmp(version, "1.0") == 0) { | |
432 | if (keep_alive) { | |
4f5ec547 | 433 | if (strchr(url, ':')) { |
af6a12ee | 434 | snprintf(buf, BUFSIZ, "Proxy-Connection: keep-alive\r\n"); |
4f5ec547 AJ |
435 | strcat(msg, buf); |
436 | } else | |
af6a12ee AJ |
437 | strcat(msg, "Connection: keep-alive\r\n"); |
438 | } | |
af6a12ee | 439 | } |
51d94d10 AJ |
440 | /* HTTP/1.1 may need close */ |
441 | if (!keep_alive) | |
442 | strcat(msg, "Connection: close\r\n"); | |
af6a12ee AJ |
443 | |
444 | strcat(msg, extra_hdrs); | |
445 | strcat(msg, "\r\n"); | |
a78886fc | 446 | } |
5ac5029d | 447 | |
63259c34 | 448 | if (opt_verbose) |
d698d2a5 | 449 | fprintf(stderr, "Request: '%s'\n", msg); |
63259c34 | 450 | |
899bab3f | 451 | if (ping) { |
452 | #if HAVE_SIGACTION | |
62e76326 | 453 | |
3afd7aae | 454 | struct sigaction sa, osa; |
62e76326 | 455 | |
3afd7aae AJ |
456 | if (sigaction(SIGINT, NULL, &osa) == 0 && osa.sa_handler == SIG_DFL) { |
457 | sa.sa_handler = catchSignal; | |
458 | sa.sa_flags = 0; | |
459 | sigemptyset(&sa.sa_mask); | |
460 | (void) sigaction(SIGINT, &sa, NULL); | |
461 | } | |
899bab3f | 462 | #else |
3afd7aae | 463 | void (*osig) (int); |
62e76326 | 464 | |
3afd7aae AJ |
465 | if ((osig = signal(SIGINT, catchSignal)) != SIG_DFL) |
466 | (void) signal(SIGINT, osig); | |
62e76326 | 467 | |
899bab3f | 468 | #endif |
62e76326 | 469 | |
899bab3f | 470 | } |
471 | loops = ping ? pcount : 1; | |
62e76326 | 472 | |
899bab3f | 473 | for (i = 0; loops == 0 || i < loops; i++) { |
3afd7aae | 474 | int fsize = 0; |
cc192b50 | 475 | struct addrinfo *AI = NULL; |
476 | ||
3afd7aae | 477 | /* Connect to the server */ |
988e90e1 | 478 | |
3afd7aae AJ |
479 | if (localhost) { |
480 | if ( !iaddr.GetHostByName(localhost) ) { | |
cc192b50 | 481 | fprintf(stderr, "client: ERROR: Cannot resolve %s: Host unknown.\n", localhost); |
482 | exit(1); | |
483 | } | |
3afd7aae | 484 | } else { |
cc192b50 | 485 | /* Process the remote host name to locate the Protocol required |
486 | in case we are being asked to link to another version of squid */ | |
3afd7aae | 487 | if ( !iaddr.GetHostByName(hostname) ) { |
cc192b50 | 488 | fprintf(stderr, "client: ERROR: Cannot resolve %s: Host unknown.\n", hostname); |
489 | exit(1); | |
490 | } | |
491 | } | |
492 | ||
493 | iaddr.GetAddrInfo(AI); | |
494 | if ((conn = socket(AI->ai_family, AI->ai_socktype, 0)) < 0) { | |
495 | perror("client: socket"); | |
496 | iaddr.FreeAddrInfo(AI); | |
497 | exit(1); | |
498 | } | |
499 | iaddr.FreeAddrInfo(AI); | |
500 | ||
501 | if (localhost && client_comm_bind(conn, iaddr) < 0) { | |
502 | perror("client: bind"); | |
503 | exit(1); | |
504 | } | |
505 | ||
506 | iaddr.SetEmpty(); | |
3afd7aae | 507 | if ( !iaddr.GetHostByName(hostname) ) { |
cc192b50 | 508 | fprintf(stderr, "client: ERROR: Cannot resolve %s: Host unknown.\n", hostname); |
509 | exit(1); | |
510 | } | |
511 | ||
512 | iaddr.SetPort(port); | |
513 | ||
514 | if (client_comm_connect(conn, iaddr, ping ? &tv1 : NULL) < 0) { | |
e053c141 FC |
515 | char hostnameBuf[MAX_IPSTRLEN]; |
516 | iaddr.ToURL(hostnameBuf, MAX_IPSTRLEN); | |
cc192b50 | 517 | if (errno == 0) { |
e053c141 | 518 | fprintf(stderr, "client: ERROR: Cannot connect to %s: Host unknown.\n", hostnameBuf); |
cc192b50 | 519 | } else { |
520 | char tbuf[BUFSIZ]; | |
e053c141 | 521 | snprintf(tbuf, BUFSIZ, "client: ERROR: Cannot connect to %s", hostnameBuf); |
cc192b50 | 522 | perror(tbuf); |
523 | } | |
524 | exit(1); | |
525 | } | |
988e90e1 | 526 | |
3afd7aae AJ |
527 | /* Send the HTTP request */ |
528 | bytesWritten = mywrite(conn, msg, strlen(msg)); | |
988e90e1 | 529 | |
3afd7aae AJ |
530 | if (bytesWritten < 0) { |
531 | perror("client: ERROR: write"); | |
532 | exit(1); | |
533 | } else if ((unsigned) bytesWritten != strlen(msg)) { | |
534 | fprintf(stderr, "client: ERROR: Cannot send request?: %s\n", msg); | |
535 | exit(1); | |
536 | } | |
cc192b50 | 537 | |
3afd7aae AJ |
538 | if (put_file) { |
539 | int x; | |
540 | lseek(put_fd, 0, SEEK_SET); | |
0ef0f1de | 541 | #ifdef _SQUID_MSWIN_ |
62e76326 | 542 | |
3afd7aae | 543 | while ((x = read(put_fd, buf, sizeof(buf))) > 0) { |
0ef0f1de | 544 | #else |
62e76326 | 545 | |
3afd7aae | 546 | while ((x = myread(put_fd, buf, sizeof(buf))) > 0) { |
0ef0f1de | 547 | #endif |
3afd7aae | 548 | x = mywrite(conn, buf, x); |
62e76326 | 549 | |
3afd7aae | 550 | total_bytes += x; |
62e76326 | 551 | |
3afd7aae AJ |
552 | if (x <= 0) |
553 | break; | |
554 | } | |
62e76326 | 555 | |
3afd7aae AJ |
556 | if (x != 0) |
557 | fprintf(stderr, "client: ERROR: Cannot send file.\n"); | |
558 | } | |
559 | /* Read the data */ | |
54220df8 | 560 | |
0ef0f1de | 561 | #ifdef _SQUID_MSWIN_ |
3afd7aae | 562 | setmode(1, O_BINARY); |
62e76326 | 563 | |
00f768c1 | 564 | #endif |
62e76326 | 565 | |
3afd7aae AJ |
566 | while ((len = myread(conn, buf, sizeof(buf))) > 0) { |
567 | fsize += len; | |
62e76326 | 568 | |
8fee788b AR |
569 | if (to_stdout && fwrite(buf, len, 1, stdout) != 1) |
570 | perror("client: ERROR writing to stdout"); | |
3afd7aae | 571 | } |
62e76326 | 572 | |
0ef0f1de | 573 | #ifdef _SQUID_MSWIN_ |
3afd7aae | 574 | setmode(1, O_TEXT); |
62e76326 | 575 | |
0ef0f1de | 576 | #endif |
62e76326 | 577 | |
3afd7aae | 578 | (void) close(conn); /* done with socket */ |
62e76326 | 579 | |
3afd7aae AJ |
580 | if (interrupted) |
581 | break; | |
62e76326 | 582 | |
3afd7aae | 583 | if (ping) { |
62e76326 | 584 | |
3afd7aae AJ |
585 | struct tm *tmp; |
586 | time_t t2s; | |
587 | long elapsed_msec; | |
62e76326 | 588 | |
3afd7aae AJ |
589 | (void) Now(&tv2); |
590 | elapsed_msec = tvSubMsec(tv1, tv2); | |
591 | t2s = tv2.tv_sec; | |
592 | tmp = localtime(&t2s); | |
593 | fprintf(stderr, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs, %f KB/s\n", | |
594 | tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, | |
595 | tmp->tm_hour, tmp->tm_min, tmp->tm_sec, i + 1, | |
596 | elapsed_msec / 1000, elapsed_msec % 1000, | |
597 | elapsed_msec ? (double) fsize / elapsed_msec : -1.0); | |
62e76326 | 598 | |
3afd7aae AJ |
599 | if (i == 0 || elapsed_msec < ping_min) |
600 | ping_min = elapsed_msec; | |
62e76326 | 601 | |
3afd7aae AJ |
602 | if (i == 0 || elapsed_msec > ping_max) |
603 | ping_max = elapsed_msec; | |
62e76326 | 604 | |
3afd7aae | 605 | ping_sum += elapsed_msec; |
62e76326 | 606 | |
3afd7aae AJ |
607 | /* Delay until next "ping_int" boundary */ |
608 | if ((loops == 0 || i + 1 < loops) && elapsed_msec < ping_int) { | |
62e76326 | 609 | |
3afd7aae AJ |
610 | struct timeval tvs; |
611 | long msec_left = ping_int - elapsed_msec; | |
62e76326 | 612 | |
3afd7aae AJ |
613 | tvs.tv_sec = msec_left / 1000; |
614 | tvs.tv_usec = (msec_left % 1000) * 1000; | |
615 | select(0, NULL, NULL, NULL, &tvs); | |
616 | } | |
617 | } | |
090089c4 | 618 | } |
899bab3f | 619 | |
620 | if (ping && i) { | |
3afd7aae AJ |
621 | ping_mean = ping_sum / i; |
622 | fprintf(stderr, "%d requests, round-trip (secs) min/avg/max = " | |
623 | "%ld.%03ld/%ld.%03ld/%ld.%03ld\n", i, | |
624 | ping_min / 1000, ping_min % 1000, ping_mean / 1000, ping_mean % 1000, | |
625 | ping_max / 1000, ping_max % 1000); | |
090089c4 | 626 | } |
090089c4 | 627 | exit(0); |
628 | /*NOTREACHED */ | |
983061ed | 629 | return 0; |
090089c4 | 630 | } |
631 | ||
2c08acd9 | 632 | static int |
e1381638 AJ |
633 | client_comm_bind(int sock, const IpAddress &addr) |
634 | { | |
62e76326 | 635 | |
cc192b50 | 636 | int res; |
62e76326 | 637 | |
cc192b50 | 638 | static struct addrinfo *AI = NULL; |
2c08acd9 | 639 | |
640 | /* Set up the source socket address from which to send. */ | |
62e76326 | 641 | |
cc192b50 | 642 | addr.GetAddrInfo(AI); |
2c08acd9 | 643 | |
cc192b50 | 644 | res = bind(sock, AI->ai_addr, AI->ai_addrlen); |
645 | ||
646 | addr.FreeAddrInfo(AI); | |
647 | ||
648 | return res; | |
2c08acd9 | 649 | } |
650 | ||
b8d8561b | 651 | static int |
e1381638 AJ |
652 | client_comm_connect(int sock, const IpAddress &addr, struct timeval *tvp) |
653 | { | |
cc192b50 | 654 | int res; |
655 | static struct addrinfo *AI = NULL; | |
62e76326 | 656 | |
cc192b50 | 657 | /* Set up the destination socket address for message to send to. */ |
62e76326 | 658 | |
cc192b50 | 659 | addr.GetAddrInfo(AI); |
090089c4 | 660 | |
cc192b50 | 661 | res = connect(sock, AI->ai_addr, AI->ai_addrlen); |
090089c4 | 662 | |
cc192b50 | 663 | addr.FreeAddrInfo(AI); |
62e76326 | 664 | |
899bab3f | 665 | if (tvp) |
cc192b50 | 666 | (void) Now(tvp); |
62e76326 | 667 | |
cc192b50 | 668 | return res; |
090089c4 | 669 | } |
899bab3f | 670 | |
671 | static int | |
e1381638 AJ |
672 | Now(struct timeval *tp) |
673 | { | |
899bab3f | 674 | #if GETTIMEOFDAY_NO_TZP |
675 | return gettimeofday(tp); | |
676 | #else | |
62e76326 | 677 | |
899bab3f | 678 | return gettimeofday(tp, NULL); |
679 | #endif | |
680 | } /* ARGSUSED */ | |
681 | ||
682 | static void | |
e1381638 AJ |
683 | catchSignal(int sig) |
684 | { | |
899bab3f | 685 | interrupted = 1; |
686 | fprintf(stderr, "Interrupted.\n"); | |
687 | } | |
b6c6bcef | 688 | |
5446b331 | 689 | static void |
e1381638 AJ |
690 | pipe_handler(int sig) |
691 | { | |
b6c6bcef | 692 | fprintf(stderr, "SIGPIPE received.\n"); |
54220df8 | 693 | } |
694 | ||
695 | static void | |
e1381638 AJ |
696 | set_our_signal(void) |
697 | { | |
54220df8 | 698 | #if HAVE_SIGACTION |
62e76326 | 699 | |
54220df8 | 700 | struct sigaction sa; |
701 | sa.sa_handler = pipe_handler; | |
702 | sa.sa_flags = SA_RESTART; | |
703 | sigemptyset(&sa.sa_mask); | |
62e76326 | 704 | |
54220df8 | 705 | if (sigaction(SIGPIPE, &sa, NULL) < 0) { |
3afd7aae AJ |
706 | fprintf(stderr, "Cannot set PIPE signal.\n"); |
707 | exit(-1); | |
54220df8 | 708 | } |
709 | #else | |
710 | signal(SIGPIPE, pipe_handler); | |
62e76326 | 711 | |
54220df8 | 712 | #endif |
713 | ||
714 | } | |
20cbfe5a | 715 | |
716 | static ssize_t | |
e1381638 AJ |
717 | myread(int fd, void *buf, size_t len) |
718 | { | |
00f768c1 | 719 | #ifndef _SQUID_MSWIN_ |
20cbfe5a | 720 | alarm(io_timeout); |
721 | return read(fd, buf, len); | |
00f768c1 | 722 | #else |
723 | ||
724 | return recv(fd, buf, len, 0); | |
725 | #endif | |
20cbfe5a | 726 | } |
727 | ||
728 | static ssize_t | |
e1381638 AJ |
729 | mywrite(int fd, void *buf, size_t len) |
730 | { | |
00f768c1 | 731 | #ifndef _SQUID_MSWIN_ |
20cbfe5a | 732 | alarm(io_timeout); |
733 | return write(fd, buf, len); | |
00f768c1 | 734 | #else |
62e76326 | 735 | |
00f768c1 | 736 | return send(fd, buf, len, 0); |
0ef0f1de | 737 | #endif |
00f768c1 | 738 | } |