]> git.ipfire.org Git - thirdparty/squid.git/blame - tools/squidclient/squidclient.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / tools / squidclient / squidclient.cc
CommitLineData
30a4f2a8 1/*
f70aedc4 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
e25c139f 3 *
5f623035
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
30a4f2a8 7 */
090089c4 8
f7f3304a 9#include "squid.h"
25f98340 10#include "base64.h"
055421ee 11#include "ip/Address.h"
0ced8e5d 12#include "ip/tools.h"
25f98340 13#include "rfc1123.h"
b2050d4d 14#include "tools/squidclient/gssapi_support.h"
842cd45a
AJ
15#include "tools/squidclient/Parameters.h"
16#include "tools/squidclient/Ping.h"
b4f805f6 17#include "tools/squidclient/Transport.h"
94ab55b0 18
0e25b470 19#if _SQUID_WINDOWS_
63be0a78 20/** \cond AUTODOCS-IGNORE */
15443eec 21using namespace Squid;
63be0a78 22/** \endcond */
15443eec 23#endif
24
3f9f5878 25#include <cassert>
074d6a40 26#include <cerrno>
b38767c7 27#include <csignal>
074d6a40 28#include <cstring>
cf6e492b 29#include <iostream>
4b19fa9e 30#include <sstream>
be266cb2 31#if _SQUID_WINDOWS_
b55fa77d 32#include <io.h>
33#endif
815f9118 34#if HAVE_SYS_SOCKET_H
94ab55b0 35#include <sys/socket.h>
815f9118 36#endif
815f9118 37#if HAVE_UNISTD_H
94ab55b0 38#include <unistd.h>
815f9118 39#endif
489520a9 40#if HAVE_NETDB_H
94ab55b0 41#include <netdb.h>
815f9118 42#endif
815f9118 43#if HAVE_SYS_STAT_H
94ab55b0 44#include <sys/stat.h>
815f9118 45#endif
46#if HAVE_FCNTL_H
94ab55b0 47#include <fcntl.h>
815f9118 48#endif
49#if HAVE_NETINET_IN_H
c7f83c7a 50#include <netinet/in.h>
815f9118 51#endif
d3e3ff4f 52#if HAVE_GETOPT_H
53#include <getopt.h>
54#endif
94ab55b0 55
090089c4 56#ifndef BUFSIZ
f53969cc 57#define BUFSIZ 8192
7ed62376 58#endif
090089c4 59
60/* Local functions */
f5b8bbc4 61static void usage(const char *progname);
62e76326 62
b38767c7 63void pipe_handler(int sig);
d6d09e02 64static void set_our_signal(void);
823d23e4 65
842cd45a
AJ
66Parameters scParams;
67
cca89eeb 68static int put_fd;
69static char *put_file = NULL;
62e76326 70
b6c6bcef 71static struct stat sb;
72int total_bytes = 0;
090089c4 73
3dc72a57
AJ
74#if _SQUID_AIX_
75/* Bug 3854: AIX 6.1 tries to link in this fde.h global symbol
76 * despite squidclient not using any of the fd_* code.
77 */
78fde *fde::Table = NULL;
79#endif
80
0e25b470 81#if _SQUID_WINDOWS_
ec556193
GS
82void
83Win32SockCleanup(void)
84{
85 WSACleanup();
86 return;
87}
1191b93b 88#endif
ec556193 89
b8d8561b 90static void
0ee4272b 91usage(const char *progname)
090089c4 92{
cf6e492b 93 std::cerr << "Version: " << VERSION << std::endl
842cd45a 94 << "Usage: " << progname << " [Basic Options] [HTTP Options]" << std::endl
b4f805f6
AJ
95 << std::endl;
96 std::cerr
f53969cc
SM
97 << " -s | --quiet Silent. Do not print response message to stdout." << std::endl
98 << " -v | --verbose Verbose debugging. Repeat (-vv) to increase output level." << std::endl
99 << " Levels:" << std::endl
100 << " 1 - Print outgoing request message to stderr." << std::endl
101 << " 2 - Print action trace to stderr." << std::endl
102 << " --help Display this help text." << std::endl
103 << std::endl;
b4f805f6 104 Transport::Config.usage();
842cd45a
AJ
105 Ping::Config.usage();
106 std::cerr
f53969cc
SM
107 << "HTTP Options:" << std::endl
108 << " -a Do NOT include Accept: header." << std::endl
109 << " -A User-Agent: header. Use \"\" to omit." << std::endl
8798e209 110 << " -H 'string' Extra headers to send. Supports '\\\\', '\\n', '\\r' and '\\t'." << std::endl
f53969cc
SM
111 << " -i IMS If-Modified-Since time (in Epoch seconds)." << std::endl
112 << " -j hosthdr Host header content" << std::endl
113 << " -k Keep the connection active. Default is to do only one request then close." << std::endl
114 << " -m method Request method, default is GET." << std::endl
823d23e4 115#if HAVE_GSSAPI
f53969cc
SM
116 << " -n Proxy Negotiate(Kerberos) authentication" << std::endl
117 << " -N WWW Negotiate(Kerberos) authentication" << std::endl
842cd45a 118#endif
f53969cc
SM
119 << " -P file Send content from the named file as request payload" << std::endl
120 << " -r Force cache to reload URL" << std::endl
121 << " -t count Trace count cache-hops" << std::endl
122 << " -u user Proxy authentication username" << std::endl
123 << " -U user WWW authentication username" << std::endl
124 << " -V version HTTP Version. Use '-' for HTTP/0.9 omitted case" << std::endl
125 << " -w password Proxy authentication password" << std::endl
126 << " -W password WWW authentication password" << std::endl
127 ;
24885773 128 exit(EXIT_FAILURE);
090089c4 129}
130
8798e209
AJ
131static void
132shellUnescape(char *buf)
133{
134 if (!buf)
135 return;
136
137 unsigned char *p, *d;
138
139 d = p = reinterpret_cast<unsigned char *>(buf);
140
141 while (auto ch = *p) {
142
143 if (ch == '\\') {
144 ++p;
145
146 switch (*p) {
147 case 'n':
148 ch = '\n';
149 break;
150 case 'r':
151 ch = '\r';
152 break;
153 case 't':
154 ch = '\t';
155 break;
156 case '\\':
157 ch = '\\';
158 break;
159 default:
160 ch = *p;
161 debugVerbose(1, "Warning: unsupported shell code '\\" << ch << "'");
162 break;
163 }
164
165 *d = ch;
166
167 if (!ch)
168 continue;
169
170 } else {
171 *d = *p;
172 }
173
174 ++p;
175 ++d;
176 }
177
178 *d = '\0';
179}
180
3f9f5878
AR
181/// [Proxy-]Authorization header producer
182class Authorization
183{
184public:
185 Authorization(const char *aHeader, const char *aDestination):
186 header(aHeader), destination(aDestination) {}
187
188 /// finalizes and writes the right HTTP header to the given stream
189 void commit(std::ostream &os);
190
191 std::string header; ///< HTTP header name to send
192 std::string destination; ///< used when describing password
193 const char *user = nullptr; ///< user name to encode and send
194 const char *password = nullptr; ///< user password to encode and send
195};
196
197void
198Authorization::commit(std::ostream &os)
199{
200#if HAVE_GETPASS
201 if (!password)
202 password = getpass((destination + " password: ").c_str());
203#endif
204 if (!password) {
205 std::cerr << "ERROR: " << destination << " password missing\n";
206 exit(EXIT_FAILURE);
207 }
208
209 struct base64_encode_ctx ctx;
210 base64_encode_init(&ctx);
211 const auto bcapacity = base64_encode_len(strlen(user) + 1 + strlen(password));
212 const auto buf = new char[bcapacity];
213
214 size_t bsize = 0;
215 bsize += base64_encode_update(&ctx, buf, strlen(user), reinterpret_cast<const uint8_t*>(user));
216 bsize += base64_encode_update(&ctx, buf+bsize, 1, reinterpret_cast<const uint8_t*>(":"));
217 bsize += base64_encode_update(&ctx, buf+bsize, strlen(password), reinterpret_cast<const uint8_t*>(password));
218 bsize += base64_encode_final(&ctx, buf+bsize);
219 assert(bsize <= bcapacity); // paranoid and late but better than nothing
220
221 os << header << ": Basic ";
222 os.write(buf, bsize);
223 os << "\r\n";
224
225 delete[] buf;
226}
227
228static Authorization ProxyAuthorization("Proxy-Authorization", "proxy");
229static Authorization OriginAuthorization("Authorization", "origin server");
230
b8d8561b 231int
232main(int argc, char *argv[])
090089c4 233{
b4f805f6 234 int len, bytesWritten;
2f399d29 235 bool to_stdout, reload;
599eadbe 236 int keep_alive = 0;
88738790 237 int opt_noaccept = 0;
14b85b48
DK
238#if HAVE_GSSAPI
239 int www_neg = 0, proxy_neg = 0;
240#endif
4b19fa9e
AJ
241 char url[BUFSIZ];
242 char buf[BUFSIZ];
243 char *extra_hdrs = nullptr;
0ee4272b 244 const char *method = "GET";
090089c4 245 extern char *optarg;
234967c9 246 time_t ims = 0;
b3b64e58 247 int max_forwards = -1;
62e76326 248
5ac5029d
AJ
249 const char *host = NULL;
250 const char *version = "1.0";
ba7ce724 251 const char *useragent = NULL;
090089c4 252
253 /* set the defaults */
2f399d29
AJ
254 to_stdout = true;
255 reload = false;
090089c4 256
0ced8e5d 257 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
dc9d555d 258 if (argc < 2 || argv[argc-1][0] == '-') {
f53969cc 259 usage(argv[0]); /* need URL */
090089c4 260 } else if (argc >= 2) {
4b19fa9e
AJ
261 strncpy(url, argv[argc - 1], sizeof(url));
262 url[sizeof(url) - 1] = '\0';
62e76326 263
dc9d555d 264 int optIndex = 0;
d8c201b7 265 const char *shortOpStr = "aA:h:j:V:l:P:i:km:nNp:rsvt:H:T:u:U:w:W:?";
dc9d555d
AJ
266
267 // options for controlling squidclient
842cd45a
AJ
268 static struct option basicOptions[] = {
269 /* These are the generic options for squidclient itself */
270 {"help", no_argument, 0, '?'},
271 {"verbose", no_argument, 0, 'v'},
272 {"quiet", no_argument, 0, 's'},
b4f805f6
AJ
273 {"host", required_argument, 0, 'h'},
274 {"local", required_argument, 0, 'l'},
275 {"port", required_argument, 0, 'p'},
842cd45a 276 {"ping", no_argument, 0, '\1'},
9958ebee 277 {"https", no_argument, 0, '\3'},
842cd45a 278 {0, 0, 0, 0}
dc9d555d
AJ
279 };
280
281 int c;
282 while ((c = getopt_long(argc, argv, shortOpStr, basicOptions, &optIndex)) != -1) {
842cd45a
AJ
283
284 // modules parse their own specific options
3afd7aae 285 switch (c) {
842cd45a
AJ
286 case '\1':
287 to_stdout = 0;
b4f805f6
AJ
288 Ping::Config.parseCommandOpts(argc, argv, c, optIndex);
289 continue;
290
f53969cc
SM
291 case 'h': /* remote host */
292 case 'l': /* local host */
293 case 'p': /* port number */
b4f805f6
AJ
294 // rewind and let the Transport::Config parser handle
295 optind -= 2;
296
297 case '\3': // request over a TLS connection
298 Transport::Config.parseCommandOpts(argc, argv, c, optIndex);
299 continue;
842cd45a
AJ
300
301 default: // fall through to next switch
302 break;
303 }
304
305 switch (c) {
306
307 case '\0': // dummy value for end-of-options
308 break;
62e76326 309
3afd7aae
AJ
310 case 'a':
311 opt_noaccept = 1;
312 break;
62e76326 313
ba7ce724 314 case 'A':
be05c185 315 useragent = optarg;
ba7ce724
AJ
316 break;
317
5ac5029d 318 case 'j':
af6a12ee
AJ
319 host = optarg;
320 break;
5ac5029d
AJ
321
322 case 'V':
be05c185 323 version = optarg;
3afd7aae 324 break;
62e76326 325
f53969cc 326 case 's': /* silent */
2f399d29 327 to_stdout = false;
3afd7aae 328 break;
62e76326 329
f53969cc 330 case 'k': /* backward compat */
3afd7aae 331 keep_alive = 1;
3afd7aae 332 break;
62e76326 333
f53969cc 334 case 'r': /* reload */
2f399d29 335 reload = true;
3afd7aae 336 break;
62e76326 337
3afd7aae
AJ
338 case 'P':
339 put_file = xstrdup(optarg);
3afd7aae 340 break;
62e76326 341
f53969cc 342 case 'i': /* IMS */
3afd7aae 343 ims = (time_t) atoi(optarg);
3afd7aae 344 break;
62e76326 345
3afd7aae
AJ
346 case 'm':
347 method = xstrdup(optarg);
3afd7aae 348 break;
62e76326 349
3afd7aae
AJ
350 case 't':
351 method = xstrdup("TRACE");
3afd7aae 352 max_forwards = atoi(optarg);
3afd7aae 353 break;
62e76326 354
3afd7aae
AJ
355 case 'H':
356 if (strlen(optarg)) {
4b19fa9e
AJ
357 if (extra_hdrs) {
358 std::cerr << "ERROR: multiple -H options not supported. Discarding previous value." << std::endl;
359 xfree(extra_hdrs);
360 }
361 extra_hdrs = xstrdup(optarg);
8798e209 362 shellUnescape(extra_hdrs);
3afd7aae
AJ
363 }
364 break;
62e76326 365
3afd7aae 366 case 'T':
b4f805f6 367 Transport::Config.ioTimeout = atoi(optarg);
3afd7aae 368 break;
62e76326 369
3afd7aae 370 case 'u':
3f9f5878 371 ProxyAuthorization.user = optarg;
3afd7aae 372 break;
62e76326 373
3afd7aae 374 case 'w':
3f9f5878 375 ProxyAuthorization.password = optarg;
3afd7aae 376 break;
62e76326 377
3afd7aae 378 case 'U':
3f9f5878 379 OriginAuthorization.user = optarg;
3afd7aae 380 break;
62e76326 381
3afd7aae 382 case 'W':
3f9f5878 383 OriginAuthorization.password = optarg;
3afd7aae 384 break;
62e76326 385
823d23e4 386 case 'n':
dc9d555d 387#if HAVE_GSSAPI
823d23e4 388 proxy_neg = 1;
dc9d555d
AJ
389#else
390 std::cerr << "ERROR: Negotiate authentication not supported." << std::endl;
391 usage(argv[0]);
392#endif
823d23e4
AJ
393 break;
394
395 case 'N':
dc9d555d 396#if HAVE_GSSAPI
823d23e4 397 www_neg = 1;
dc9d555d
AJ
398#else
399 std::cerr << "ERROR: Negotiate authentication not supported." << std::endl;
400 usage(argv[0]);
823d23e4 401#endif
dc9d555d
AJ
402 break;
403
3afd7aae
AJ
404 case 'v':
405 /* undocumented: may increase verb-level by giving more -v's */
842cd45a
AJ
406 ++scParams.verbosityLevel;
407 debugVerbose(2, "verbosity level set to " << scParams.verbosityLevel);
3afd7aae 408 break;
62e76326 409
f53969cc 410 case '?': /* usage */
62e76326 411
3afd7aae
AJ
412 default:
413 usage(argv[0]);
414 break;
415 }
dc9d555d 416 }
090089c4 417 }
0e25b470 418#if _SQUID_WINDOWS_
0ef0f1de 419 {
3afd7aae
AJ
420 WSADATA wsaData;
421 WSAStartup(2, &wsaData);
422 atexit(Win32SockCleanup);
0ef0f1de 423 }
424#endif
090089c4 425 /* Build the HTTP request */
8a9b6b94 426 if (strncmp(url, "mgr:", 4) == 0) {
3afd7aae 427 char *t = xstrdup(url + 4);
3f3e5473
AJ
428 const char *at = NULL;
429 if (!strrchr(t, '@')) { // ignore any -w password if @ is explicit already.
3f9f5878 430 at = ProxyAuthorization.password;
3f3e5473
AJ
431 }
432 // embed the -w proxy password into old-style cachemgr URLs
433 if (at)
4b19fa9e 434 snprintf(url, sizeof(url), "cache_object://%s/%s@%s", Transport::Config.hostname, t, at);
3f3e5473 435 else
4b19fa9e 436 snprintf(url, sizeof(url), "cache_object://%s/%s", Transport::Config.hostname, t);
3afd7aae 437 xfree(t);
8a9b6b94 438 }
cca89eeb 439 if (put_file) {
3afd7aae
AJ
440 put_fd = open(put_file, O_RDONLY);
441 set_our_signal();
442
443 if (put_fd < 0) {
b69e9ffa
AJ
444 int xerrno = errno;
445 std::cerr << "ERROR: can't open file (" << xstrerr(xerrno) << ")" << std::endl;
24885773 446 exit(EXIT_FAILURE);
3afd7aae 447 }
be266cb2 448#if _SQUID_WINDOWS_
3afd7aae 449 setmode(put_fd, O_BINARY);
c4aefe96 450#endif
62e76326 451
be05c185 452 if (fstat(put_fd, &sb) < 0) {
b69e9ffa
AJ
453 int xerrno = errno;
454 std::cerr << "ERROR: can't identify length of file (" << xstrerr(xerrno) << ")" << std::endl;
be05c185 455 }
cca89eeb 456 }
5ac5029d
AJ
457
458 if (!host) {
af6a12ee
AJ
459 char *newhost = strstr(url, "://");
460 if (newhost) {
461 char *t;
462 newhost += 3;
dc47f531 463 newhost = xstrdup(newhost);
af6a12ee
AJ
464 t = newhost + strcspn(newhost, "@/?");
465 if (*t == '@') {
466 newhost = t + 1;
467 t = newhost + strcspn(newhost, "@/?");
468 }
469 *t = '\0';
470 host = newhost;
471 }
5ac5029d
AJ
472 }
473
4b19fa9e
AJ
474 std::stringstream msg;
475
8d55d7ef 476 if (version[0] == '-' || !version[0]) {
af6a12ee 477 /* HTTP/0.9, no headers, no version */
4b19fa9e 478 msg << method << " " << url << "\r\n";
5ac5029d 479 } else {
4b19fa9e
AJ
480 const auto versionImpliesHttp = xisdigit(version[0]); // is HTTP/n.n
481 msg << method << " "
482 << url << " "
483 << (versionImpliesHttp ? "HTTP/" : "") << version
484 << "\r\n";
62e76326 485
af6a12ee 486 if (host) {
4b19fa9e 487 msg << "Host: " << host << "\r\n";
af6a12ee
AJ
488 }
489
4b19fa9e
AJ
490 if (!useragent) {
491 msg << "User-Agent: squidclient/" << VERSION << "\r\n";
ba7ce724 492 } else if (useragent[0] != '\0') {
4b19fa9e
AJ
493 msg << "User-Agent: " << useragent << "\r\n";
494 } // else custom: no value U-A header
ba7ce724 495
af6a12ee 496 if (reload) {
4b19fa9e 497 msg << "Cache-Control: no-cache\r\n";
af6a12ee
AJ
498 }
499 if (put_fd > 0) {
4b19fa9e 500 msg << "Content-length: " << sb.st_size << "\r\n";
af6a12ee
AJ
501 }
502 if (opt_noaccept == 0) {
4b19fa9e 503 msg << "Accept: */*\r\n";
af6a12ee
AJ
504 }
505 if (ims) {
4b19fa9e 506 msg << "If-Modified-Since: " << mkrfc1123(ims) << "\r\n";
af6a12ee
AJ
507 }
508 if (max_forwards > -1) {
4b19fa9e 509 msg << "Max-Forwards: " << max_forwards << "\r\n";
af6a12ee 510 }
3f9f5878
AR
511 if (ProxyAuthorization.user)
512 ProxyAuthorization.commit(msg);
513 if (OriginAuthorization.user)
514 OriginAuthorization.commit(msg);
823d23e4
AJ
515#if HAVE_GSSAPI
516 if (www_neg) {
517 if (host) {
aadbbd7d 518 const char *token = GSSAPI_token(host);
4b19fa9e 519 msg << "Proxy-Authorization: Negotiate " << token << "\r\n";
b745a16e 520 delete[] token;
823d23e4 521 } else
95c25f66 522 std::cerr << "ERROR: server host missing" << std::endl;
823d23e4
AJ
523 }
524 if (proxy_neg) {
b4f805f6 525 if (Transport::Config.hostname) {
aadbbd7d 526 const char *token = GSSAPI_token(Transport::Config.hostname);
4b19fa9e 527 msg << "Proxy-Authorization: Negotiate " << token << "\r\n";
b745a16e 528 delete[] token;
823d23e4 529 } else
95c25f66 530 std::cerr << "ERROR: proxy server host missing" << std::endl;
823d23e4
AJ
531 }
532#endif
af6a12ee 533
95e78500
AJ
534 /* HTTP/1.0 may need keep-alive explicitly */
535 if (strcmp(version, "1.0") == 0 && keep_alive)
4b19fa9e 536 msg << "Connection: keep-alive\r\n";
95e78500
AJ
537
538 /* HTTP/1.1 may need close explicitly */
51d94d10 539 if (!keep_alive)
4b19fa9e 540 msg << "Connection: close\r\n";
af6a12ee 541
4b19fa9e
AJ
542 if (extra_hdrs) {
543 msg << extra_hdrs;
544 safe_free(extra_hdrs);
545 }
546 msg << "\r\n"; // empty line ends MIME header block
a78886fc 547 }
5ac5029d 548
4b19fa9e
AJ
549 msg.flush();
550 const auto messageHeader = msg.str();
551 debugVerbose(1, "Request:" << std::endl << messageHeader << std::endl << ".");
63259c34 552
842cd45a 553 uint32_t loops = Ping::Init();
62e76326 554
b38767c7 555 for (uint32_t i = 0; loops == 0 || i < loops; ++i) {
842cd45a 556 size_t fsize = 0;
cc192b50 557
b4f805f6
AJ
558 if (!Transport::Connect())
559 continue;
988e90e1 560
3afd7aae 561 /* Send the HTTP request */
95c25f66 562 debugVerbose(2, "Sending HTTP request ... ");
4b19fa9e 563 bytesWritten = Transport::Write(messageHeader.data(), messageHeader.length());
988e90e1 564
3afd7aae 565 if (bytesWritten < 0) {
95c25f66 566 std::cerr << "ERROR: write" << std::endl;
24885773 567 exit(EXIT_FAILURE);
4b19fa9e
AJ
568 } else if (static_cast<size_t>(bytesWritten) != messageHeader.length()) {
569 std::cerr << "ERROR: Failed to send the following request: " << std::endl
570 << messageHeader << std::endl;
24885773 571 exit(EXIT_FAILURE);
3afd7aae 572 }
95c25f66 573 debugVerbose(2, "done.");
cc192b50 574
3afd7aae 575 if (put_file) {
95c25f66 576 debugVerbose(1, "Sending HTTP request payload ...");
3afd7aae 577 int x;
cf4ae693
AJ
578 if ((x = lseek(put_fd, 0, SEEK_SET)) < 0) {
579 int xerrno = errno;
580 std::cerr << "ERROR: lseek: " << xstrerr(xerrno) << std::endl;
581
582 } else while ((x = read(put_fd, buf, sizeof(buf))) > 0) {
62e76326 583
d64ed7f5 584 x = Transport::Write(buf, x);
62e76326 585
d64ed7f5 586 total_bytes += x;
62e76326 587
d64ed7f5
SM
588 if (x <= 0)
589 break;
590 }
62e76326 591
3afd7aae 592 if (x != 0)
95c25f66 593 std::cerr << "ERROR: Cannot send file." << std::endl;
b65ab6e8 594 else
95c25f66 595 debugVerbose(1, "done.");
3afd7aae
AJ
596 }
597 /* Read the data */
54220df8 598
0e25b470 599#if _SQUID_WINDOWS_
3afd7aae 600 setmode(1, O_BINARY);
00f768c1 601#endif
62e76326 602
b4f805f6 603 while ((len = Transport::Read(buf, sizeof(buf))) > 0) {
3afd7aae 604 fsize += len;
62e76326 605
b69e9ffa
AJ
606 if (to_stdout && fwrite(buf, len, 1, stdout) != 1) {
607 int xerrno = errno;
608 std::cerr << "ERROR: writing to stdout: " << xstrerr(xerrno) << std::endl;
609 }
3afd7aae 610 }
62e76326 611
b4f805f6
AJ
612#if USE_GNUTLS
613 if (Transport::Config.tlsEnabled) {
614 if (len == 0) {
615 std::cerr << "- Peer has closed the TLS connection" << std::endl;
616 } else if (!gnutls_error_is_fatal(len)) {
617 std::cerr << "WARNING: " << gnutls_strerror(len) << std::endl;
618 } else {
619 std::cerr << "ERROR: " << gnutls_strerror(len) << std::endl;
620 }
621 }
622#endif
623
0e25b470 624#if _SQUID_WINDOWS_
3afd7aae 625 setmode(1, O_TEXT);
0ef0f1de 626#endif
62e76326 627
b4f805f6 628 Transport::CloseConnection();
62e76326 629
842cd45a 630 if (Ping::LoopDone(i))
3afd7aae 631 break;
62e76326 632
842cd45a 633 Ping::TimerStop(fsize);
090089c4 634 }
899bab3f 635
842cd45a 636 Ping::DisplayStats();
b4f805f6 637 Transport::ShutdownTls();
24885773 638 return EXIT_SUCCESS;
090089c4 639}
640
daacd51f 641void
ced8def3 642pipe_handler(int)
e1381638 643{
bf989d30 644 std::cerr << "SIGPIPE received." << std::endl;
54220df8 645}
646
647static void
e1381638
AJ
648set_our_signal(void)
649{
54220df8 650#if HAVE_SIGACTION
651 struct sigaction sa;
652 sa.sa_handler = pipe_handler;
653 sa.sa_flags = SA_RESTART;
654 sigemptyset(&sa.sa_mask);
62e76326 655
54220df8 656 if (sigaction(SIGPIPE, &sa, NULL) < 0) {
bf989d30 657 std::cerr << "ERROR: Cannot set PIPE signal." << std::endl;
24885773 658 exit(EXIT_FAILURE);
54220df8 659 }
660#else
661 signal(SIGPIPE, pipe_handler);
662#endif
54220df8 663}
f53969cc 664