]>
Commit | Line | Data |
---|---|---|
ea3a2a69 | 1 | |
da2d50d1 | 2 | |
30a4f2a8 | 3 | /* |
da2d50d1 | 4 | * $Id: client.cc,v 1.42 1997/11/21 01:59:15 wessels Exp $ |
30a4f2a8 | 5 | * |
6 | * DEBUG: section 0 WWW Client | |
7 | * AUTHOR: Harvest Derived | |
8 | * | |
42c04c16 | 9 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ |
30a4f2a8 | 10 | * -------------------------------------------------------- |
11 | * | |
12 | * Squid is the result of efforts by numerous individuals from the | |
13 | * Internet community. Development is led by Duane Wessels of the | |
14 | * National Laboratory for Applied Network Research and funded by | |
15 | * the National Science Foundation. | |
16 | * | |
17 | * This program is free software; you can redistribute it and/or modify | |
18 | * it under the terms of the GNU General Public License as published by | |
19 | * the Free Software Foundation; either version 2 of the License, or | |
20 | * (at your option) any later version. | |
21 | * | |
22 | * This program is distributed in the hope that it will be useful, | |
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
25 | * GNU General Public License for more details. | |
26 | * | |
27 | * You should have received a copy of the GNU General Public License | |
28 | * along with this program; if not, write to the Free Software | |
29 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
30 | * | |
31 | */ | |
32 | ||
33 | /* | |
34 | * Copyright (c) 1994, 1995. All rights reserved. | |
35 | * | |
36 | * The Harvest software was developed by the Internet Research Task | |
37 | * Force Research Group on Resource Discovery (IRTF-RD): | |
38 | * | |
39 | * Mic Bowman of Transarc Corporation. | |
40 | * Peter Danzig of the University of Southern California. | |
41 | * Darren R. Hardy of the University of Colorado at Boulder. | |
42 | * Udi Manber of the University of Arizona. | |
43 | * Michael F. Schwartz of the University of Colorado at Boulder. | |
44 | * Duane Wessels of the University of Colorado at Boulder. | |
45 | * | |
46 | * This copyright notice applies to software in the Harvest | |
47 | * ``src/'' directory only. Users should consult the individual | |
48 | * copyright notices in the ``components/'' subdirectories for | |
49 | * copyright information about other software bundled with the | |
50 | * Harvest source code distribution. | |
51 | * | |
52 | * TERMS OF USE | |
53 | * | |
54 | * The Harvest software may be used and re-distributed without | |
55 | * charge, provided that the software origin and research team are | |
56 | * cited in any use of the system. Most commonly this is | |
57 | * accomplished by including a link to the Harvest Home Page | |
58 | * (http://harvest.cs.colorado.edu/) from the query page of any | |
59 | * Broker you deploy, as well as in the query result pages. These | |
60 | * links are generated automatically by the standard Broker | |
61 | * software distribution. | |
62 | * | |
63 | * The Harvest software is provided ``as is'', without express or | |
64 | * implied warranty, and with no support nor obligation to assist | |
65 | * in its use, correction, modification or enhancement. We assume | |
66 | * no liability with respect to the infringement of copyrights, | |
67 | * trade secrets, or any patents, and are not responsible for | |
68 | * consequential damages. Proper use of the Harvest software is | |
69 | * entirely the responsibility of the user. | |
70 | * | |
71 | * DERIVATIVE WORKS | |
72 | * | |
73 | * Users may make derivative works from the Harvest software, subject | |
74 | * to the following constraints: | |
75 | * | |
76 | * - You must include the above copyright notice and these | |
77 | * accompanying paragraphs in all forms of derivative works, | |
78 | * and any documentation and other materials related to such | |
79 | * distribution and use acknowledge that the software was | |
80 | * developed at the above institutions. | |
81 | * | |
82 | * - You must notify IRTF-RD regarding your distribution of | |
83 | * the derivative work. | |
84 | * | |
85 | * - You must clearly notify users that your are distributing | |
86 | * a modified version and not the original Harvest software. | |
87 | * | |
88 | * - Any derivative product is also subject to these copyright | |
89 | * and use restrictions. | |
90 | * | |
91 | * Note that the Harvest software is NOT in the public domain. We | |
92 | * retain copyright, as specified above. | |
93 | * | |
94 | * HISTORY OF FREE SOFTWARE STATUS | |
95 | * | |
96 | * Originally we required sites to license the software in cases | |
97 | * where they were going to build commercial products/services | |
98 | * around Harvest. In June 1995 we changed this policy. We now | |
99 | * allow people to use the core Harvest software (the code found in | |
100 | * the Harvest ``src/'' directory) for free. We made this change | |
101 | * in the interest of encouraging the widest possible deployment of | |
102 | * the technology. The Harvest software is really a reference | |
103 | * implementation of a set of protocols and formats, some of which | |
104 | * we intend to standardize. We encourage commercial | |
105 | * re-implementations of code complying to this set of standards. | |
106 | */ | |
090089c4 | 107 | |
44a47c6e | 108 | #include "squid.h" |
090089c4 | 109 | |
110 | #ifndef BUFSIZ | |
111 | #define BUFSIZ 8192 | |
112 | #endif | |
113 | ||
114 | /* Local functions */ | |
899bab3f | 115 | static int client_comm_connect(int, char *, u_short, struct timeval *); |
f5b8bbc4 | 116 | static void usage(const char *progname); |
899bab3f | 117 | static int Now(struct timeval *); |
118 | static SIGHDLR catch; | |
090089c4 | 119 | |
b8d8561b | 120 | static void |
0ee4272b | 121 | usage(const char *progname) |
090089c4 | 122 | { |
0ee4272b | 123 | fprintf(stderr, |
899bab3f | 124 | "Usage: %s [-ars] [-i IMS] [-h host] [-p port] [-m method] [-t count] [-I ping-interval] url\n" |
fe4e214f | 125 | "Options:\n" |
899bab3f | 126 | " -a Do NOT include Accept: header.\n" |
127 | " -r Force cache to reload URL.\n" | |
128 | " -s Silent. Do not print data to stdout.\n" | |
129 | " -i IMS If-Modified-Since time (in Epoch seconds).\n" | |
130 | " -h host Retrieve URL from cache on hostname. Default is localhost.\n" | |
131 | " -p port Port number of cache. Default is %d.\n" | |
132 | " -m method Request method, default is GET.\n" | |
133 | " -t count Trace count cache-hops\n" | |
134 | " -g count Ping mode, \"count\" iterations (0 to loop until interrupted).\n" | |
135 | " -I interval Ping interval in seconds (default 1 second).\n", | |
fe4e214f | 136 | progname, CACHE_HTTP_PORT); |
090089c4 | 137 | exit(1); |
138 | } | |
139 | ||
899bab3f | 140 | static int interrupted = 0; |
b8d8561b | 141 | int |
142 | main(int argc, char *argv[]) | |
090089c4 | 143 | { |
144 | int conn, c, len, bytesWritten; | |
145 | int port, to_stdout, reload; | |
899bab3f | 146 | int ping, pcount; |
599eadbe | 147 | int keep_alive = 0; |
88738790 | 148 | int opt_noaccept = 0; |
090089c4 | 149 | char url[BUFSIZ], msg[BUFSIZ], buf[BUFSIZ], hostname[BUFSIZ]; |
0ee4272b | 150 | const char *method = "GET"; |
090089c4 | 151 | extern char *optarg; |
234967c9 | 152 | time_t ims = 0; |
b3b64e58 | 153 | int max_forwards = -1; |
899bab3f | 154 | struct timeval tv1, tv2; |
155 | int i = 0, loops; | |
156 | long ping_int; | |
157 | long ping_min = 0, ping_max = 0, ping_sum = 0, ping_mean = 0; | |
090089c4 | 158 | |
159 | /* set the defaults */ | |
160 | strcpy(hostname, "localhost"); | |
161 | port = CACHE_HTTP_PORT; | |
162 | to_stdout = 1; | |
163 | reload = 0; | |
899bab3f | 164 | ping = 0; |
165 | pcount = 0; | |
166 | ping_int = 1 * 1000; | |
090089c4 | 167 | |
168 | if (argc < 2) { | |
169 | usage(argv[0]); /* need URL */ | |
170 | } else if (argc >= 2) { | |
171 | strcpy(url, argv[argc - 1]); | |
172 | if (url[0] == '-') | |
173 | usage(argv[0]); | |
899bab3f | 174 | while ((c = getopt(argc, argv, "ah:i:km:p:rst:g:I:?")) != -1) |
090089c4 | 175 | switch (c) { |
88738790 | 176 | case 'a': |
177 | opt_noaccept = 1; | |
178 | break; | |
090089c4 | 179 | case 'h': /* host:arg */ |
090089c4 | 180 | if (optarg != NULL) |
181 | strcpy(hostname, optarg); | |
182 | break; | |
183 | case 's': /* silent */ | |
090089c4 | 184 | to_stdout = 0; |
185 | break; | |
599eadbe | 186 | case 'k': /* backward compat */ |
187 | keep_alive = 1; | |
188 | break; | |
090089c4 | 189 | case 'r': /* reload */ |
190 | reload = 1; | |
191 | break; | |
192 | case 'p': /* port number */ | |
193 | sscanf(optarg, "%d", &port); | |
194 | if (port < 1) | |
195 | port = CACHE_HTTP_PORT; /* default */ | |
196 | break; | |
234967c9 | 197 | case 'i': /* IMS */ |
198 | ims = (time_t) atoi(optarg); | |
199 | break; | |
200 | case 'm': | |
201 | method = xstrdup(optarg); | |
202 | break; | |
b3b64e58 | 203 | case 't': |
204 | method = xstrdup("TRACE"); | |
205 | max_forwards = atoi(optarg); | |
206 | break; | |
899bab3f | 207 | case 'g': |
208 | ping = 1; | |
209 | pcount = atoi(optarg); | |
210 | to_stdout = 0; | |
211 | break; | |
212 | case 'I': | |
213 | if ((ping_int = atoi(optarg) * 1000) <= 0) | |
214 | usage(argv[0]); | |
215 | break; | |
090089c4 | 216 | case '?': /* usage */ |
217 | default: | |
218 | usage(argv[0]); | |
219 | break; | |
220 | } | |
221 | } | |
090089c4 | 222 | /* Build the HTTP request */ |
042461c3 | 223 | snprintf(msg, BUFSIZ, "%s %s HTTP/1.0\r\n", method, url); |
090089c4 | 224 | if (reload) { |
042461c3 | 225 | snprintf(buf, BUFSIZ, "Pragma: no-cache\r\n"); |
234967c9 | 226 | strcat(msg, buf); |
227 | } | |
88738790 | 228 | if (opt_noaccept == 0) { |
042461c3 | 229 | snprintf(buf, BUFSIZ, "Accept: */*\r\n"); |
88738790 | 230 | strcat(msg, buf); |
231 | } | |
234967c9 | 232 | if (ims) { |
042461c3 | 233 | snprintf(buf, BUFSIZ, "If-Modified-Since: %s\r\n", mkrfc1123(ims)); |
234967c9 | 234 | strcat(msg, buf); |
090089c4 | 235 | } |
b3b64e58 | 236 | if (max_forwards > -1) { |
042461c3 | 237 | snprintf(buf, BUFSIZ, "Max-Forwards: %d\r\n", max_forwards); |
b3b64e58 | 238 | strcat(msg, buf); |
239 | } | |
599eadbe | 240 | if (keep_alive) { |
042461c3 | 241 | snprintf(buf, BUFSIZ, "Proxy-Connection: Keep-Alive\r\n"); |
599eadbe | 242 | strcat(msg, buf); |
243 | } | |
042461c3 | 244 | snprintf(buf, BUFSIZ, "\r\n"); |
234967c9 | 245 | strcat(msg, buf); |
090089c4 | 246 | |
899bab3f | 247 | if (ping) { |
248 | #if HAVE_SIGACTION | |
249 | struct sigaction sa, osa; | |
250 | if (sigaction(SIGINT, NULL, &osa) == 0 && osa.sa_handler == SIG_DFL) { | |
251 | sa.sa_handler = catch; | |
252 | sa.sa_flags = 0; | |
253 | sigemptyset(&sa.sa_mask); | |
254 | (void) sigaction(SIGINT, &sa, NULL); | |
255 | } | |
256 | #else | |
257 | void (*osig) (); | |
258 | if ((osig = signal(SIGINT, catch)) != SIG_DFL) | |
259 | (void) signal(SIGINT, osig); | |
260 | #endif | |
261 | } | |
262 | loops = ping ? pcount : 1; | |
263 | for (i = 0; loops == 0 || i < loops; i++) { | |
264 | /* Connect to the server */ | |
265 | if ((conn = socket(PF_INET, SOCK_STREAM, 0)) < 0) { | |
266 | perror("client: socket"); | |
267 | exit(1); | |
268 | } | |
269 | if (client_comm_connect(conn, hostname, port, ping ? &tv1 : NULL) < 0) { | |
270 | if (errno == 0) { | |
271 | fprintf(stderr, "client: ERROR: Cannot connect to %s:%d: Host unknown.\n", hostname, port); | |
272 | } else { | |
273 | char tbuf[BUFSIZ]; | |
2bbd722b | 274 | snprintf(tbuf, BUFSIZ, "client: ERROR: Cannot connect to %s:%d", |
899bab3f | 275 | hostname, port); |
276 | perror(tbuf); | |
277 | } | |
278 | exit(1); | |
279 | } | |
280 | /* Send the HTTP request */ | |
281 | bytesWritten = write(conn, msg, strlen(msg)); | |
282 | if (bytesWritten < 0) { | |
283 | perror("client: ERROR: write"); | |
284 | exit(1); | |
285 | } else if (bytesWritten != strlen(msg)) { | |
286 | fprintf(stderr, "client: ERROR: Cannot send request?: %s\n", msg); | |
287 | exit(1); | |
288 | } | |
289 | /* Read the data */ | |
290 | while ((len = read(conn, buf, sizeof(buf))) > 0) { | |
291 | if (to_stdout) | |
292 | fwrite(buf, len, 1, stdout); | |
293 | } | |
294 | (void) close(conn); /* done with socket */ | |
295 | ||
296 | if (interrupted) | |
297 | break; | |
298 | ||
299 | if (ping) { | |
300 | struct tm *tmp; | |
301 | time_t t2s; | |
302 | long elapsed_msec; | |
303 | ||
304 | (void) Now(&tv2); | |
305 | elapsed_msec = tvSubMsec(tv1, tv2); | |
306 | t2s = tv2.tv_sec; | |
307 | tmp = localtime(&t2s); | |
308 | fprintf(stderr, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs\n", | |
309 | tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, | |
310 | tmp->tm_hour, tmp->tm_min, tmp->tm_sec, i + 1, | |
311 | elapsed_msec / 1000, elapsed_msec % 1000); | |
312 | if (i == 0 || elapsed_msec < ping_min) | |
313 | ping_min = elapsed_msec; | |
314 | if (i == 0 || elapsed_msec > ping_max) | |
315 | ping_max = elapsed_msec; | |
316 | ping_sum += elapsed_msec; | |
317 | /* Delay until next "ping_int" boundary */ | |
318 | if ((loops == 0 || i + 1 < loops) && elapsed_msec < ping_int) { | |
319 | struct timeval tvs; | |
320 | long msec_left = ping_int - elapsed_msec; | |
321 | ||
322 | tvs.tv_sec = msec_left / 1000; | |
323 | tvs.tv_usec = (msec_left % 1000) * 1000; | |
324 | select(0, NULL, NULL, NULL, &tvs); | |
325 | } | |
326 | } | |
090089c4 | 327 | } |
899bab3f | 328 | |
329 | if (ping && i) { | |
330 | ping_mean = ping_sum / i; | |
331 | fprintf(stderr, "%d requests, round-trip (secs) min/avg/max = " | |
332 | "%ld.%03ld/%ld.%03ld/%ld.%03ld\n", i, | |
333 | ping_min / 1000, ping_min % 1000, ping_mean / 1000, ping_mean % 1000, | |
334 | ping_max / 1000, ping_max % 1000); | |
090089c4 | 335 | } |
090089c4 | 336 | exit(0); |
337 | /*NOTREACHED */ | |
983061ed | 338 | return 0; |
090089c4 | 339 | } |
340 | ||
b8d8561b | 341 | static int |
899bab3f | 342 | client_comm_connect(int sock, char *dest_host, u_short dest_port, struct timeval *tvp) |
090089c4 | 343 | { |
899bab3f | 344 | static const struct hostent *hp = NULL; |
090089c4 | 345 | static struct sockaddr_in to_addr; |
346 | ||
347 | /* Set up the destination socket address for message to send to. */ | |
899bab3f | 348 | if (hp == NULL) { |
349 | to_addr.sin_family = AF_INET; | |
090089c4 | 350 | |
899bab3f | 351 | if ((hp = gethostbyname(dest_host)) == 0) { |
352 | return (-1); | |
353 | } | |
354 | xmemcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length); | |
355 | to_addr.sin_port = htons(dest_port); | |
090089c4 | 356 | } |
899bab3f | 357 | if (tvp) |
358 | (void) Now(tvp); | |
090089c4 | 359 | return connect(sock, (struct sockaddr *) &to_addr, sizeof(struct sockaddr_in)); |
360 | } | |
899bab3f | 361 | |
362 | static int | |
363 | Now(struct timeval *tp) | |
364 | { | |
365 | #if GETTIMEOFDAY_NO_TZP | |
366 | return gettimeofday(tp); | |
367 | #else | |
368 | return gettimeofday(tp, NULL); | |
369 | #endif | |
370 | } /* ARGSUSED */ | |
371 | ||
372 | static void | |
373 | catch(int sig) | |
374 | { | |
375 | interrupted = 1; | |
376 | fprintf(stderr, "Interrupted.\n"); | |
377 | } |