]> git.ipfire.org Git - thirdparty/squid.git/blob - tools/squidclient.cc
SourceFormat Enforcement
[thirdparty/squid.git] / tools / squidclient.cc
1 /*
2 * $Id$
3 *
4 * DEBUG: section -- WWW Client
5 * AUTHOR: Harvest Derived
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
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.
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.
23 *
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.
28 *
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
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35 #include "squid.h"
36 #include "base64.h"
37 #include "ip/Address.h"
38 #include "rfc1123.h"
39 #include "SquidTime.h"
40
41 #if _SQUID_WINDOWS_
42 /** \cond AUTODOCS-IGNORE */
43 using namespace Squid;
44 /** \endcond */
45 #endif
46
47 #if _SQUID_WINDOWS_
48 #include <io.h>
49 #endif
50 #if HAVE_STDIO_H
51 #include <stdio.h>
52 #endif
53 #if HAVE_SYS_SOCKET_H
54 #include <sys/socket.h>
55 #endif
56 #if HAVE_STRING_H
57 #include <string.h>
58 #endif
59 #if HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62 #if HAVE_NETDB_H
63 #include <netdb.h>
64 #endif
65 #if HAVE_SIGNAL_H
66 #include <signal.h>
67 #endif
68 #if HAVE_ERRNO_H
69 #include <errno.h>
70 #endif
71 #if HAVE_SYS_STAT_H
72 #include <sys/stat.h>
73 #endif
74 #if HAVE_FCNTL_H
75 #include <fcntl.h>
76 #endif
77 #if HAVE_NETINET_IN_H
78 #include <netinet/in.h>
79 #endif
80 #if HAVE_GETOPT_H
81 #include <getopt.h>
82 #endif
83
84 #if HAVE_GSSAPI
85 #if HAVE_GSSAPI_GSSAPI_H
86 #include <gssapi/gssapi.h>
87 #elif HAVE_GSSAPI_H
88 #include <gssapi.h>
89 #endif /* HAVE_GSSAPI_GSSAPI_H/HAVE_GSSAPI_H */
90 #if !HAVE_HEIMDAL_KERBEROS
91 #if HAVE_GSSAPI_GSSAPI_KRB5_H
92 #include <gssapi/gssapi_krb5.h>
93 #endif
94 #if HAVE_GSSAPI_GSSAPI_GENERIC_H
95 #include <gssapi/gssapi_generic.h>
96 #endif
97 #if HAVE_GSSAPI_GSSAPI_EXT_H
98 #include <gssapi/gssapi_ext.h>
99 #endif
100 #endif
101
102 #ifndef gss_nt_service_name
103 #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
104 #endif
105
106 #ifndef gss_mech_spnego
107 static gss_OID_desc _gss_mech_spnego = {6, (void *) "\x2b\x06\x01\x05\x05\x02"};
108 gss_OID gss_mech_spnego = &_gss_mech_spnego;
109 #endif
110 #endif /* HAVE_GSSAPI */
111
112 #ifndef BUFSIZ
113 #define BUFSIZ 8192
114 #endif
115 #ifndef MESSAGELEN
116 #define MESSAGELEN 65536
117 #endif
118 #ifndef HEADERLEN
119 #define HEADERLEN 65536
120 #endif
121
122 typedef void SIGHDLR(int sig);
123
124 /* Local functions */
125 static int client_comm_bind(int, const Ip::Address &);
126
127 static int client_comm_connect(int, const Ip::Address &, struct timeval *);
128 static void usage(const char *progname);
129
130 static int Now(struct timeval *);
131 SIGHDLR catchSignal;
132 SIGHDLR pipe_handler;
133 static void set_our_signal(void);
134 static ssize_t myread(int fd, void *buf, size_t len);
135 static ssize_t mywrite(int fd, void *buf, size_t len);
136
137 #if HAVE_GSSAPI
138 static int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, const char *function);
139 static char *GSSAPI_token(const char *server);
140 #endif
141
142 static int put_fd;
143 static char *put_file = NULL;
144
145 static struct stat sb;
146 int total_bytes = 0;
147 int io_timeout = 120;
148
149 #if _SQUID_WINDOWS_
150 void
151 Win32SockCleanup(void)
152 {
153 WSACleanup();
154 return;
155 }
156 #endif
157
158 static void
159 usage(const char *progname)
160 {
161 fprintf(stderr,
162 "Version: %s\n"
163 "Usage: %s [-arsv] [-A 'string'] [-g count] [-h remote host] [-H 'string'] [-i IMS] [-I ping-interval] [-j 'Host-header']"
164 "[-k] [-l local-host] [-m method] "
165 #if HAVE_GSSAPI
166 "[-n] [-N] "
167 #endif
168 "[-p port] [-P file] [-t count] [-T timeout] [-u proxy-user] [-U www-user] "
169 "[-V version] [-w proxy-password] [-W www-password] url\n"
170 "\n"
171 "Options:\n"
172 " -a Do NOT include Accept: header.\n"
173 " -A User-Agent: header. Use \"\" to omit.\n"
174 " -g count Ping mode, perform \"count\" iterations (0 to loop until interrupted).\n"
175 " -h host Retrieve URL from cache on hostname. Default is localhost.\n"
176 " -H 'string' Extra headers to send. Use '\\n' for new lines.\n"
177 " -i IMS If-Modified-Since time (in Epoch seconds).\n"
178 " -I interval Ping interval in seconds (default 1 second).\n"
179 " -j hosthdr Host header content\n"
180 " -k Keep the connection active. Default is to do only one request then close.\n"
181 " -l host Specify a local IP address to bind to. Default is none.\n"
182 " -m method Request method, default is GET.\n"
183 #if HAVE_GSSAPI
184 " -n Proxy Negotiate(Kerberos) authentication\n"
185 " -N WWW Negotiate(Kerberos) authentication\n"
186 #endif
187 " -p port Port number of cache. Default is %d.\n"
188 " -P file PUT request. Using the named file\n"
189 " -r Force cache to reload URL.\n"
190 " -s Silent. Do not print data to stdout.\n"
191 " -t count Trace count cache-hops\n"
192 " -T timeout Timeout value (seconds) for read/write operations.\n"
193 " -u user Proxy authentication username\n"
194 " -U user WWW authentication username\n"
195 " -v Verbose. Print outgoing message to stderr.\n"
196 " -V version HTTP Version. Use '-' for HTTP/0.9 omitted case\n"
197 " -w password Proxy authentication password\n"
198 " -W password WWW authentication password\n",
199 VERSION, progname, CACHE_HTTP_PORT);
200 exit(1);
201 }
202
203 static int interrupted = 0;
204 int
205 main(int argc, char *argv[])
206 {
207 int conn, c, len, bytesWritten;
208 int port, to_stdout, reload;
209 int ping, pcount;
210 int keep_alive = 0;
211 int opt_noaccept = 0;
212 bool opt_verbose = false;
213 #if HAVE_GSSAPI
214 int www_neg = 0, proxy_neg = 0;
215 #endif
216 const char *hostname, *localhost;
217 Ip::Address iaddr;
218 char url[BUFSIZ], msg[MESSAGELEN], buf[BUFSIZ];
219 char extra_hdrs[HEADERLEN];
220 const char *method = "GET";
221 extern char *optarg;
222 time_t ims = 0;
223 int max_forwards = -1;
224
225 struct timeval tv1, tv2;
226 int i = 0, loops;
227 long ping_int;
228 long ping_min = 0, ping_max = 0, ping_sum = 0, ping_mean = 0;
229 const char *proxy_user = NULL;
230 const char *proxy_password = NULL;
231 const char *www_user = NULL;
232 const char *www_password = NULL;
233 const char *host = NULL;
234 const char *version = "1.0";
235 const char *useragent = NULL;
236
237 /* set the defaults */
238 hostname = "localhost";
239 localhost = NULL;
240 extra_hdrs[0] = '\0';
241 port = CACHE_HTTP_PORT;
242 to_stdout = 1;
243 reload = 0;
244 ping = 0;
245 pcount = 0;
246 ping_int = 1 * 1000;
247
248 if (argc < 2) {
249 usage(argv[0]); /* need URL */
250 } else if (argc >= 2) {
251 strncpy(url, argv[argc - 1], BUFSIZ);
252 url[BUFSIZ - 1] = '\0';
253
254 if (url[0] == '-')
255 usage(argv[0]);
256 #if HAVE_GSSAPI
257 while ((c = getopt(argc, argv, "aA:h:j:V:l:P:i:km:p:rsvt:g:p:I:H:T:u:U:w:W:nN?")) != -1)
258 #else
259 while ((c = getopt(argc, argv, "aA:h:j:V:l:P:i:km:p:rsvt:g:p:I:H:T:u:U:w:W:?")) != -1)
260 #endif
261 switch (c) {
262
263 case 'a':
264 opt_noaccept = 1;
265 break;
266
267 case 'A':
268 if (optarg != NULL)
269 useragent = optarg;
270 break;
271
272 case 'h': /* remote host */
273 if (optarg != NULL)
274 hostname = optarg;
275 break;
276
277 case 'j':
278 host = optarg;
279 break;
280
281 case 'V':
282 if (optarg != NULL)
283 version = optarg;
284 break;
285
286 case 'l': /* local host */
287 if (optarg != NULL)
288 localhost = optarg;
289 break;
290
291 case 's': /* silent */
292 to_stdout = 0;
293 break;
294
295 case 'k': /* backward compat */
296 keep_alive = 1;
297 break;
298
299 case 'r': /* reload */
300 reload = 1;
301 break;
302
303 case 'p': /* port number */
304 sscanf(optarg, "%d", &port);
305 if (port < 1)
306 port = CACHE_HTTP_PORT; /* default */
307 break;
308
309 case 'P':
310 put_file = xstrdup(optarg);
311 break;
312
313 case 'i': /* IMS */
314 ims = (time_t) atoi(optarg);
315 break;
316
317 case 'm':
318 method = xstrdup(optarg);
319 break;
320
321 case 't':
322 method = xstrdup("TRACE");
323 max_forwards = atoi(optarg);
324 break;
325
326 case 'g':
327 ping = 1;
328 pcount = atoi(optarg);
329 to_stdout = 0;
330 break;
331
332 case 'I':
333 if ((ping_int = atoi(optarg) * 1000) <= 0)
334 usage(argv[0]);
335 break;
336
337 case 'H':
338 if (strlen(optarg)) {
339 char *t;
340 strncpy(extra_hdrs, optarg, sizeof(extra_hdrs));
341 while ((t = strstr(extra_hdrs, "\\n")))
342 *t = '\r', *(t + 1) = '\n';
343 }
344 break;
345
346 case 'T':
347 io_timeout = atoi(optarg);
348 break;
349
350 case 'u':
351 proxy_user = optarg;
352 break;
353
354 case 'w':
355 proxy_password = optarg;
356 break;
357
358 case 'U':
359 www_user = optarg;
360 break;
361
362 case 'W':
363 www_password = optarg;
364 break;
365
366 #if HAVE_GSSAPI
367 case 'n':
368 proxy_neg = 1;
369 break;
370
371 case 'N':
372 www_neg = 1;
373 break;
374 #endif
375 case 'v':
376 /* undocumented: may increase verb-level by giving more -v's */
377 opt_verbose=true;
378 break;
379
380 case '?': /* usage */
381
382 default:
383 usage(argv[0]);
384 break;
385 }
386 }
387 #if _SQUID_WINDOWS_
388 {
389 WSADATA wsaData;
390 WSAStartup(2, &wsaData);
391 atexit(Win32SockCleanup);
392 }
393 #endif
394 /* Build the HTTP request */
395 if (strncmp(url, "mgr:", 4) == 0) {
396 char *t = xstrdup(url + 4);
397 const char *at = NULL;
398 if (!strrchr(t, '@')) { // ignore any -w password if @ is explicit already.
399 at = proxy_password;
400 }
401 // embed the -w proxy password into old-style cachemgr URLs
402 if (at)
403 snprintf(url, BUFSIZ, "cache_object://%s/%s@%s", hostname, t, at);
404 else
405 snprintf(url, BUFSIZ, "cache_object://%s/%s", hostname, t);
406 xfree(t);
407 }
408 if (put_file) {
409 put_fd = open(put_file, O_RDONLY);
410 set_our_signal();
411
412 if (put_fd < 0) {
413 fprintf(stderr, "%s: can't open file (%s)\n", argv[0],
414 xstrerror());
415 exit(-1);
416 }
417 #if _SQUID_WINDOWS_
418 setmode(put_fd, O_BINARY);
419 #endif
420
421 fstat(put_fd, &sb);
422 }
423
424 if (!host) {
425 char *newhost = strstr(url, "://");
426 if (newhost) {
427 char *t;
428 newhost += 3;
429 newhost = xstrdup(newhost);
430 t = newhost + strcspn(newhost, "@/?");
431 if (*t == '@') {
432 newhost = t + 1;
433 t = newhost + strcspn(newhost, "@/?");
434 }
435 *t = '\0';
436 host = newhost;
437 }
438 }
439
440 if (version[0] == '-' || !version[0]) {
441 /* HTTP/0.9, no headers, no version */
442 snprintf(msg, BUFSIZ, "%s %s\r\n", method, url);
443 } else {
444 if (!xisdigit(version[0])) // not HTTP/n.n
445 snprintf(msg, BUFSIZ, "%s %s %s\r\n", method, url, version);
446 else
447 snprintf(msg, BUFSIZ, "%s %s HTTP/%s\r\n", method, url, version);
448
449 if (host) {
450 snprintf(buf, BUFSIZ, "Host: %s\r\n", host);
451 strcat(msg,buf);
452 }
453
454 if (useragent == NULL) {
455 snprintf(buf, BUFSIZ, "User-Agent: squidclient/%s\r\n", VERSION);
456 strcat(msg,buf);
457 } else if (useragent[0] != '\0') {
458 snprintf(buf, BUFSIZ, "User-Agent: %s\r\n", useragent);
459 strcat(msg,buf);
460 }
461
462 if (reload) {
463 snprintf(buf, BUFSIZ, "Cache-Control: no-cache\r\n");
464 strcat(msg, buf);
465 }
466 if (put_fd > 0) {
467 snprintf(buf, BUFSIZ, "Content-length: %" PRId64 "\r\n", (int64_t) sb.st_size);
468 strcat(msg, buf);
469 }
470 if (opt_noaccept == 0) {
471 snprintf(buf, BUFSIZ, "Accept: */*\r\n");
472 strcat(msg, buf);
473 }
474 if (ims) {
475 snprintf(buf, BUFSIZ, "If-Modified-Since: %s\r\n", mkrfc1123(ims));
476 strcat(msg, buf);
477 }
478 if (max_forwards > -1) {
479 snprintf(buf, BUFSIZ, "Max-Forwards: %d\r\n", max_forwards);
480 strcat(msg, buf);
481 }
482 if (proxy_user) {
483 const char *user = proxy_user;
484 const char *password = proxy_password;
485 #if HAVE_GETPASS
486 if (!password)
487 password = getpass("Proxy password: ");
488 #endif
489 if (!password) {
490 fprintf(stderr, "ERROR: Proxy password missing\n");
491 exit(1);
492 }
493 snprintf(buf, BUFSIZ, "%s:%s", user, password);
494 snprintf(buf, BUFSIZ, "Proxy-Authorization: Basic %s\r\n", old_base64_encode(buf));
495 strcat(msg, buf);
496 }
497 if (www_user) {
498 const char *user = www_user;
499 const char *password = www_password;
500 #if HAVE_GETPASS
501 if (!password)
502 password = getpass("WWW password: ");
503 #endif
504 if (!password) {
505 fprintf(stderr, "ERROR: WWW password missing\n");
506 exit(1);
507 }
508 snprintf(buf, BUFSIZ, "%s:%s", user, password);
509 snprintf(buf, BUFSIZ, "Authorization: Basic %s\r\n", old_base64_encode(buf));
510 strcat(msg, buf);
511 }
512 #if HAVE_GSSAPI
513 if (www_neg) {
514 if (host) {
515 snprintf(buf, BUFSIZ, "Authorization: Negotiate %s\r\n", GSSAPI_token(host));
516 strcat(msg, buf);
517 } else
518 fprintf(stderr, "ERROR: server host missing\n");
519 }
520 if (proxy_neg) {
521 if (hostname) {
522 snprintf(buf, BUFSIZ, "Proxy-Authorization: Negotiate %s\r\n", GSSAPI_token(hostname));
523 strcat(msg, buf);
524 } else
525 fprintf(stderr, "ERROR: proxy server host missing\n");
526 }
527 #endif
528
529 /* HTTP/1.0 may need keep-alive explicitly */
530 if (strcmp(version, "1.0") == 0 && keep_alive)
531 strcat(msg, "Connection: keep-alive\r\n");
532
533 /* HTTP/1.1 may need close explicitly */
534 if (!keep_alive)
535 strcat(msg, "Connection: close\r\n");
536
537 strcat(msg, extra_hdrs);
538 strcat(msg, "\r\n");
539 }
540
541 if (opt_verbose)
542 fprintf(stderr, "Request:'%s'\n", msg);
543
544 if (ping) {
545 #if HAVE_SIGACTION
546
547 struct sigaction sa, osa;
548
549 if (sigaction(SIGINT, NULL, &osa) == 0 && osa.sa_handler == SIG_DFL) {
550 sa.sa_handler = catchSignal;
551 sa.sa_flags = 0;
552 sigemptyset(&sa.sa_mask);
553 (void) sigaction(SIGINT, &sa, NULL);
554 }
555 #else
556 void (*osig) (int);
557
558 if ((osig = signal(SIGINT, catchSignal)) != SIG_DFL)
559 (void) signal(SIGINT, osig);
560
561 #endif
562
563 }
564 loops = ping ? pcount : 1;
565
566 for (i = 0; loops == 0 || i < loops; ++i) {
567 int fsize = 0;
568 struct addrinfo *AI = NULL;
569
570 if (opt_verbose)
571 fprintf(stderr, "Resolving... %s\n", hostname);
572
573 /* Connect to the server */
574
575 if (localhost) {
576 if ( !iaddr.GetHostByName(localhost) ) {
577 fprintf(stderr, "client: ERROR: Cannot resolve %s: Host unknown.\n", localhost);
578 exit(1);
579 }
580 } else {
581 /* Process the remote host name to locate the Protocol required
582 in case we are being asked to link to another version of squid */
583 if ( !iaddr.GetHostByName(hostname) ) {
584 fprintf(stderr, "client: ERROR: Cannot resolve %s: Host unknown.\n", hostname);
585 exit(1);
586 }
587 }
588
589 iaddr.GetAddrInfo(AI);
590 if ((conn = socket(AI->ai_family, AI->ai_socktype, 0)) < 0) {
591 perror("client: socket");
592 iaddr.FreeAddrInfo(AI);
593 exit(1);
594 }
595 iaddr.FreeAddrInfo(AI);
596
597 if (localhost && client_comm_bind(conn, iaddr) < 0) {
598 perror("client: bind");
599 exit(1);
600 }
601
602 iaddr.SetEmpty();
603 if ( !iaddr.GetHostByName(hostname) ) {
604 fprintf(stderr, "client: ERROR: Cannot resolve %s: Host unknown.\n", hostname);
605 exit(1);
606 }
607
608 iaddr.SetPort(port);
609
610 if (opt_verbose) {
611 char ipbuf[MAX_IPSTRLEN];
612 fprintf(stderr, "Connecting... %s(%s)\n", hostname, iaddr.NtoA(ipbuf, MAX_IPSTRLEN));
613 }
614
615 if (client_comm_connect(conn, iaddr, ping ? &tv1 : NULL) < 0) {
616 char hostnameBuf[MAX_IPSTRLEN];
617 iaddr.ToURL(hostnameBuf, MAX_IPSTRLEN);
618 if (errno == 0) {
619 fprintf(stderr, "client: ERROR: Cannot connect to %s: Host unknown.\n", hostnameBuf);
620 } else {
621 char tbuf[BUFSIZ];
622 snprintf(tbuf, BUFSIZ, "client: ERROR: Cannot connect to %s", hostnameBuf);
623 perror(tbuf);
624 }
625 exit(1);
626 }
627 if (opt_verbose) {
628 char ipbuf[MAX_IPSTRLEN];
629 fprintf(stderr, "Connected to: %s (%s)\n", hostname, iaddr.NtoA(ipbuf, MAX_IPSTRLEN));
630 }
631
632 /* Send the HTTP request */
633 bytesWritten = mywrite(conn, msg, strlen(msg));
634
635 if (bytesWritten < 0) {
636 perror("client: ERROR: write");
637 exit(1);
638 } else if ((unsigned) bytesWritten != strlen(msg)) {
639 fprintf(stderr, "client: ERROR: Cannot send request?: %s\n", msg);
640 exit(1);
641 }
642
643 if (put_file) {
644 int x;
645 lseek(put_fd, 0, SEEK_SET);
646 while ((x = read(put_fd, buf, sizeof(buf))) > 0) {
647
648 x = mywrite(conn, buf, x);
649
650 total_bytes += x;
651
652 if (x <= 0)
653 break;
654 }
655
656 if (x != 0)
657 fprintf(stderr, "client: ERROR: Cannot send file.\n");
658 }
659 /* Read the data */
660
661 #if _SQUID_WINDOWS_
662 setmode(1, O_BINARY);
663 #endif
664
665 while ((len = myread(conn, buf, sizeof(buf))) > 0) {
666 fsize += len;
667
668 if (to_stdout && fwrite(buf, len, 1, stdout) != 1)
669 perror("client: ERROR writing to stdout");
670 }
671
672 #if _SQUID_WINDOWS_
673 setmode(1, O_TEXT);
674 #endif
675
676 (void) close(conn); /* done with socket */
677
678 if (interrupted)
679 break;
680
681 if (ping) {
682
683 struct tm *tmp;
684 time_t t2s;
685 long elapsed_msec;
686
687 (void) Now(&tv2);
688 elapsed_msec = tvSubMsec(tv1, tv2);
689 t2s = tv2.tv_sec;
690 tmp = localtime(&t2s);
691 fprintf(stderr, "%d-%02d-%02d %02d:%02d:%02d [%d]: %ld.%03ld secs, %f KB/s\n",
692 tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
693 tmp->tm_hour, tmp->tm_min, tmp->tm_sec, i + 1,
694 elapsed_msec / 1000, elapsed_msec % 1000,
695 elapsed_msec ? (double) fsize / elapsed_msec : -1.0);
696
697 if (i == 0 || elapsed_msec < ping_min)
698 ping_min = elapsed_msec;
699
700 if (i == 0 || elapsed_msec > ping_max)
701 ping_max = elapsed_msec;
702
703 ping_sum += elapsed_msec;
704
705 /* Delay until next "ping_int" boundary */
706 if ((loops == 0 || i + 1 < loops) && elapsed_msec < ping_int) {
707
708 struct timeval tvs;
709 long msec_left = ping_int - elapsed_msec;
710
711 tvs.tv_sec = msec_left / 1000;
712 tvs.tv_usec = (msec_left % 1000) * 1000;
713 select(0, NULL, NULL, NULL, &tvs);
714 }
715 }
716 }
717
718 if (ping && i) {
719 ping_mean = ping_sum / i;
720 fprintf(stderr, "%d requests, round-trip (secs) min/avg/max = "
721 "%ld.%03ld/%ld.%03ld/%ld.%03ld\n", i,
722 ping_min / 1000, ping_min % 1000, ping_mean / 1000, ping_mean % 1000,
723 ping_max / 1000, ping_max % 1000);
724 }
725 exit(0);
726 /*NOTREACHED */
727 return 0;
728 }
729
730 static int
731 client_comm_bind(int sock, const Ip::Address &addr)
732 {
733
734 int res;
735
736 static struct addrinfo *AI = NULL;
737
738 /* Set up the source socket address from which to send. */
739
740 addr.GetAddrInfo(AI);
741
742 res = bind(sock, AI->ai_addr, AI->ai_addrlen);
743
744 addr.FreeAddrInfo(AI);
745
746 return res;
747 }
748
749 static int
750 client_comm_connect(int sock, const Ip::Address &addr, struct timeval *tvp)
751 {
752 int res;
753 static struct addrinfo *AI = NULL;
754
755 /* Set up the destination socket address for message to send to. */
756
757 addr.GetAddrInfo(AI);
758
759 res = connect(sock, AI->ai_addr, AI->ai_addrlen);
760
761 addr.FreeAddrInfo(AI);
762
763 if (tvp)
764 (void) Now(tvp);
765
766 return res;
767 }
768
769 static int
770 Now(struct timeval *tp)
771 {
772 #if GETTIMEOFDAY_NO_TZP
773 return gettimeofday(tp);
774 #else
775
776 return gettimeofday(tp, NULL);
777 #endif
778 } /* ARGSUSED */
779
780 void
781 catchSignal(int sig)
782 {
783 interrupted = 1;
784 fprintf(stderr, "Interrupted.\n");
785 }
786
787 void
788 pipe_handler(int sig)
789 {
790 fprintf(stderr, "SIGPIPE received.\n");
791 }
792
793 static void
794 set_our_signal(void)
795 {
796 #if HAVE_SIGACTION
797
798 struct sigaction sa;
799 sa.sa_handler = pipe_handler;
800 sa.sa_flags = SA_RESTART;
801 sigemptyset(&sa.sa_mask);
802
803 if (sigaction(SIGPIPE, &sa, NULL) < 0) {
804 fprintf(stderr, "Cannot set PIPE signal.\n");
805 exit(-1);
806 }
807 #else
808 signal(SIGPIPE, pipe_handler);
809
810 #endif
811
812 }
813
814 static ssize_t
815 myread(int fd, void *buf, size_t len)
816 {
817 #if _SQUID_WINDOWS_
818 return recv(fd, buf, len, 0);
819 #else
820 alarm(io_timeout);
821 return read(fd, buf, len);
822 #endif
823 }
824
825 static ssize_t
826 mywrite(int fd, void *buf, size_t len)
827 {
828 #if _SQUID_WINDOWS_
829 return send(fd, buf, len, 0);
830 #else
831 alarm(io_timeout);
832 return write(fd, buf, len);
833 #endif
834 }
835
836 #if HAVE_GSSAPI
837 /*
838 * Check return valuse major_status, minor_status for error and print error description
839 * in case of an error.
840 * Returns 1 in case of gssapi error
841 * 0 in case of no gssapi error
842 */
843 #define BUFFER_SIZE 8192
844 static int
845 check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, const char *function)
846 {
847 if (GSS_ERROR(major_status)) {
848 OM_uint32 maj_stat, min_stat;
849 OM_uint32 msg_ctx = 0;
850 gss_buffer_desc status_string;
851 char buf[BUFFER_SIZE];
852 size_t len;
853
854 len = 0;
855 msg_ctx = 0;
856 while (!msg_ctx) {
857 /* convert major status code (GSS-API error) to text */
858 maj_stat = gss_display_status(&min_stat, major_status,
859 GSS_C_GSS_CODE,
860 GSS_C_NULL_OID,
861 &msg_ctx, &status_string);
862 if (maj_stat == GSS_S_COMPLETE) {
863 snprintf(buf + len, BUFFER_SIZE-len, "%s", (char *) status_string.value);
864 len += status_string.length;
865 gss_release_buffer(&min_stat, &status_string);
866 break;
867 }
868 gss_release_buffer(&min_stat, &status_string);
869 }
870 snprintf(buf + len, BUFFER_SIZE-len, "%s", ". ");
871 len += 2;
872 msg_ctx = 0;
873 while (!msg_ctx) {
874 /* convert minor status code (underlying routine error) to text */
875 maj_stat = gss_display_status(&min_stat, minor_status,
876 GSS_C_MECH_CODE,
877 GSS_C_NULL_OID,
878 &msg_ctx, &status_string);
879 if (maj_stat == GSS_S_COMPLETE) {
880 snprintf(buf + len, BUFFER_SIZE-len,"%s", (char *) status_string.value);
881 len += status_string.length;
882 gss_release_buffer(&min_stat, &status_string);
883 break;
884 }
885 gss_release_buffer(&min_stat, &status_string);
886 }
887 fprintf(stderr, "%s failed: %s\n", function, buf);
888 return (1);
889 }
890 return (0);
891 }
892
893 /*
894 * Get gssapi token for service HTTP/<server>
895 * User has to initiate a kinit user@DOMAIN on commandline first for the
896 * function to be successful
897 * Returns base64 encoded token if successful
898 * string "ERROR" if unsuccessful
899 */
900 static char *
901 GSSAPI_token(const char *server)
902 {
903 OM_uint32 major_status, minor_status;
904 gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
905 gss_name_t server_name = GSS_C_NO_NAME;
906 gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
907 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
908 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
909 char *token = NULL;
910
911 setbuf(stdout, NULL);
912 setbuf(stdin, NULL);
913
914 if (!server) {
915 fprintf(stderr, "Error: No server name\n");
916 return (char *)"ERROR";
917 }
918 service.value = xmalloc(strlen("HTTP") + strlen(server) + 2);
919 snprintf((char *) service.value, strlen("HTTP") + strlen(server) + 2, "%s@%s", "HTTP", server);
920 service.length = strlen((char *) service.value);
921
922 major_status = gss_import_name(&minor_status, &service,
923 gss_nt_service_name, &server_name);
924
925 if (!check_gss_err(major_status, minor_status, "gss_import_name()")) {
926
927 major_status = gss_init_sec_context(&minor_status,
928 GSS_C_NO_CREDENTIAL,
929 &gss_context,
930 server_name,
931 gss_mech_spnego,
932 0,
933 0,
934 GSS_C_NO_CHANNEL_BINDINGS,
935 &input_token,
936 NULL,
937 &output_token,
938 NULL,
939 NULL);
940
941 if (!check_gss_err(major_status, minor_status, "gss_init_sec_context()")) {
942
943 if (output_token.length)
944 token = (char *) base64_encode_bin((const char *) output_token.value, output_token.length);
945 }
946 }
947
948 if (!output_token.length)
949 token = (char *) "ERROR";
950 gss_delete_sec_context(&minor_status, &gss_context, NULL);
951 gss_release_buffer(&minor_status, &service);
952 gss_release_buffer(&minor_status, &input_token);
953 gss_release_buffer(&minor_status, &output_token);
954 gss_release_name(&minor_status, &server_name);
955
956 return token;
957 }
958 #endif