1 #include "ping_common.h" 2 #include <ctype.h> 3 #include <sched.h> 4 5 int options; 6 7 int sndbuf; 8 int ttl; 9 int rtt; 10 int rtt_addend; 11 __u16 acked; 12 13 int mx_dup_ck = MAX_DUP_CHK; 14 char rcvd_tbl[MAX_DUP_CHK / 8]; 15 16 17 /* counters */ 18 long npackets; /* max packets to transmit */ 19 long nreceived; /* # of packets we got back */ 20 long nrepeats; /* number of duplicates */ 21 long ntransmitted; /* sequence # for outbound packets = #sent */ 22 long nchecksum; /* replies with bad checksum */ 23 long nerrors; /* icmp errors */ 24 int interval = 1000; /* interval between packets (msec) */ 25 int preload; 26 int deadline = 0; /* time to die */ 27 int lingertime = MAXWAIT*1000; 28 struct timeval start_time, cur_time; 29 volatile int exiting; 30 volatile int status_snapshot; 31 int confirm = 0; 32 33 /* Stupid workarounds for bugs/missing functionality in older linuces. 34 * confirm_flag fixes refusing service of kernels without MSG_CONFIRM. 35 * i.e. for linux-2.2 */ 36 int confirm_flag = MSG_CONFIRM; 37 /* And this is workaround for bug in IP_RECVERR on raw sockets which is present 38 * in linux-2.2.[0-19], linux-2.4.[0-7] */ 39 int working_recverr; 40 41 /* timing */ 42 int timing; /* flag to do timing */ 43 long tmin = LONG_MAX; /* minimum round trip time */ 44 long tmax; /* maximum round trip time */ 45 /* Message for rpm maintainers: have _shame_. If you want 46 * to fix something send the patch to me for sanity checking. 47 * "sparcfix" patch is a complete non-sense, apparenly the person 48 * prepared it was stoned. 49 */ 50 long long tsum; /* sum of all times, for doing average */ 51 long long tsum2; 52 int pipesize = -1; 53 54 int datalen = DEFDATALEN; 55 56 char *hostname; 57 int uid; 58 int ident; /* process id to identify our packets */ 59 60 static int screen_width = INT_MAX; 61 62 /* Fills all the outpack, excluding ICMP header, but _including_ 63 * timestamp area with supplied pattern. 64 */ 65 static void fill(char *patp) 66 { 67 int ii, jj, kk; 68 int pat[16]; 69 char *cp; 70 char *bp = outpack+8; 71 72 for (cp = patp; *cp; cp++) { 73 if (!isxdigit(*cp)) { 74 fprintf(stderr, 75 "ping: patterns must be specified as hex digits.\n"); 76 exit(2); 77 } 78 } 79 ii = sscanf(patp, 80 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 81 &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 82 &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 83 &pat[13], &pat[14], &pat[15]); 84 85 if (ii > 0) { 86 for (kk = 0; kk <= maxpacket - (8 + ii); kk += ii) 87 for (jj = 0; jj < ii; ++jj) 88 bp[jj + kk] = pat[jj]; 89 } 90 if (!(options & F_QUIET)) { 91 printf("PATTERN: 0x"); 92 for (jj = 0; jj < ii; ++jj) 93 printf("%02x", bp[jj] & 0xFF); 94 printf("\n"); 95 } 96 } 97 98 void common_options(int ch) 99 { 100 switch(ch) { 101 case 'a': 102 options |= F_AUDIBLE; 103 break; 104 case 'A': 105 options |= F_ADAPTIVE; 106 break; 107 case 'c': 108 npackets = atoi(optarg); 109 if (npackets <= 0) { 110 fprintf(stderr, "ping: bad number of packets to transmit.\n"); 111 exit(2); 112 } 113 break; 114 case 'd': 115 options |= F_SO_DEBUG; 116 break; 117 case 'f': 118 options |= F_FLOOD; 119 setbuf(stdout, (char *)NULL); 120 break; 121 case 'i': /* wait between sending packets */ 122 { 123 if (strchr(optarg, '.')) { 124 float t; 125 if (sscanf(optarg, "%f", &t) != 1) { 126 fprintf(stderr, "ping: bad timing interval.\n"); 127 exit(2); 128 } 129 interval = (int)(t*1000); 130 } else if (sscanf(optarg, "%d", &interval) == 1) { 131 interval *= 1000; 132 } else { 133 fprintf(stderr, "ping: bad timing interval.\n"); 134 exit(2); 135 } 136 137 if (interval < 0) { 138 fprintf(stderr, "ping: bad timing interval.\n"); 139 exit(2); 140 } 141 options |= F_INTERVAL; 142 break; 143 } 144 case 'w': 145 deadline = atoi(optarg); 146 if (deadline < 0) { 147 fprintf(stderr, "ping: bad wait time.\n"); 148 exit(2); 149 } 150 break; 151 case 'l': 152 preload = atoi(optarg); 153 if (preload <= 0) { 154 fprintf(stderr, "ping: bad preload value, should be 1..%d\n", mx_dup_ck); 155 exit(2); 156 } 157 if (preload > mx_dup_ck) 158 preload = mx_dup_ck; 159 if (uid && preload > 3) { 160 fprintf(stderr, "ping: cannot set preload to value > 3\n"); 161 exit(2); 162 } 163 break; 164 case 'S': 165 sndbuf = atoi(optarg); 166 if (sndbuf <= 0) { 167 fprintf(stderr, "ping: bad sndbuf value.\n"); 168 exit(2); 169 } 170 break; 171 case 'n': 172 options |= F_NUMERIC; 173 break; 174 case 'p': /* fill buffer with user pattern */ 175 options |= F_PINGFILLED; 176 fill(optarg); 177 break; 178 case 'q': 179 options |= F_QUIET; 180 break; 181 case 'r': 182 options |= F_SO_DONTROUTE; 183 break; 184 case 's': /* size of packet to send */ 185 datalen = atoi(optarg); 186 if (datalen < 0) { 187 fprintf(stderr, "ping: illegal negative packet size %d.\n", datalen); 188 exit(2); 189 } 190 break; 191 case 'v': 192 options |= F_VERBOSE; 193 break; 194 case 'L': 195 options |= F_NOLOOP; 196 break; 197 case 't': 198 options |= F_TTL; 199 ttl = atoi(optarg); 200 if (ttl < 0 || ttl > 255) { 201 fprintf(stderr, "ping: ttl %u out of range\n", ttl); 202 exit(2); 203 } 204 break; 205 case 'U': 206 options |= F_LATENCY; 207 break; 208 case 'B': 209 options |= F_STRICTSOURCE; 210 break; 211 case 'W': 212 lingertime = atoi(optarg); 213 if (lingertime < 0 || lingertime > INT_MAX/1000000) { 214 fprintf(stderr, "ping: bad linger time.\n"); 215 exit(2); 216 } 217 lingertime *= 1000; 218 break; 219 case 'V': 220 printf("ping utility, iputils-ss%s\n", SNAPSHOT); 221 exit(0); 222 default: 223 abort(); 224 } 225 } 226 227 228 static void sigexit(int signo) 229 { 230 exiting = 1; 231 } 232 233 static void sigstatus(int signo) 234 { 235 status_snapshot = 1; 236 } 237 238 239 int __schedule_exit(int next) 240 { 241 static unsigned long waittime; 242 struct itimerval it; 243 244 if (waittime) 245 return next; 246 247 if (nreceived) { 248 waittime = 2 * tmax; 249 if (waittime < 1000*interval) 250 waittime = 1000*interval; 251 } else 252 waittime = lingertime*1000; 253 254 if (next < 0 || next < waittime/1000) 255 next = waittime/1000; 256 257 it.it_interval.tv_sec = 0; 258 it.it_interval.tv_usec = 0; 259 it.it_value.tv_sec = waittime/1000000; 260 it.it_value.tv_usec = waittime%1000000; 261 setitimer(ITIMER_REAL, &it, NULL); 262 return next; 263 } 264 265 static inline void update_interval(void) 266 { 267 int est = rtt ? rtt/8 : interval*1000; 268 269 interval = (est+rtt_addend+500)/1000; 270 if (uid && interval < MINUSERINTERVAL) 271 interval = MINUSERINTERVAL; 272 } 273 274 /* 275 * pinger -- 276 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 277 * will be added on by the kernel. The ID field is our UNIX process ID, 278 * and the sequence number is an ascending integer. The first 8 bytes 279 * of the data portion are used to hold a UNIX "timeval" struct in VAX 280 * byte-order, to compute the round-trip time. 281 */ 282 int pinger(void) 283 { 284 static int oom_count; 285 static int tokens; 286 int i; 287 288 /* Have we already sent enough? If we have, return an arbitrary positive value. */ 289 if (exiting || (npackets && ntransmitted >= npackets && !deadline)) 290 return 1000; 291 292 /* Check that packets < rate*time + preload */ 293 if (cur_time.tv_sec == 0) { 294 gettimeofday(&cur_time, NULL); 295 tokens = interval*(preload-1); 296 } else { 297 long ntokens; 298 struct timeval tv; 299 300 gettimeofday(&tv, NULL); 301 ntokens = (tv.tv_sec - cur_time.tv_sec)*1000 + 302 (tv.tv_usec-cur_time.tv_usec)/1000; 303 if (!interval) { 304 /* Case of unlimited flood is special; 305 * if we see no reply, they are limited to 100pps */ 306 if (ntokens < MININTERVAL && in_flight() >= preload) 307 return MININTERVAL-ntokens; 308 } 309 ntokens += tokens; 310 if (ntokens > interval*preload) 311 ntokens = interval*preload; 312 if (ntokens < interval) 313 return interval - ntokens; 314 315 cur_time = tv; 316 tokens = ntokens - interval; 317 } 318 319 resend: 320 i = send_probe(); 321 322 if (i == 0) { 323 oom_count = 0; 324 advance_ntransmitted(); 325 if (!(options & F_QUIET) && (options & F_FLOOD)) { 326 /* Very silly, but without this output with 327 * high preload or pipe size is very confusing. */ 328 if ((preload < screen_width && pipesize < screen_width) || 329 in_flight() < screen_width) 330 write(STDOUT_FILENO, ".", 1); 331 } 332 return interval - tokens; 333 } 334 335 /* And handle various errors... */ 336 if (i > 0) { 337 /* Apparently, it is some fatal bug. */ 338 abort(); 339 } else if (errno == ENOBUFS || errno == ENOMEM) { 340 int nores_interval; 341 342 /* Device queue overflow or OOM. Packet is not sent. */ 343 tokens = 0; 344 /* Slowdown. This works only in adaptive mode (option -A) */ 345 rtt_addend += (rtt < 8*50000 ? rtt/8 : 50000); 346 if (options&F_ADAPTIVE) 347 update_interval(); 348 nores_interval = SCHINT(interval/2); 349 if (nores_interval > 500) 350 nores_interval = 500; 351 oom_count++; 352 if (oom_count*nores_interval < lingertime) 353 return nores_interval; 354 i = 0; 355 /* Fall to hard error. It is to avoid complete deadlock 356 * on stuck output device even when dealine was not requested. 357 * Expected timings are screwed up in any case, but we will 358 * exit some day. :-) */ 359 } else if (errno == EAGAIN) { 360 /* Socket buffer is full. */ 361 tokens += interval; 362 return MININTERVAL; 363 } else { 364 if ((i=receive_error_msg()) > 0) { 365 /* An ICMP error arrived. */ 366 tokens += interval; 367 return MININTERVAL; 368 } 369 /* Compatibility with old linuces. */ 370 if (i == 0 && confirm_flag && errno == EINVAL) { 371 confirm_flag = 0; 372 errno = 0; 373 } 374 if (!errno) 375 goto resend; 376 } 377 378 /* Hard local error. Pretend we sent packet. */ 379 advance_ntransmitted(); 380 381 if (i == 0 && !(options & F_QUIET)) { 382 if (options & F_FLOOD) 383 write(STDOUT_FILENO, "E", 1); 384 else 385 perror("ping: sendmsg"); 386 } 387 tokens = 0; 388 return SCHINT(interval); 389 } 390 391 /* Set socket buffers, "alloc" is an estimate of memory taken by single packet. */ 392 393 void sock_setbufs(int icmp_sock, int alloc) 394 { 395 int rcvbuf, hold; 396 int tmplen = sizeof(hold); 397 398 if (!sndbuf) 399 sndbuf = alloc; 400 setsockopt(icmp_sock, SOL_SOCKET, SO_SNDBUF, (char *)&sndbuf, sizeof(sndbuf)); 401 402 rcvbuf = hold = alloc * preload; 403 if (hold < 65536) 404 hold = 65536; 405 setsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold)); 406 if (getsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *)&hold, &tmplen) == 0) { 407 if (hold < rcvbuf) 408 fprintf(stderr, "WARNING: probably, rcvbuf is not enough to hold preload.\n"); 409 } 410 } 411 412 /* Protocol independent setup and parameter checks. */ 413 414 void setup(int icmp_sock) 415 { 416 int hold; 417 struct timeval tv; 418 419 if ((options & F_FLOOD) && !(options & F_INTERVAL)) 420 interval = 0; 421 422 if (uid && interval < MINUSERINTERVAL) { 423 fprintf(stderr, "ping: cannot flood; minimal interval, allowed for user, is %dms\n", MINUSERINTERVAL); 424 exit(2); 425 } 426 427 if (interval >= INT_MAX/preload) { 428 fprintf(stderr, "ping: illegal preload and/or interval\n"); 429 exit(2); 430 } 431 432 hold = 1; 433 if (options & F_SO_DEBUG) 434 setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG, (char *)&hold, sizeof(hold)); 435 if (options & F_SO_DONTROUTE) 436 setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, sizeof(hold)); 437 438 #ifdef SO_TIMESTAMP 439 if (!(options&F_LATENCY)) { 440 int on = 1; 441 if (setsockopt(icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) 442 fprintf(stderr, "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP\n"); 443 } 444 #endif 445 446 /* Set some SNDTIMEO to prevent blocking forever 447 * on sends, when device is too slow or stalls. Just put limit 448 * of one second, or "interval", if it is less. 449 */ 450 tv.tv_sec = 1; 451 tv.tv_usec = 0; 452 if (interval < 1000) { 453 tv.tv_sec = 0; 454 tv.tv_usec = 1000 * SCHINT(interval); 455 } 456 setsockopt(icmp_sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv)); 457 458 /* Set RCVTIMEO to "interval". Note, it is just an optimization 459 * allowing to avoid redundant poll(). */ 460 tv.tv_sec = SCHINT(interval)/1000; 461 tv.tv_usec = 1000*(SCHINT(interval)%1000); 462 if (setsockopt(icmp_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv))) 463 options |= F_FLOOD_POLL; 464 465 if (!(options & F_PINGFILLED)) { 466 int i; 467 char *p = outpack+8; 468 469 /* Do not forget about case of small datalen, 470 * fill timestamp area too! 471 */ 472 for (i = 0; i < datalen; ++i) 473 *p++ = i; 474 } 475 476 if (!ident) 477 ident = getpid() & 0xFFFF; 478 479 set_signal(SIGINT, sigexit); 480 set_signal(SIGALRM, sigexit); 481 set_signal(SIGQUIT, sigstatus); 482 483 gettimeofday(&start_time, NULL); 484 485 if (deadline) { 486 struct itimerval it; 487 488 it.it_interval.tv_sec = 0; 489 it.it_interval.tv_usec = 0; 490 it.it_value.tv_sec = deadline; 491 it.it_value.tv_usec = 0; 492 setitimer(ITIMER_REAL, &it, NULL); 493 } 494 495 #ifndef ANDROID 496 if (isatty(STDOUT_FILENO)) { 497 struct winsize w; 498 499 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) { 500 if (w.ws_col > 0) 501 screen_width = w.ws_col; 502 } 503 } 504 #endif 505 } 506 507 void main_loop(int icmp_sock, __u8 *packet, int packlen) 508 { 509 char addrbuf[128]; 510 char ans_data[4096]; 511 struct iovec iov; 512 struct msghdr msg; 513 struct cmsghdr *c; 514 int cc; 515 int next; 516 int polling; 517 518 iov.iov_base = (char *)packet; 519 520 for (;;) { 521 /* Check exit conditions. */ 522 if (exiting) 523 break; 524 if (npackets && nreceived + nerrors >= npackets) 525 break; 526 if (deadline && nerrors) 527 break; 528 /* Check for and do special actions. */ 529 if (status_snapshot) 530 status(); 531 532 /* Send probes scheduled to this time. */ 533 do { 534 next = pinger(); 535 next = schedule_exit(next); 536 } while (next <= 0); 537 538 /* "next" is time to send next probe, if positive. 539 * If next<=0 send now or as soon as possible. */ 540 541 /* Technical part. Looks wicked. Could be dropped, 542 * if everyone used the newest kernel. :-) 543 * Its purpose is: 544 * 1. Provide intervals less than resolution of scheduler. 545 * Solution: spinning. 546 * 2. Avoid use of poll(), when recvmsg() can provide 547 * timed waiting (SO_RCVTIMEO). */ 548 polling = 0; 549 if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next<SCHINT(interval)) { 550 int recv_expected = in_flight(); 551 552 /* If we are here, recvmsg() is unable to wait for 553 * required timeout. */ 554 if (1000*next <= 1000000/(int)HZ) { 555 /* Very short timeout... So, if we wait for 556 * something, we sleep for MININTERVAL. 557 * Otherwise, spin! */ 558 if (recv_expected) { 559 next = MININTERVAL; 560 } else { 561 next = 0; 562 /* When spinning, no reasons to poll. 563 * Use nonblocking recvmsg() instead. */ 564 polling = MSG_DONTWAIT; 565 /* But yield yet. */ 566 sched_yield(); 567 } 568 } 569 570 if (!polling && 571 ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) { 572 struct pollfd pset; 573 pset.fd = icmp_sock; 574 pset.events = POLLIN|POLLERR; 575 pset.revents = 0; 576 if (poll(&pset, 1, next) < 1 || 577 !(pset.revents&(POLLIN|POLLERR))) 578 continue; 579 polling = MSG_DONTWAIT; 580 } 581 } 582 583 for (;;) { 584 struct timeval *recv_timep = NULL; 585 struct timeval recv_time; 586 int not_ours = 0; /* Raw socket can receive messages 587 * destined to other running pings. */ 588 589 iov.iov_len = packlen; 590 msg.msg_name = addrbuf; 591 msg.msg_namelen = sizeof(addrbuf); 592 msg.msg_iov = &iov; 593 msg.msg_iovlen = 1; 594 msg.msg_control = ans_data; 595 msg.msg_controllen = sizeof(ans_data); 596 597 cc = recvmsg(icmp_sock, &msg, polling); 598 polling = MSG_DONTWAIT; 599 600 if (cc < 0) { 601 if (errno == EAGAIN || errno == EINTR) 602 break; 603 if (!receive_error_msg()) { 604 if (errno) { 605 perror("ping: recvmsg"); 606 break; 607 } 608 not_ours = 1; 609 } 610 } else { 611 612 #ifdef SO_TIMESTAMP 613 for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) { 614 if (c->cmsg_level != SOL_SOCKET || 615 c->cmsg_type != SO_TIMESTAMP) 616 continue; 617 if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval))) 618 continue; 619 recv_timep = (struct timeval*)CMSG_DATA(c); 620 } 621 #endif 622 623 if ((options&F_LATENCY) || recv_timep == NULL) { 624 if ((options&F_LATENCY) || 625 ioctl(icmp_sock, SIOCGSTAMP, &recv_time)) 626 gettimeofday(&recv_time, NULL); 627 recv_timep = &recv_time; 628 } 629 630 not_ours = parse_reply(&msg, cc, addrbuf, recv_timep); 631 } 632 633 /* See? ... someone runs another ping on this host. */ 634 if (not_ours) 635 install_filter(); 636 637 /* If nothing is in flight, "break" returns us to pinger. */ 638 if (in_flight() == 0) 639 break; 640 641 /* Otherwise, try to recvmsg() again. recvmsg() 642 * is nonblocking after the first iteration, so that 643 * if nothing is queued, it will receive EAGAIN 644 * and return to pinger. */ 645 } 646 } 647 finish(); 648 } 649 650 int gather_statistics(__u8 *ptr, int cc, __u16 seq, int hops, 651 int csfailed, struct timeval *tv, char *from) 652 { 653 int dupflag = 0; 654 long triptime = 0; 655 656 ++nreceived; 657 if (!csfailed) 658 acknowledge(seq); 659 660 if (timing && cc >= 8+sizeof(struct timeval)) { 661 struct timeval tmp_tv; 662 memcpy(&tmp_tv, ptr, sizeof(tmp_tv)); 663 664 restamp: 665 tvsub(tv, &tmp_tv); 666 triptime = tv->tv_sec * 1000000 + tv->tv_usec; 667 if (triptime < 0) { 668 fprintf(stderr, "Warning: time of day goes back (%ldus), taking countermeasures.\n", triptime); 669 triptime = 0; 670 if (!(options & F_LATENCY)) { 671 gettimeofday(tv, NULL); 672 options |= F_LATENCY; 673 goto restamp; 674 } 675 } 676 if (!csfailed) { 677 tsum += triptime; 678 tsum2 += (long long)triptime * (long long)triptime; 679 if (triptime < tmin) 680 tmin = triptime; 681 if (triptime > tmax) 682 tmax = triptime; 683 if (!rtt) 684 rtt = triptime*8; 685 else 686 rtt += triptime-rtt/8; 687 if (options&F_ADAPTIVE) 688 update_interval(); 689 } 690 } 691 692 if (csfailed) { 693 ++nchecksum; 694 --nreceived; 695 } else if (TST(seq % mx_dup_ck)) { 696 ++nrepeats; 697 --nreceived; 698 dupflag = 1; 699 } else { 700 SET(seq % mx_dup_ck); 701 dupflag = 0; 702 } 703 confirm = confirm_flag; 704 705 if (options & F_QUIET) 706 return 1; 707 708 if (options & F_FLOOD) { 709 if (!csfailed) 710 write(STDOUT_FILENO, "\b \b", 3); 711 else 712 write(STDOUT_FILENO, "\bC", 1); 713 } else { 714 int i; 715 __u8 *cp, *dp; 716 printf("%d bytes from %s: icmp_seq=%u", cc, from, seq); 717 718 if (hops >= 0) 719 printf(" ttl=%d", hops); 720 721 if (cc < datalen+8) { 722 printf(" (truncated)\n"); 723 return 1; 724 } 725 if (timing) { 726 if (triptime >= 100000) 727 printf(" time=%ld ms", triptime/1000); 728 else if (triptime >= 10000) 729 printf(" time=%ld.%01ld ms", triptime/1000, 730 (triptime%1000)/100); 731 else if (triptime >= 1000) 732 printf(" time=%ld.%02ld ms", triptime/1000, 733 (triptime%1000)/10); 734 else 735 printf(" time=%ld.%03ld ms", triptime/1000, 736 triptime%1000); 737 } 738 if (dupflag) 739 printf(" (DUP!)"); 740 if (csfailed) 741 printf(" (BAD CHECKSUM!)"); 742 743 /* check the data */ 744 cp = ((u_char*)ptr) + sizeof(struct timeval); 745 dp = &outpack[8 + sizeof(struct timeval)]; 746 for (i = sizeof(struct timeval); i < datalen; ++i, ++cp, ++dp) { 747 if (*cp != *dp) { 748 printf("\nwrong data byte #%d should be 0x%x but was 0x%x", 749 i, *dp, *cp); 750 cp = (u_char*)ptr + sizeof(struct timeval); 751 for (i = sizeof(struct timeval); i < datalen; ++i, ++cp) { 752 if ((i % 32) == sizeof(struct timeval)) 753 printf("\n#%d\t", i); 754 printf("%x ", *cp); 755 } 756 break; 757 } 758 } 759 } 760 return 0; 761 } 762 763 static long llsqrt(long long a) 764 { 765 long long prev = ~((long long)1 << 63); 766 long long x = a; 767 768 if (x > 0) { 769 while (x < prev) { 770 prev = x; 771 x = (x+(a/x))/2; 772 } 773 } 774 775 return (long)x; 776 } 777 778 /* 779 * finish -- 780 * Print out statistics, and give up. 781 */ 782 void finish(void) 783 { 784 struct timeval tv = cur_time; 785 786 tvsub(&tv, &start_time); 787 788 putchar('\n'); 789 fflush(stdout); 790 printf("--- %s ping statistics ---\n", hostname); 791 printf("%ld packets transmitted, ", ntransmitted); 792 printf("%ld received", nreceived); 793 if (nrepeats) 794 printf(", +%ld duplicates", nrepeats); 795 if (nchecksum) 796 printf(", +%ld corrupted", nchecksum); 797 if (nerrors) 798 printf(", +%ld errors", nerrors); 799 if (ntransmitted) { 800 printf(", %d%% packet loss", 801 (int) ((((long long)(ntransmitted - nreceived)) * 100) / 802 ntransmitted)); 803 printf(", time %ldms", 1000*tv.tv_sec+tv.tv_usec/1000); 804 } 805 putchar('\n'); 806 807 if (nreceived && timing) { 808 long tmdev; 809 810 tsum /= nreceived + nrepeats; 811 tsum2 /= nreceived + nrepeats; 812 tmdev = llsqrt(tsum2 - tsum * tsum); 813 814 printf("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms", 815 tmin/1000, tmin%1000, 816 (unsigned long)(tsum/1000), (long)(tsum%1000), 817 tmax/1000, tmax%1000, 818 tmdev/1000, tmdev%1000 819 ); 820 } 821 if (pipesize > 1) 822 printf(", pipe %d", pipesize); 823 if (ntransmitted > 1 && (!interval || (options&(F_FLOOD|F_ADAPTIVE)))) { 824 int ipg = (1000000*(long long)tv.tv_sec+tv.tv_usec)/(ntransmitted-1); 825 printf(", ipg/ewma %d.%03d/%d.%03d ms", 826 ipg/1000, ipg%1000, rtt/8000, (rtt/8)%1000); 827 } 828 putchar('\n'); 829 exit(!nreceived || (deadline && nreceived < npackets)); 830 } 831 832 833 void status(void) 834 { 835 int loss = 0; 836 long tavg = 0; 837 838 status_snapshot = 0; 839 840 if (ntransmitted) 841 loss = (((long long)(ntransmitted - nreceived)) * 100) / ntransmitted; 842 843 fprintf(stderr, "\r%ld/%ld packets, %d%% loss", ntransmitted, nreceived, loss); 844 845 if (nreceived && timing) { 846 tavg = tsum / (nreceived + nrepeats); 847 848 fprintf(stderr, ", min/avg/ewma/max = %ld.%03ld/%lu.%03ld/%d.%03d/%ld.%03ld ms", 849 tmin/1000, tmin%1000, 850 tavg/1000, tavg%1000, 851 rtt/8000, (rtt/8)%1000, 852 tmax/1000, tmax%1000 853 ); 854 } 855 fprintf(stderr, "\n"); 856 } 857 858