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