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