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