]> git.ipfire.org Git - thirdparty/squid.git/blame - tools/squidclient/squidclient.cc
SourceFormat Enforcement
[thirdparty/squid.git] / tools / squidclient / squidclient.cc
CommitLineData
30a4f2a8 1/*
bde978a6 2 * Copyright (C) 1996-2015 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
114 << " -H 'string' Extra headers to send. Use '\\n' for new lines." << std::endl
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 ;
090089c4 132 exit(1);
133}
134
b8d8561b 135int
136main(int argc, char *argv[])
090089c4 137{
b4f805f6 138 int len, bytesWritten;
2f399d29 139 bool to_stdout, reload;
599eadbe 140 int keep_alive = 0;
88738790 141 int opt_noaccept = 0;
14b85b48
DK
142#if HAVE_GSSAPI
143 int www_neg = 0, proxy_neg = 0;
144#endif
7ed62376
AJ
145 char url[BUFSIZ], msg[MESSAGELEN], buf[BUFSIZ];
146 char extra_hdrs[HEADERLEN];
0ee4272b 147 const char *method = "GET";
090089c4 148 extern char *optarg;
234967c9 149 time_t ims = 0;
b3b64e58 150 int max_forwards = -1;
62e76326 151
5ac5029d
AJ
152 const char *proxy_user = NULL;
153 const char *proxy_password = NULL;
154 const char *www_user = NULL;
155 const char *www_password = NULL;
156 const char *host = NULL;
157 const char *version = "1.0";
ba7ce724 158 const char *useragent = NULL;
090089c4 159
160 /* set the defaults */
63259c34 161 extra_hdrs[0] = '\0';
2f399d29
AJ
162 to_stdout = true;
163 reload = false;
090089c4 164
0ced8e5d 165 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
dc9d555d 166 if (argc < 2 || argv[argc-1][0] == '-') {
f53969cc 167 usage(argv[0]); /* need URL */
090089c4 168 } else if (argc >= 2) {
3afd7aae
AJ
169 strncpy(url, argv[argc - 1], BUFSIZ);
170 url[BUFSIZ - 1] = '\0';
62e76326 171
dc9d555d 172 int optIndex = 0;
d8c201b7 173 const char *shortOpStr = "aA:h:j:V:l:P:i:km:nNp:rsvt:H:T:u:U:w:W:?";
dc9d555d
AJ
174
175 // options for controlling squidclient
842cd45a
AJ
176 static struct option basicOptions[] = {
177 /* These are the generic options for squidclient itself */
178 {"help", no_argument, 0, '?'},
179 {"verbose", no_argument, 0, 'v'},
180 {"quiet", no_argument, 0, 's'},
b4f805f6
AJ
181 {"host", required_argument, 0, 'h'},
182 {"local", required_argument, 0, 'l'},
183 {"port", required_argument, 0, 'p'},
842cd45a 184 {"ping", no_argument, 0, '\1'},
9958ebee 185 {"https", no_argument, 0, '\3'},
842cd45a 186 {0, 0, 0, 0}
dc9d555d
AJ
187 };
188
189 int c;
190 while ((c = getopt_long(argc, argv, shortOpStr, basicOptions, &optIndex)) != -1) {
842cd45a
AJ
191
192 // modules parse their own specific options
3afd7aae 193 switch (c) {
842cd45a
AJ
194 case '\1':
195 to_stdout = 0;
b4f805f6
AJ
196 Ping::Config.parseCommandOpts(argc, argv, c, optIndex);
197 continue;
198
f53969cc
SM
199 case 'h': /* remote host */
200 case 'l': /* local host */
201 case 'p': /* port number */
b4f805f6
AJ
202 // rewind and let the Transport::Config parser handle
203 optind -= 2;
204
205 case '\3': // request over a TLS connection
206 Transport::Config.parseCommandOpts(argc, argv, c, optIndex);
207 continue;
842cd45a
AJ
208
209 default: // fall through to next switch
210 break;
211 }
212
213 switch (c) {
214
215 case '\0': // dummy value for end-of-options
216 break;
62e76326 217
3afd7aae
AJ
218 case 'a':
219 opt_noaccept = 1;
220 break;
62e76326 221
ba7ce724 222 case 'A':
be05c185 223 useragent = optarg;
ba7ce724
AJ
224 break;
225
5ac5029d 226 case 'j':
af6a12ee
AJ
227 host = optarg;
228 break;
5ac5029d
AJ
229
230 case 'V':
be05c185 231 version = optarg;
3afd7aae 232 break;
62e76326 233
f53969cc 234 case 's': /* silent */
2f399d29 235 to_stdout = false;
3afd7aae 236 break;
62e76326 237
f53969cc 238 case 'k': /* backward compat */
3afd7aae 239 keep_alive = 1;
3afd7aae 240 break;
62e76326 241
f53969cc 242 case 'r': /* reload */
2f399d29 243 reload = true;
3afd7aae 244 break;
62e76326 245
3afd7aae
AJ
246 case 'P':
247 put_file = xstrdup(optarg);
3afd7aae 248 break;
62e76326 249
f53969cc 250 case 'i': /* IMS */
3afd7aae 251 ims = (time_t) atoi(optarg);
3afd7aae 252 break;
62e76326 253
3afd7aae
AJ
254 case 'm':
255 method = xstrdup(optarg);
3afd7aae 256 break;
62e76326 257
3afd7aae
AJ
258 case 't':
259 method = xstrdup("TRACE");
3afd7aae 260 max_forwards = atoi(optarg);
3afd7aae 261 break;
62e76326 262
3afd7aae
AJ
263 case 'H':
264 if (strlen(optarg)) {
265 char *t;
266 strncpy(extra_hdrs, optarg, sizeof(extra_hdrs));
3afd7aae
AJ
267 while ((t = strstr(extra_hdrs, "\\n")))
268 *t = '\r', *(t + 1) = '\n';
269 }
270 break;
62e76326 271
3afd7aae 272 case 'T':
b4f805f6 273 Transport::Config.ioTimeout = atoi(optarg);
3afd7aae 274 break;
62e76326 275
3afd7aae
AJ
276 case 'u':
277 proxy_user = optarg;
278 break;
62e76326 279
3afd7aae
AJ
280 case 'w':
281 proxy_password = optarg;
282 break;
62e76326 283
3afd7aae
AJ
284 case 'U':
285 www_user = optarg;
286 break;
62e76326 287
3afd7aae
AJ
288 case 'W':
289 www_password = optarg;
290 break;
62e76326 291
823d23e4 292 case 'n':
dc9d555d 293#if HAVE_GSSAPI
823d23e4 294 proxy_neg = 1;
dc9d555d
AJ
295#else
296 std::cerr << "ERROR: Negotiate authentication not supported." << std::endl;
297 usage(argv[0]);
298#endif
823d23e4
AJ
299 break;
300
301 case 'N':
dc9d555d 302#if HAVE_GSSAPI
823d23e4 303 www_neg = 1;
dc9d555d
AJ
304#else
305 std::cerr << "ERROR: Negotiate authentication not supported." << std::endl;
306 usage(argv[0]);
823d23e4 307#endif
dc9d555d
AJ
308 break;
309
3afd7aae
AJ
310 case 'v':
311 /* undocumented: may increase verb-level by giving more -v's */
842cd45a
AJ
312 ++scParams.verbosityLevel;
313 debugVerbose(2, "verbosity level set to " << scParams.verbosityLevel);
3afd7aae 314 break;
62e76326 315
f53969cc 316 case '?': /* usage */
62e76326 317
3afd7aae
AJ
318 default:
319 usage(argv[0]);
320 break;
321 }
dc9d555d 322 }
090089c4 323 }
0e25b470 324#if _SQUID_WINDOWS_
0ef0f1de 325 {
3afd7aae
AJ
326 WSADATA wsaData;
327 WSAStartup(2, &wsaData);
328 atexit(Win32SockCleanup);
0ef0f1de 329 }
330#endif
090089c4 331 /* Build the HTTP request */
8a9b6b94 332 if (strncmp(url, "mgr:", 4) == 0) {
3afd7aae 333 char *t = xstrdup(url + 4);
3f3e5473
AJ
334 const char *at = NULL;
335 if (!strrchr(t, '@')) { // ignore any -w password if @ is explicit already.
336 at = proxy_password;
337 }
338 // embed the -w proxy password into old-style cachemgr URLs
339 if (at)
b4f805f6 340 snprintf(url, BUFSIZ, "cache_object://%s/%s@%s", Transport::Config.hostname, t, at);
3f3e5473 341 else
b4f805f6 342 snprintf(url, BUFSIZ, "cache_object://%s/%s", Transport::Config.hostname, t);
3afd7aae 343 xfree(t);
8a9b6b94 344 }
cca89eeb 345 if (put_file) {
3afd7aae
AJ
346 put_fd = open(put_file, O_RDONLY);
347 set_our_signal();
348
349 if (put_fd < 0) {
95c25f66 350 std::cerr << "ERROR: can't open file (" << xstrerror() << ")" << std::endl;
3afd7aae
AJ
351 exit(-1);
352 }
be266cb2 353#if _SQUID_WINDOWS_
3afd7aae 354 setmode(put_fd, O_BINARY);
c4aefe96 355#endif
62e76326 356
be05c185 357 if (fstat(put_fd, &sb) < 0) {
95c25f66 358 std::cerr << "ERROR: can't identify length of file (" << xstrerror() << ")" << std::endl;
be05c185 359 }
cca89eeb 360 }
5ac5029d
AJ
361
362 if (!host) {
af6a12ee
AJ
363 char *newhost = strstr(url, "://");
364 if (newhost) {
365 char *t;
366 newhost += 3;
dc47f531 367 newhost = xstrdup(newhost);
af6a12ee
AJ
368 t = newhost + strcspn(newhost, "@/?");
369 if (*t == '@') {
370 newhost = t + 1;
371 t = newhost + strcspn(newhost, "@/?");
372 }
373 *t = '\0';
374 host = newhost;
375 }
5ac5029d
AJ
376 }
377
8d55d7ef 378 if (version[0] == '-' || !version[0]) {
af6a12ee 379 /* HTTP/0.9, no headers, no version */
5ac5029d
AJ
380 snprintf(msg, BUFSIZ, "%s %s\r\n", method, url);
381 } else {
8d55d7ef
AJ
382 if (!xisdigit(version[0])) // not HTTP/n.n
383 snprintf(msg, BUFSIZ, "%s %s %s\r\n", method, url, version);
384 else
385 snprintf(msg, BUFSIZ, "%s %s HTTP/%s\r\n", method, url, version);
62e76326 386
af6a12ee
AJ
387 if (host) {
388 snprintf(buf, BUFSIZ, "Host: %s\r\n", host);
389 strcat(msg,buf);
390 }
391
ba7ce724
AJ
392 if (useragent == NULL) {
393 snprintf(buf, BUFSIZ, "User-Agent: squidclient/%s\r\n", VERSION);
394 strcat(msg,buf);
395 } else if (useragent[0] != '\0') {
396 snprintf(buf, BUFSIZ, "User-Agent: %s\r\n", useragent);
397 strcat(msg,buf);
398 }
399
af6a12ee 400 if (reload) {
d440ba10 401 snprintf(buf, BUFSIZ, "Cache-Control: no-cache\r\n");
af6a12ee
AJ
402 strcat(msg, buf);
403 }
404 if (put_fd > 0) {
173bc2bf 405 snprintf(buf, BUFSIZ, "Content-length: %" PRId64 "\r\n", (int64_t) sb.st_size);
af6a12ee
AJ
406 strcat(msg, buf);
407 }
408 if (opt_noaccept == 0) {
409 snprintf(buf, BUFSIZ, "Accept: */*\r\n");
410 strcat(msg, buf);
411 }
412 if (ims) {
413 snprintf(buf, BUFSIZ, "If-Modified-Since: %s\r\n", mkrfc1123(ims));
414 strcat(msg, buf);
415 }
416 if (max_forwards > -1) {
417 snprintf(buf, BUFSIZ, "Max-Forwards: %d\r\n", max_forwards);
418 strcat(msg, buf);
419 }
aadbbd7d
AJ
420 struct base64_encode_ctx ctx;
421 base64_encode_init(&ctx);
422 size_t blen;
af6a12ee
AJ
423 if (proxy_user) {
424 const char *user = proxy_user;
425 const char *password = proxy_password;
230c091c 426#if HAVE_GETPASS
af6a12ee
AJ
427 if (!password)
428 password = getpass("Proxy password: ");
230c091c 429#endif
af6a12ee 430 if (!password) {
95c25f66 431 std::cerr << "ERROR: Proxy password missing" << std::endl;
af6a12ee
AJ
432 exit(1);
433 }
aadbbd7d
AJ
434 blen = base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf), strlen(user), reinterpret_cast<const uint8_t*>(user));
435 blen += base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf+blen), 1, reinterpret_cast<const uint8_t*>(":"));
436 blen += base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf+blen), strlen(password), reinterpret_cast<const uint8_t*>(password));
437 blen += base64_encode_final(&ctx, reinterpret_cast<uint8_t*>(buf+blen));
bb64d879 438 snprintf(buf, BUFSIZ, "Proxy-Authorization: Basic %.*s\r\n", (int)blen, buf);
af6a12ee
AJ
439 strcat(msg, buf);
440 }
441 if (www_user) {
442 const char *user = www_user;
443 const char *password = www_password;
230c091c 444#if HAVE_GETPASS
af6a12ee
AJ
445 if (!password)
446 password = getpass("WWW password: ");
230c091c 447#endif
af6a12ee 448 if (!password) {
95c25f66 449 std::cerr << "ERROR: WWW password missing" << std::endl;
af6a12ee
AJ
450 exit(1);
451 }
aadbbd7d
AJ
452 blen = base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf), strlen(user), reinterpret_cast<const uint8_t*>(user));
453 blen += base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf+blen), 1, reinterpret_cast<const uint8_t*>(":"));
454 blen += base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(buf+blen), strlen(password), reinterpret_cast<const uint8_t*>(password));
455 blen += base64_encode_final(&ctx, reinterpret_cast<uint8_t*>(buf+blen));
bb64d879 456 snprintf(buf, BUFSIZ, "Authorization: Basic %.*s\r\n", (int)blen, buf);
af6a12ee
AJ
457 strcat(msg, buf);
458 }
823d23e4
AJ
459#if HAVE_GSSAPI
460 if (www_neg) {
461 if (host) {
aadbbd7d
AJ
462 const char *token = GSSAPI_token(host);
463 snprintf(buf, BUFSIZ, "Authorization: Negotiate %s\r\n", token);
823d23e4 464 strcat(msg, buf);
b745a16e 465 delete[] token;
823d23e4 466 } else
95c25f66 467 std::cerr << "ERROR: server host missing" << std::endl;
823d23e4
AJ
468 }
469 if (proxy_neg) {
b4f805f6 470 if (Transport::Config.hostname) {
aadbbd7d
AJ
471 const char *token = GSSAPI_token(Transport::Config.hostname);
472 snprintf(buf, BUFSIZ, "Proxy-Authorization: Negotiate %s\r\n", token);
823d23e4 473 strcat(msg, buf);
b745a16e 474 delete[] token;
823d23e4 475 } else
95c25f66 476 std::cerr << "ERROR: proxy server host missing" << std::endl;
823d23e4
AJ
477 }
478#endif
af6a12ee 479
95e78500
AJ
480 /* HTTP/1.0 may need keep-alive explicitly */
481 if (strcmp(version, "1.0") == 0 && keep_alive)
482 strcat(msg, "Connection: keep-alive\r\n");
483
484 /* HTTP/1.1 may need close explicitly */
51d94d10
AJ
485 if (!keep_alive)
486 strcat(msg, "Connection: close\r\n");
af6a12ee
AJ
487
488 strcat(msg, extra_hdrs);
489 strcat(msg, "\r\n");
a78886fc 490 }
5ac5029d 491
95c25f66 492 debugVerbose(1, "Request:" << std::endl << msg << std::endl << ".");
63259c34 493
842cd45a 494 uint32_t loops = Ping::Init();
62e76326 495
b38767c7 496 for (uint32_t i = 0; loops == 0 || i < loops; ++i) {
842cd45a 497 size_t fsize = 0;
cc192b50 498
b4f805f6
AJ
499 if (!Transport::Connect())
500 continue;
988e90e1 501
3afd7aae 502 /* Send the HTTP request */
95c25f66 503 debugVerbose(2, "Sending HTTP request ... ");
b4f805f6 504 bytesWritten = Transport::Write(msg, strlen(msg));
988e90e1 505
3afd7aae 506 if (bytesWritten < 0) {
95c25f66 507 std::cerr << "ERROR: write" << std::endl;
3afd7aae
AJ
508 exit(1);
509 } else if ((unsigned) bytesWritten != strlen(msg)) {
95c25f66 510 std::cerr << "ERROR: Cannot send request?: " << std::endl << msg << std::endl;
3afd7aae
AJ
511 exit(1);
512 }
95c25f66 513 debugVerbose(2, "done.");
cc192b50 514
3afd7aae 515 if (put_file) {
95c25f66 516 debugVerbose(1, "Sending HTTP request payload ...");
3afd7aae
AJ
517 int x;
518 lseek(put_fd, 0, SEEK_SET);
3afd7aae 519 while ((x = read(put_fd, buf, sizeof(buf))) > 0) {
62e76326 520
b4f805f6 521 x = Transport::Write(buf, x);
62e76326 522
3afd7aae 523 total_bytes += x;
62e76326 524
3afd7aae
AJ
525 if (x <= 0)
526 break;
527 }
62e76326 528
3afd7aae 529 if (x != 0)
95c25f66 530 std::cerr << "ERROR: Cannot send file." << std::endl;
b65ab6e8 531 else
95c25f66 532 debugVerbose(1, "done.");
3afd7aae
AJ
533 }
534 /* Read the data */
54220df8 535
0e25b470 536#if _SQUID_WINDOWS_
3afd7aae 537 setmode(1, O_BINARY);
00f768c1 538#endif
62e76326 539
b4f805f6 540 while ((len = Transport::Read(buf, sizeof(buf))) > 0) {
3afd7aae 541 fsize += len;
62e76326 542
8fee788b 543 if (to_stdout && fwrite(buf, len, 1, stdout) != 1)
95c25f66 544 std::cerr << "ERROR: writing to stdout: " << xstrerror() << std::endl;
3afd7aae 545 }
62e76326 546
b4f805f6
AJ
547#if USE_GNUTLS
548 if (Transport::Config.tlsEnabled) {
549 if (len == 0) {
550 std::cerr << "- Peer has closed the TLS connection" << std::endl;
551 } else if (!gnutls_error_is_fatal(len)) {
552 std::cerr << "WARNING: " << gnutls_strerror(len) << std::endl;
553 } else {
554 std::cerr << "ERROR: " << gnutls_strerror(len) << std::endl;
555 }
556 }
557#endif
558
0e25b470 559#if _SQUID_WINDOWS_
3afd7aae 560 setmode(1, O_TEXT);
0ef0f1de 561#endif
62e76326 562
b4f805f6 563 Transport::CloseConnection();
62e76326 564
842cd45a 565 if (Ping::LoopDone(i))
3afd7aae 566 break;
62e76326 567
842cd45a 568 Ping::TimerStop(fsize);
090089c4 569 }
899bab3f 570
842cd45a 571 Ping::DisplayStats();
b4f805f6 572 Transport::ShutdownTls();
983061ed 573 return 0;
090089c4 574}
575
daacd51f 576void
ced8def3 577pipe_handler(int)
e1381638 578{
bf989d30 579 std::cerr << "SIGPIPE received." << std::endl;
54220df8 580}
581
582static void
e1381638
AJ
583set_our_signal(void)
584{
54220df8 585#if HAVE_SIGACTION
586 struct sigaction sa;
587 sa.sa_handler = pipe_handler;
588 sa.sa_flags = SA_RESTART;
589 sigemptyset(&sa.sa_mask);
62e76326 590
54220df8 591 if (sigaction(SIGPIPE, &sa, NULL) < 0) {
bf989d30 592 std::cerr << "ERROR: Cannot set PIPE signal." << std::endl;
3afd7aae 593 exit(-1);
54220df8 594 }
595#else
596 signal(SIGPIPE, pipe_handler);
597#endif
54220df8 598}
f53969cc 599