]> git.ipfire.org Git - thirdparty/squid.git/blame - src/client.cc
Backed out bad/unneded cleanup
[thirdparty/squid.git] / src / client.cc
CommitLineData
16300b58 1
30a4f2a8 2/*
1810dde6 3 * $Id: client.cc,v 1.93 2001/02/23 20:59:50 hno Exp $
30a4f2a8 4 *
5 * DEBUG: section 0 WWW Client
6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
30a4f2a8 34 */
090089c4 35
44a47c6e 36#include "squid.h"
090089c4 37
38#ifndef BUFSIZ
39#define BUFSIZ 8192
40#endif
41
42/* Local functions */
2c08acd9 43static int client_comm_bind(int, char *);
899bab3f 44static int client_comm_connect(int, char *, u_short, struct timeval *);
f5b8bbc4 45static void usage(const char *progname);
899bab3f 46static int Now(struct timeval *);
47static SIGHDLR catch;
54220df8 48static SIGHDLR pipe_handler;
d6d09e02 49static void set_our_signal(void);
20cbfe5a 50static ssize_t myread(int fd, void *buf, size_t len);
51static ssize_t mywrite(int fd, void *buf, size_t len);
cca89eeb 52static int put_fd;
53static char *put_file = NULL;
b6c6bcef 54static struct stat sb;
55int total_bytes = 0;
20cbfe5a 56int io_timeout = 120;
090089c4 57
b8d8561b 58static void
0ee4272b 59usage(const char *progname)
090089c4 60{
0ee4272b 61 fprintf(stderr,
20cbfe5a 62 "Usage: %s [-arsv] [-i IMS] [-h remote host] [-l local host] [-p port] [-m method] [-t count] [-I ping-interval] [-H 'strings'] [-T timeout] url\n"
fe4e214f 63 "Options:\n"
cca89eeb 64 " -P file PUT request.\n"
899bab3f 65 " -a Do NOT include Accept: header.\n"
66 " -r Force cache to reload URL.\n"
67 " -s Silent. Do not print data to stdout.\n"
63259c34 68 " -v Verbose. Print outgoing message to stderr.\n"
899bab3f 69 " -i IMS If-Modified-Since time (in Epoch seconds).\n"
70 " -h host Retrieve URL from cache on hostname. Default is localhost.\n"
2c08acd9 71 " -l host Specify a local IP address to bind to. Default is none.\n"
899bab3f 72 " -p port Port number of cache. Default is %d.\n"
73 " -m method Request method, default is GET.\n"
74 " -t count Trace count cache-hops\n"
75 " -g count Ping mode, \"count\" iterations (0 to loop until interrupted).\n"
63259c34 76 " -I interval Ping interval in seconds (default 1 second).\n"
20cbfe5a 77 " -H 'string' Extra headers to send. Use '\\n' for new lines.\n"
78 " -T timeout Timeout value (seconds) for read/write operations.\n",
fe4e214f 79 progname, CACHE_HTTP_PORT);
090089c4 80 exit(1);
81}
82
899bab3f 83static int interrupted = 0;
b8d8561b 84int
85main(int argc, char *argv[])
090089c4 86{
87 int conn, c, len, bytesWritten;
88 int port, to_stdout, reload;
899bab3f 89 int ping, pcount;
599eadbe 90 int keep_alive = 0;
88738790 91 int opt_noaccept = 0;
63259c34 92 int opt_verbose = 0;
2c08acd9 93 char *hostname, *localhost;
94 char url[BUFSIZ], msg[BUFSIZ], buf[BUFSIZ];
63259c34 95 char extra_hdrs[BUFSIZ];
0ee4272b 96 const char *method = "GET";
090089c4 97 extern char *optarg;
234967c9 98 time_t ims = 0;
b3b64e58 99 int max_forwards = -1;
899bab3f 100 struct timeval tv1, tv2;
101 int i = 0, loops;
102 long ping_int;
103 long ping_min = 0, ping_max = 0, ping_sum = 0, ping_mean = 0;
090089c4 104
105 /* set the defaults */
2c08acd9 106 hostname = "localhost";
107 localhost = NULL;
63259c34 108 extra_hdrs[0] = '\0';
090089c4 109 port = CACHE_HTTP_PORT;
110 to_stdout = 1;
111 reload = 0;
899bab3f 112 ping = 0;
113 pcount = 0;
114 ping_int = 1 * 1000;
090089c4 115
116 if (argc < 2) {
117 usage(argv[0]); /* need URL */
118 } else if (argc >= 2) {
119 strcpy(url, argv[argc - 1]);
120 if (url[0] == '-')
121 usage(argv[0]);
2c08acd9 122 while ((c = getopt(argc, argv, "ah:l:P:i:km:p:rsvt:g:p:I:H:?")) != -1)
090089c4 123 switch (c) {
88738790 124 case 'a':
125 opt_noaccept = 1;
126 break;
2c08acd9 127 case 'h': /* remote host */
090089c4 128 if (optarg != NULL)
2c08acd9 129 hostname = optarg;
130 break;
131 case 'l': /* local host */
132 if (optarg != NULL)
133 localhost = optarg;
090089c4 134 break;
135 case 's': /* silent */
090089c4 136 to_stdout = 0;
137 break;
599eadbe 138 case 'k': /* backward compat */
139 keep_alive = 1;
140 break;
090089c4 141 case 'r': /* reload */
142 reload = 1;
143 break;
144 case 'p': /* port number */
145 sscanf(optarg, "%d", &port);
146 if (port < 1)
147 port = CACHE_HTTP_PORT; /* default */
148 break;
cca89eeb 149 case 'P':
16300b58 150 put_file = xstrdup(optarg);
cca89eeb 151 break;
234967c9 152 case 'i': /* IMS */
153 ims = (time_t) atoi(optarg);
154 break;
155 case 'm':
156 method = xstrdup(optarg);
157 break;
b3b64e58 158 case 't':
159 method = xstrdup("TRACE");
160 max_forwards = atoi(optarg);
161 break;
899bab3f 162 case 'g':
163 ping = 1;
164 pcount = atoi(optarg);
165 to_stdout = 0;
166 break;
167 case 'I':
168 if ((ping_int = atoi(optarg) * 1000) <= 0)
169 usage(argv[0]);
170 break;
63259c34 171 case 'H':
172 if (strlen(optarg)) {
4e41e277 173 char *t;
63259c34 174 strncpy(extra_hdrs, optarg, sizeof(extra_hdrs));
4e41e277 175 while ((t = strstr(extra_hdrs, "\\n")))
b644367b 176 *t = '\r', *(t + 1) = '\n';
63259c34 177 }
178 break;
179 case 'v':
180 /* undocumented: may increase verb-level by giving more -v's */
181 opt_verbose++;
182 break;
090089c4 183 case '?': /* usage */
184 default:
185 usage(argv[0]);
186 break;
187 }
188 }
090089c4 189 /* Build the HTTP request */
8a9b6b94 190 if (strncmp(url, "mgr:", 4) == 0) {
191 char *t = xstrdup(url + 4);
192 snprintf(url, BUFSIZ, "cache_object://%s/%s", hostname, t);
e5f4e1b0 193 xfree(t);
8a9b6b94 194 }
cca89eeb 195 if (put_file) {
16300b58 196 put_fd = open(put_file, O_RDONLY);
54220df8 197 set_our_signal();
16300b58 198 if (put_fd < 0) {
199 fprintf(stderr, "%s: can't open file (%s)\n", argv[0],
200 xstrerror());
201 exit(-1);
cca89eeb 202 }
c4aefe96 203#if defined(_SQUID_CYGWIN_)
204 setmode(put_fd, O_BINARY);
205#endif
b6c6bcef 206 fstat(put_fd, &sb);
cca89eeb 207 }
042461c3 208 snprintf(msg, BUFSIZ, "%s %s HTTP/1.0\r\n", method, url);
090089c4 209 if (reload) {
042461c3 210 snprintf(buf, BUFSIZ, "Pragma: no-cache\r\n");
234967c9 211 strcat(msg, buf);
212 }
16300b58 213 if (put_fd > 0) {
5f6ac48b 214 snprintf(buf, BUFSIZ, "Content-length: %d\r\n", (int) sb.st_size);
cca89eeb 215 strcat(msg, buf);
216 }
88738790 217 if (opt_noaccept == 0) {
042461c3 218 snprintf(buf, BUFSIZ, "Accept: */*\r\n");
88738790 219 strcat(msg, buf);
220 }
234967c9 221 if (ims) {
042461c3 222 snprintf(buf, BUFSIZ, "If-Modified-Since: %s\r\n", mkrfc1123(ims));
234967c9 223 strcat(msg, buf);
090089c4 224 }
b3b64e58 225 if (max_forwards > -1) {
042461c3 226 snprintf(buf, BUFSIZ, "Max-Forwards: %d\r\n", max_forwards);
b3b64e58 227 strcat(msg, buf);
228 }
599eadbe 229 if (keep_alive) {
c62815be 230 if (port != 80)
99edd1c3 231 snprintf(buf, BUFSIZ, "Proxy-Connection: keep-alive\r\n");
c62815be 232 else
99edd1c3 233 snprintf(buf, BUFSIZ, "Connection: keep-alive\r\n");
599eadbe 234 strcat(msg, buf);
235 }
63259c34 236 strcat(msg, extra_hdrs);
042461c3 237 snprintf(buf, BUFSIZ, "\r\n");
234967c9 238 strcat(msg, buf);
090089c4 239
63259c34 240 if (opt_verbose)
241 fprintf(stderr, "headers: '%s'\n", msg);
242
899bab3f 243 if (ping) {
244#if HAVE_SIGACTION
245 struct sigaction sa, osa;
246 if (sigaction(SIGINT, NULL, &osa) == 0 && osa.sa_handler == SIG_DFL) {
247 sa.sa_handler = catch;
248 sa.sa_flags = 0;
249 sigemptyset(&sa.sa_mask);
250 (void) sigaction(SIGINT, &sa, NULL);
251 }
252#else
253 void (*osig) ();
254 if ((osig = signal(SIGINT, catch)) != SIG_DFL)
255 (void) signal(SIGINT, osig);
256#endif
257 }
258 loops = ping ? pcount : 1;
259 for (i = 0; loops == 0 || i < loops; i++) {
d20b1cd0 260 int fsize = 0;
899bab3f 261 /* Connect to the server */
262 if ((conn = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
263 perror("client: socket");
264 exit(1);
265 }
2c08acd9 266 if (localhost && client_comm_bind(conn, localhost) < 0) {
267 perror("client: bind");
268 exit(1);
269 }
899bab3f 270 if (client_comm_connect(conn, hostname, port, ping ? &tv1 : NULL) < 0) {
271 if (errno == 0) {
272 fprintf(stderr, "client: ERROR: Cannot connect to %s:%d: Host unknown.\n", hostname, port);
273 } else {
274 char tbuf[BUFSIZ];
2bbd722b 275 snprintf(tbuf, BUFSIZ, "client: ERROR: Cannot connect to %s:%d",
899bab3f 276 hostname, port);
277 perror(tbuf);
278 }
279 exit(1);
280 }
281 /* Send the HTTP request */
20cbfe5a 282 bytesWritten = mywrite(conn, msg, strlen(msg));
899bab3f 283 if (bytesWritten < 0) {
284 perror("client: ERROR: write");
285 exit(1);
286 } else if (bytesWritten != strlen(msg)) {
287 fprintf(stderr, "client: ERROR: Cannot send request?: %s\n", msg);
288 exit(1);
289 }
cca89eeb 290 if (put_file) {
16300b58 291 int x;
9b7b8edd 292 lseek(put_fd, 0, SEEK_SET);
20cbfe5a 293 while ((x = myread(put_fd, buf, sizeof(buf))) > 0) {
294 x = mywrite(conn, buf, x);
b6c6bcef 295 total_bytes += x;
16300b58 296 if (x <= 0)
297 break;
298 }
b6c6bcef 299 if (x != 0)
16300b58 300 fprintf(stderr, "client: ERROR: Cannot send file.\n");
cca89eeb 301 }
899bab3f 302 /* Read the data */
54220df8 303
20cbfe5a 304 while ((len = myread(conn, buf, sizeof(buf))) > 0) {
d20b1cd0 305 fsize += len;
899bab3f 306 if (to_stdout)
307 fwrite(buf, len, 1, stdout);
308 }
309 (void) close(conn); /* done with socket */
310
311 if (interrupted)
312 break;
313
314 if (ping) {
315 struct tm *tmp;
316 time_t t2s;
317 long elapsed_msec;
318
319 (void) Now(&tv2);
320 elapsed_msec = tvSubMsec(tv1, tv2);
321 t2s = tv2.tv_sec;
322 tmp = localtime(&t2s);
d20b1cd0 323 fprintf(stderr, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs, %f KB/s\n",
899bab3f 324 tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
325 tmp->tm_hour, tmp->tm_min, tmp->tm_sec, i + 1,
d20b1cd0 326 elapsed_msec / 1000, elapsed_msec % 1000,
327 elapsed_msec ? (double) fsize / elapsed_msec : -1.0);
899bab3f 328 if (i == 0 || elapsed_msec < ping_min)
329 ping_min = elapsed_msec;
330 if (i == 0 || elapsed_msec > ping_max)
331 ping_max = elapsed_msec;
332 ping_sum += elapsed_msec;
333 /* Delay until next "ping_int" boundary */
334 if ((loops == 0 || i + 1 < loops) && elapsed_msec < ping_int) {
335 struct timeval tvs;
336 long msec_left = ping_int - elapsed_msec;
337
338 tvs.tv_sec = msec_left / 1000;
339 tvs.tv_usec = (msec_left % 1000) * 1000;
340 select(0, NULL, NULL, NULL, &tvs);
341 }
342 }
090089c4 343 }
899bab3f 344
345 if (ping && i) {
346 ping_mean = ping_sum / i;
347 fprintf(stderr, "%d requests, round-trip (secs) min/avg/max = "
348 "%ld.%03ld/%ld.%03ld/%ld.%03ld\n", i,
349 ping_min / 1000, ping_min % 1000, ping_mean / 1000, ping_mean % 1000,
350 ping_max / 1000, ping_max % 1000);
090089c4 351 }
090089c4 352 exit(0);
353 /*NOTREACHED */
983061ed 354 return 0;
090089c4 355}
356
2c08acd9 357static int
358client_comm_bind(int sock, char *local_host)
359{
360 static const struct hostent *hp = NULL;
361 static struct sockaddr_in from_addr;
362
363 /* Set up the source socket address from which to send. */
364 if (hp == NULL) {
365 from_addr.sin_family = AF_INET;
366
367 if ((hp = gethostbyname(local_host)) == 0) {
368 return (-1);
369 }
370 xmemcpy(&from_addr.sin_addr, hp->h_addr, hp->h_length);
371 from_addr.sin_port = 0;
372 }
373 return bind(sock, (struct sockaddr *) &from_addr, sizeof(struct sockaddr_in));
374}
375
b8d8561b 376static int
899bab3f 377client_comm_connect(int sock, char *dest_host, u_short dest_port, struct timeval *tvp)
090089c4 378{
899bab3f 379 static const struct hostent *hp = NULL;
090089c4 380 static struct sockaddr_in to_addr;
381
382 /* Set up the destination socket address for message to send to. */
899bab3f 383 if (hp == NULL) {
384 to_addr.sin_family = AF_INET;
090089c4 385
899bab3f 386 if ((hp = gethostbyname(dest_host)) == 0) {
387 return (-1);
388 }
389 xmemcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
390 to_addr.sin_port = htons(dest_port);
090089c4 391 }
899bab3f 392 if (tvp)
393 (void) Now(tvp);
090089c4 394 return connect(sock, (struct sockaddr *) &to_addr, sizeof(struct sockaddr_in));
395}
899bab3f 396
397static int
398Now(struct timeval *tp)
399{
400#if GETTIMEOFDAY_NO_TZP
401 return gettimeofday(tp);
402#else
403 return gettimeofday(tp, NULL);
404#endif
405} /* ARGSUSED */
406
407static void
408catch(int sig)
409{
410 interrupted = 1;
411 fprintf(stderr, "Interrupted.\n");
412}
b6c6bcef 413
5446b331 414static void
54220df8 415pipe_handler(int sig)
416{
b6c6bcef 417 fprintf(stderr, "SIGPIPE received.\n");
54220df8 418}
419
420static void
9bc73deb 421set_our_signal(void)
54220df8 422{
423#if HAVE_SIGACTION
424 struct sigaction sa;
425 sa.sa_handler = pipe_handler;
426 sa.sa_flags = SA_RESTART;
427 sigemptyset(&sa.sa_mask);
428 if (sigaction(SIGPIPE, &sa, NULL) < 0) {
b6c6bcef 429 fprintf(stderr, "Cannot set PIPE signal.\n");
54220df8 430 exit(-1);
431 }
432#else
433 signal(SIGPIPE, pipe_handler);
434#endif
435
436}
20cbfe5a 437
438static ssize_t
439myread(int fd, void *buf, size_t len)
440{
441 alarm(io_timeout);
442 return read(fd, buf, len);
443}
444
445static ssize_t
446mywrite(int fd, void *buf, size_t len)
447{
448 alarm(io_timeout);
449 return write(fd, buf, len);
450}