"Fossies" - the Fresh Open Source Software Archive

Member "bwping-1.15/src/bwping.c" (10 May 2019, 24743 Bytes) of package /linux/privat/bwping-1.15.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "bwping.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.14_vs_1.15.

    1 #include "../include/features.h"
    2 
    3 #ifdef HAVE_CONFIG_H
    4 #include <config.h>
    5 #endif
    6 
    7 #include <sys/time.h>
    8 #include <sys/types.h>
    9 #include <sys/select.h>
   10 #include <sys/socket.h>
   11 
   12 #include <stdbool.h>
   13 #include <stdint.h>
   14 #include <stddef.h>
   15 #include <inttypes.h>
   16 #include <stdio.h>
   17 #include <unistd.h>
   18 #include <stdlib.h>
   19 #include <sysexits.h>
   20 #include <time.h>
   21 #include <errno.h>
   22 #include <string.h>
   23 #include <libgen.h>
   24 
   25 #include <arpa/inet.h>
   26 
   27 #include <netinet/in.h>
   28 #include <netinet/in_systm.h>
   29 #include <netinet/ip.h>
   30 #include <netinet/ip6.h>
   31 #include <netinet/ip_icmp.h>
   32 #ifdef HAVE_NETINET_ICMP6_H
   33 #include <netinet/icmp6.h>
   34 #endif
   35 
   36 #ifdef __CYGWIN__
   37 #include "../include/cygwin.h"
   38 #endif
   39 
   40 #include <netdb.h>
   41 
   42 const size_t   MAX_IPV4_HDR_SIZE       = 60;
   43 const uint32_t CALIBRATION_CYCLES      = 100,
   44                PKT_BURST_PRECISION     = 1000,
   45                BUF_SIZE_RESERVE_FACTOR = 10;
   46 
   47 int64_t min_rtt, max_rtt, average_rtt;
   48 char   *prog_name;
   49 
   50 static void get_time(struct timespec *ts)
   51 {
   52 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
   53 #if defined(CLOCK_HIGHRES)
   54     const clockid_t id = CLOCK_HIGHRES;
   55 #elif defined(CLOCK_MONOTONIC_RAW)
   56     const clockid_t id = CLOCK_MONOTONIC_RAW;
   57 #elif defined(CLOCK_MONOTONIC)
   58     const clockid_t id = CLOCK_MONOTONIC;
   59 #else
   60     const clockid_t id = CLOCK_REALTIME;
   61 #endif /* CLOCK_XXX */
   62 
   63     if (clock_gettime(id, ts) < 0) {
   64         fprintf(stderr, "%s: clock_gettime() failed: %s\n", prog_name, strerror(errno));
   65 
   66         ts->tv_sec  = 0;
   67         ts->tv_nsec = 0;
   68     }
   69 #else
   70     struct timeval tv;
   71 
   72     if (gettimeofday(&tv, NULL) < 0) {
   73         fprintf(stderr, "%s: gettimeofday() failed: %s\n", prog_name, strerror(errno));
   74 
   75         ts->tv_sec  = 0;
   76         ts->tv_nsec = 0;
   77     } else {
   78         ts->tv_sec  = tv.tv_sec;
   79         ts->tv_nsec = tv.tv_usec * 1000;
   80     }
   81 #endif /* HAVE_CLOCK_GETTIME */
   82 }
   83 
   84 static int64_t ts_sub(struct timespec *ts1, struct timespec *ts2)
   85 {
   86     return ((int64_t)ts1->tv_sec - (int64_t)ts2->tv_sec) * 1000000 + (ts1->tv_nsec - ts2->tv_nsec) / 1000;
   87 }
   88 
   89 static uint16_t cksum(void *packet, size_t pkt_size)
   90 {
   91     size_t   i;
   92     uint32_t sum;
   93     uint16_t buf[IP_MAXPACKET];
   94 
   95     memset(buf, 0,      sizeof(buf));
   96     memcpy(buf, packet, pkt_size);
   97 
   98     sum = 0;
   99 
  100     for (i = 0; i < pkt_size / 2 + pkt_size % 2; i++) {
  101         sum += buf[i];
  102     }
  103 
  104     sum  = (sum >> 16) + (sum & 0xFFFF);
  105     sum += (sum >> 16);
  106 
  107     return ~sum;
  108 }
  109 
  110 static int64_t calibrate_timer(void)
  111 {
  112     int             n;
  113     uint32_t        i;
  114     int64_t         sum;
  115     struct timeval  timeout;
  116     struct timespec begin, end;
  117 
  118     sum = 0;
  119 
  120     for (i = 0; i < CALIBRATION_CYCLES; i++) {
  121         n = -1;
  122 
  123         while (n < 0) {
  124             get_time(&begin);
  125 
  126             timeout.tv_sec  = 0;
  127             timeout.tv_usec = 10;
  128 
  129             n = select(0, NULL, NULL, NULL, &timeout);
  130         }
  131 
  132         get_time(&end);
  133 
  134         sum += ts_sub(&end, &begin);
  135     }
  136 
  137     return sum / CALIBRATION_CYCLES;
  138 }
  139 
  140 static void send_ping4(int sock, struct sockaddr_in *to4, size_t pkt_size, uint16_t ident, bool first_in_burst, uint32_t *transmitted_number, uint64_t *transmitted_volume)
  141 {
  142     ssize_t         res;
  143     char            packet[IP_MAXPACKET];
  144     struct icmp     icmp4;
  145     struct timespec now, pkt_time;
  146 
  147     memset(&icmp4, 0, sizeof(icmp4));
  148 
  149     icmp4.icmp_type  = ICMP_ECHO;
  150     icmp4.icmp_code  = 0;
  151     icmp4.icmp_cksum = 0;
  152     icmp4.icmp_id    = ident;
  153     icmp4.icmp_seq   = htons(*transmitted_number);
  154 
  155     memcpy(packet, &icmp4, sizeof(icmp4));
  156 
  157     if (first_in_burst) {
  158         get_time(&now);
  159 
  160         pkt_time.tv_sec  = now.tv_sec;
  161         pkt_time.tv_nsec = now.tv_nsec;
  162     } else {
  163         memset(&pkt_time, 0, sizeof(pkt_time));
  164     }
  165 
  166     memcpy(&packet[sizeof(icmp4)], &pkt_time, sizeof(pkt_time));
  167 
  168     icmp4.icmp_cksum = cksum(packet, pkt_size);
  169 
  170     memcpy(&packet[offsetof(struct icmp, icmp_cksum)], &icmp4.icmp_cksum, sizeof(icmp4.icmp_cksum));
  171 
  172     res = sendto(sock, packet, pkt_size, 0, (struct sockaddr *)to4, sizeof(*to4));
  173 
  174     if (res < 0) {
  175         fprintf(stderr, "%s: sendto() failed: %s\n", prog_name, strerror(errno));
  176     } else if (res != (ssize_t)pkt_size) {
  177         fprintf(stderr, "%s: partial write: packet size: %zu, sent: %zd\n", prog_name, pkt_size, res);
  178     }
  179 
  180     (*transmitted_number)++;
  181     (*transmitted_volume) += pkt_size;
  182 }
  183 
  184 static void send_ping6(int sock, struct sockaddr_in6 *to6, size_t pkt_size, uint16_t ident, bool first_in_burst, uint32_t *transmitted_number, uint64_t *transmitted_volume)
  185 {
  186     ssize_t          res;
  187     char             packet[IP_MAXPACKET];
  188     struct icmp6_hdr icmp6;
  189     struct timespec  now, pkt_time;
  190 
  191     memset(&icmp6, 0, sizeof(icmp6));
  192 
  193     icmp6.icmp6_type  = ICMP6_ECHO_REQUEST;
  194     icmp6.icmp6_code  = 0;
  195     icmp6.icmp6_cksum = 0;
  196     icmp6.icmp6_id    = ident;
  197     icmp6.icmp6_seq   = htons(*transmitted_number);
  198 
  199     memcpy(packet, &icmp6, sizeof(icmp6));
  200 
  201     if (first_in_burst) {
  202         get_time(&now);
  203 
  204         pkt_time.tv_sec  = now.tv_sec;
  205         pkt_time.tv_nsec = now.tv_nsec;
  206     } else {
  207         memset(&pkt_time, 0, sizeof(pkt_time));
  208     }
  209 
  210     memcpy(&packet[sizeof(icmp6)], &pkt_time, sizeof(pkt_time));
  211 
  212     res = sendto(sock, packet, pkt_size, 0, (struct sockaddr *)to6, sizeof(*to6));
  213 
  214     if (res < 0) {
  215         fprintf(stderr, "%s: sendto() failed: %s\n", prog_name, strerror(errno));
  216     } else if (res != (ssize_t)pkt_size) {
  217         fprintf(stderr, "%s: partial write: packet size: %zu, sent: %zd\n", prog_name, pkt_size, res);
  218     }
  219 
  220     (*transmitted_number)++;
  221     (*transmitted_volume) += pkt_size;
  222 }
  223 
  224 static bool recv_ping4(int sock, uint16_t ident, uint32_t *received_number, uint64_t *received_volume)
  225 {
  226     size_t             hdr_len;
  227     ssize_t            res;
  228     int64_t            rtt;
  229     char               packet[IP_MAXPACKET];
  230     struct sockaddr_in from4;
  231     struct iovec       iov;
  232     struct msghdr      msg;
  233     struct ip          ip4;
  234     struct icmp        icmp4;
  235     struct timespec    now, pkt_time;
  236 
  237     memset(&iov, 0, sizeof(iov));
  238 
  239     iov.iov_base = packet;
  240     iov.iov_len  = sizeof(packet);
  241 
  242     memset(&msg, 0, sizeof(msg));
  243 
  244     msg.msg_name    = (caddr_t)&from4;
  245     msg.msg_namelen = sizeof(from4);
  246     msg.msg_iov     = &iov;
  247     msg.msg_iovlen  = 1;
  248 
  249     res = recvmsg(sock, &msg, MSG_DONTWAIT);
  250 
  251     if (res >= (ssize_t)sizeof(ip4)) {
  252         memcpy(&ip4, packet, sizeof(ip4));
  253 
  254         hdr_len = ip4.ip_hl << 2;
  255 
  256         if (res >= (ssize_t)(hdr_len + sizeof(icmp4))) {
  257             memcpy(&icmp4, &packet[hdr_len], sizeof(icmp4));
  258 
  259             if (icmp4.icmp_type == ICMP_ECHOREPLY &&
  260                 icmp4.icmp_id   == ident) {
  261                 (*received_number)++;
  262                 (*received_volume) += res - hdr_len;
  263 
  264                 if (res >= (ssize_t)(hdr_len + sizeof(icmp4) + sizeof(pkt_time))) {
  265                     memcpy(&pkt_time, &packet[hdr_len + sizeof(icmp4)], sizeof(pkt_time));
  266 
  267                     if (pkt_time.tv_sec != 0 || pkt_time.tv_nsec != 0) {
  268                         get_time(&now);
  269 
  270                         rtt = ts_sub(&now, &pkt_time) / 1000;
  271 
  272                         if (min_rtt > rtt) {
  273                             min_rtt = rtt;
  274                         }
  275                         if (max_rtt < rtt) {
  276                             max_rtt = rtt;
  277                         }
  278 
  279                         average_rtt = *received_number ? ((average_rtt * (*received_number - 1)) + rtt) / *received_number : average_rtt;
  280                     }
  281                 }
  282             }
  283         }
  284 
  285         return true;
  286     } else {
  287         return false;
  288     }
  289 }
  290 
  291 static bool recv_ping6(int sock, uint16_t ident, uint32_t *received_number, uint64_t *received_volume)
  292 {
  293     ssize_t             res;
  294     int64_t             rtt;
  295     char                packet[IP_MAXPACKET];
  296     struct sockaddr_in6 from6;
  297     struct iovec        iov;
  298     struct msghdr       msg;
  299     struct icmp6_hdr    icmp6;
  300     struct timespec     now, pkt_time;
  301 
  302     memset(&iov, 0, sizeof(iov));
  303 
  304     iov.iov_base = packet;
  305     iov.iov_len  = sizeof(packet);
  306 
  307     memset(&msg, 0, sizeof(msg));
  308 
  309     msg.msg_name    = (caddr_t)&from6;
  310     msg.msg_namelen = sizeof(from6);
  311     msg.msg_iov     = &iov;
  312     msg.msg_iovlen  = 1;
  313 
  314     res = recvmsg(sock, &msg, MSG_DONTWAIT);
  315 
  316     if (res >= (ssize_t)sizeof(icmp6)) {
  317         memcpy(&icmp6, packet, sizeof(icmp6));
  318 
  319         if (icmp6.icmp6_type == ICMP6_ECHO_REPLY &&
  320             icmp6.icmp6_id   == ident) {
  321             (*received_number)++;
  322             (*received_volume) += res;
  323 
  324             if (res >= (ssize_t)(sizeof(icmp6) + sizeof(pkt_time))) {
  325                 memcpy(&pkt_time, &packet[sizeof(icmp6)], sizeof(pkt_time));
  326 
  327                 if (pkt_time.tv_sec != 0 || pkt_time.tv_nsec != 0) {
  328                     get_time(&now);
  329 
  330                     rtt = ts_sub(&now, &pkt_time) / 1000;
  331 
  332                     if (min_rtt > rtt) {
  333                         min_rtt = rtt;
  334                     }
  335                     if (max_rtt < rtt) {
  336                         max_rtt = rtt;
  337                     }
  338 
  339                     average_rtt = *received_number ? ((average_rtt * (*received_number - 1)) + rtt) / *received_number : average_rtt;
  340                 }
  341             }
  342         }
  343 
  344         return true;
  345     } else {
  346         return false;
  347     }
  348 }
  349 
  350 static bool resolve_name4(char *name, struct sockaddr_in *addr4)
  351 {
  352     int              res;
  353     struct addrinfo  hints;
  354     struct addrinfo *res_info;
  355 
  356     memset(&hints, 0, sizeof(hints));
  357 
  358     hints.ai_flags    = AI_CANONNAME;
  359     hints.ai_family   = AF_INET;
  360     hints.ai_socktype = SOCK_RAW;
  361     hints.ai_protocol = IPPROTO_ICMP;
  362 
  363     res = getaddrinfo(name, NULL, &hints, &res_info);
  364 
  365     if (res != 0) {
  366         fprintf(stderr, "%s: cannot resolve %s: %s\n", prog_name, name, gai_strerror(res));
  367 
  368         return false;
  369     } else if (res_info->ai_addr == NULL || res_info->ai_addrlen != sizeof(*addr4)) {
  370         freeaddrinfo(res_info);
  371 
  372         fprintf(stderr, "%s: getaddrinfo() returned an illegal address\n", prog_name);
  373 
  374         return false;
  375     } else {
  376         memcpy(addr4, res_info->ai_addr, sizeof(*addr4));
  377 
  378         freeaddrinfo(res_info);
  379 
  380         return true;
  381     }
  382 }
  383 
  384 static bool resolve_name6(char *name, struct sockaddr_in6 *addr6)
  385 {
  386     int              res;
  387     struct addrinfo  hints;
  388     struct addrinfo *res_info;
  389 
  390     memset(&hints, 0, sizeof(hints));
  391 
  392     hints.ai_flags    = AI_CANONNAME;
  393     hints.ai_family   = AF_INET6;
  394     hints.ai_socktype = SOCK_RAW;
  395     hints.ai_protocol = IPPROTO_ICMPV6;
  396 
  397     res = getaddrinfo(name, NULL, &hints, &res_info);
  398 
  399     if (res != 0) {
  400         fprintf(stderr, "%s: cannot resolve %s: %s\n", prog_name, name, gai_strerror(res));
  401 
  402         return false;
  403     } else if (res_info->ai_addr == NULL || res_info->ai_addrlen != sizeof(*addr6)) {
  404         freeaddrinfo(res_info);
  405 
  406         fprintf(stderr, "%s: getaddrinfo() returned an illegal address\n", prog_name);
  407 
  408         return false;
  409     } else {
  410         memcpy(addr6, res_info->ai_addr, sizeof(*addr6));
  411 
  412         freeaddrinfo(res_info);
  413 
  414         return true;
  415     }
  416 }
  417 
  418 int main(int argc, char **argv)
  419 {
  420     bool                ipv4_mode, finish;
  421     int                 exit_val, sock, ch, n;
  422     unsigned int        buf_size, tos_or_traf_class;
  423     size_t              pkt_size;
  424     uint16_t            ident;
  425     int32_t             reporting_period;
  426     uint32_t            kbps, transmitted_number, received_number, pkt_burst, pkt_burst_error, i;
  427     int64_t             min_interval, interval, current_interval, interval_error, select_timeout;
  428     uint64_t            volume, transmitted_volume, received_volume;
  429     char               *bind_addr,
  430                        *target,
  431                        *ep;
  432     char                p_addr4[INET_ADDRSTRLEN],
  433                         p_addr6[INET6_ADDRSTRLEN];
  434     fd_set              fds;
  435     struct sockaddr_in  bind_to4, to4;
  436     struct sockaddr_in6 bind_to6, to6;
  437     struct timeval      timeout;
  438     struct timespec     begin, end, report, start, now;
  439 
  440     prog_name = basename(argv[0]);
  441 
  442     ipv4_mode         = (strcmp(prog_name, "bwping") == 0);
  443     buf_size          = 0;
  444     tos_or_traf_class = 0;
  445     pkt_size          = 0;
  446     reporting_period  = 0;
  447     kbps              = 0;
  448     volume            = 0;
  449     bind_addr         = NULL;
  450     target            = NULL;
  451 
  452     exit_val = EX_OK;
  453 
  454     while ((ch = getopt(argc, argv, "46B:T:b:r:s:u:v:")) != -1) {
  455         switch (ch) {
  456             case '4':
  457                 ipv4_mode = true;
  458 
  459                 break;
  460             case '6':
  461                 ipv4_mode = false;
  462 
  463                 break;
  464             case 'B':
  465                 bind_addr = optarg;
  466 
  467                 break;
  468             case 'T':
  469                 tos_or_traf_class = strtoul(optarg, &ep, 0);
  470 
  471                 if (*ep || ep == optarg) {
  472                     exit_val = EX_USAGE;
  473                 }
  474 
  475                 break;
  476             case 'b':
  477                 kbps = strtoul(optarg, &ep, 0);
  478 
  479                 if (*ep || ep == optarg) {
  480                     exit_val = EX_USAGE;
  481                 }
  482 
  483                 break;
  484             case 'r':
  485                 reporting_period = strtol(optarg, &ep, 0);
  486 
  487                 if (*ep || ep == optarg || reporting_period < 0) {
  488                     exit_val = EX_USAGE;
  489                 }
  490 
  491                 break;
  492             case 's':
  493                 pkt_size = strtoul(optarg, &ep, 0);
  494 
  495                 if (*ep || ep == optarg) {
  496                     exit_val = EX_USAGE;
  497                 }
  498 
  499                 break;
  500             case 'u':
  501                 buf_size = strtoul(optarg, &ep, 0);
  502 
  503                 if (*ep || ep == optarg) {
  504                     exit_val = EX_USAGE;
  505                 }
  506 
  507                 break;
  508             case 'v':
  509                 volume = strtoull(optarg, &ep, 0);
  510 
  511                 if (*ep || ep == optarg) {
  512                     exit_val = EX_USAGE;
  513                 }
  514 
  515                 break;
  516             default:
  517                 exit_val = EX_USAGE;
  518         }
  519     }
  520 
  521     if (argc - optind == 1) {
  522         target = argv[optind];
  523     }
  524 
  525     if (pkt_size == 0 || kbps == 0 || volume == 0 || target == NULL) {
  526         exit_val = EX_USAGE;
  527     }
  528 
  529     if (exit_val != EX_OK) {
  530         fprintf(stderr, "Usage: %s [-4 | -6] [-u buf_size] [-r reporting_period] [-T tos(v4) | traf_class(v6)] [-B bind_addr] -b kbps -s pkt_size -v volume target\n", prog_name);
  531 
  532         exit(exit_val);
  533     }
  534 
  535     if (ipv4_mode) {
  536         if (pkt_size < sizeof(struct icmp) + sizeof(struct timespec) || pkt_size > IP_MAXPACKET - MAX_IPV4_HDR_SIZE) {
  537             fprintf(stderr, "%s: invalid packet size, should be between %zu and %zu\n", prog_name,
  538                                                                                         sizeof(struct icmp) + sizeof(struct timespec),
  539                                                                                         (size_t)IP_MAXPACKET - MAX_IPV4_HDR_SIZE);
  540             exit(EX_USAGE);
  541         }
  542     } else {
  543         if (pkt_size < sizeof(struct icmp6_hdr) + sizeof(struct timespec) || pkt_size > IP_MAXPACKET) {
  544             fprintf(stderr, "%s: invalid packet size, should be between %zu and %zu\n", prog_name,
  545                                                                                         sizeof(struct icmp6_hdr) + sizeof(struct timespec),
  546                                                                                         (size_t)IP_MAXPACKET);
  547             exit(EX_USAGE);
  548         }
  549     }
  550 
  551     if (ipv4_mode) {
  552         sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  553 
  554         if (sock < 0) {
  555             fprintf(stderr, "%s: socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) failed: %s\n", prog_name, strerror(errno));
  556 
  557             exit(EX_OSERR);
  558         }
  559     } else {
  560         sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
  561 
  562         if (sock < 0) {
  563             fprintf(stderr, "%s: socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6) failed: %s\n", prog_name, strerror(errno));
  564 
  565             exit(EX_OSERR);
  566         }
  567     }
  568 
  569     if (setuid(getuid()) < 0) {
  570         fprintf(stderr, "%s: setuid(getuid()) failed: %s\n", prog_name, strerror(errno));
  571 
  572         exit_val = EX_OSERR;
  573     } else {
  574         if (bind_addr != NULL) {
  575             if (ipv4_mode) {
  576                 if (resolve_name4(bind_addr, &bind_to4)) {
  577                     if (bind(sock, (struct sockaddr *)&bind_to4, sizeof(bind_to4)) < 0) {
  578                         fprintf(stderr, "%s: bind() failed: %s\n", prog_name, strerror(errno));
  579 
  580                         exit_val = EX_OSERR;
  581                     }
  582                 } else {
  583                     exit_val = EX_SOFTWARE;
  584                 }
  585             } else {
  586                 if (resolve_name6(bind_addr, &bind_to6)) {
  587                     if (bind(sock, (struct sockaddr *)&bind_to6, sizeof(bind_to6)) < 0) {
  588                         fprintf(stderr, "%s: bind() failed: %s\n", prog_name, strerror(errno));
  589 
  590                         exit_val = EX_OSERR;
  591                     }
  592                 } else {
  593                     exit_val = EX_SOFTWARE;
  594                 }
  595             }
  596         }
  597 
  598         if (exit_val == EX_OK) {
  599             if (ipv4_mode ? resolve_name4(target, &to4) :
  600                             resolve_name6(target, &to6)) {
  601                 ident = getpid() & 0xFFFF;
  602 
  603                 if (ipv4_mode) {
  604                     if (inet_ntop(AF_INET, &(to4.sin_addr), p_addr4, sizeof(p_addr4)) == NULL) {
  605                         p_addr4[0] = '?';
  606                         p_addr4[1] = 0;
  607                     }
  608 
  609                     printf("Target: %s (%s), transfer speed: %" PRIu32 " kbps, packet size: %zu bytes, traffic volume: %" PRIu64 " bytes\n",
  610                            target, p_addr4, kbps, pkt_size, volume);
  611                 } else {
  612                     if (inet_ntop(AF_INET6, &(to6.sin6_addr), p_addr6, sizeof(p_addr6)) == NULL) {
  613                         p_addr6[0] = '?';
  614                         p_addr6[1] = 0;
  615                     }
  616 
  617                     printf("Target: %s (%s), transfer speed: %" PRIu32 " kbps, packet size: %zu bytes, traffic volume: %" PRIu64 " bytes\n",
  618                            target, p_addr6, kbps, pkt_size, volume);
  619                 }
  620 
  621                 min_rtt     = INT64_MAX;
  622                 max_rtt     = 0;
  623                 average_rtt = 0;
  624 
  625                 finish             = false;
  626                 transmitted_number = 0;
  627                 received_number    = 0;
  628                 transmitted_volume = 0;
  629                 received_volume    = 0;
  630 
  631                 interval = (int64_t)pkt_size * 8000 / kbps;
  632 
  633                 min_interval = calibrate_timer();
  634 
  635                 if (interval >= min_interval) {
  636                     pkt_burst = PKT_BURST_PRECISION * 1;
  637                 } else if (interval == 0) {
  638                     pkt_burst = PKT_BURST_PRECISION * min_interval * kbps / 8000 / pkt_size;
  639                     interval  = min_interval;
  640                 } else {
  641                     pkt_burst = PKT_BURST_PRECISION * min_interval / interval;
  642                     interval  = min_interval;
  643                 }
  644 
  645                 if (buf_size == 0) {
  646                     buf_size = pkt_size * (pkt_burst / PKT_BURST_PRECISION + 1) * BUF_SIZE_RESERVE_FACTOR;
  647                 }
  648 
  649                 if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(buf_size)) < 0) {
  650                     fprintf(stderr, "%s: setsockopt(SO_RCVBUF, %u) failed: %s\n", prog_name, buf_size, strerror(errno));
  651                 }
  652                 if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)) < 0) {
  653                     fprintf(stderr, "%s: setsockopt(SO_SNDBUF, %u) failed: %s\n", prog_name, buf_size, strerror(errno));
  654                 }
  655 
  656                 if (ipv4_mode) {
  657                     if (setsockopt(sock, IPPROTO_IP, IP_TOS, &tos_or_traf_class, sizeof(tos_or_traf_class)) < 0) {
  658                         fprintf(stderr, "%s: setsockopt(IP_TOS, %u) failed: %s\n", prog_name, tos_or_traf_class, strerror(errno));
  659                     }
  660                 } else {
  661                     if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &tos_or_traf_class, sizeof(tos_or_traf_class)) < 0) {
  662                         fprintf(stderr, "%s: setsockopt(IPV6_TCLASS, %u) failed: %s\n", prog_name, tos_or_traf_class, strerror(errno));
  663                     }
  664                 }
  665 
  666                 get_time(&begin);
  667                 get_time(&end);
  668                 get_time(&report);
  669 
  670                 current_interval = interval;
  671                 pkt_burst_error  = 0;
  672                 interval_error   = 0;
  673 
  674                 while (!finish) {
  675                     get_time(&start);
  676 
  677                     for (i = 0; i < pkt_burst / PKT_BURST_PRECISION + pkt_burst_error / PKT_BURST_PRECISION; i++) {
  678                         if ((uint64_t)pkt_size * transmitted_number < volume) {
  679                             if (ipv4_mode) {
  680                                 send_ping4(sock, &to4, pkt_size, ident, !i, &transmitted_number, &transmitted_volume);
  681                             } else {
  682                                 send_ping6(sock, &to6, pkt_size, ident, !i, &transmitted_number, &transmitted_volume);
  683                             }
  684                         }
  685                     }
  686 
  687                     pkt_burst_error  = pkt_burst_error % PKT_BURST_PRECISION;
  688                     pkt_burst_error += pkt_burst       % PKT_BURST_PRECISION;
  689 
  690                     select_timeout = current_interval;
  691 
  692                     while (1) {
  693                         FD_ZERO(&fds);
  694                         FD_SET(sock, &fds);
  695 
  696                         timeout.tv_sec  = select_timeout / 1000000;
  697                         timeout.tv_usec = select_timeout % 1000000;
  698 
  699                         n = select(sock + 1, &fds, NULL, NULL, &timeout);
  700 
  701                         if (n > 0) {
  702                             while (ipv4_mode ? recv_ping4(sock, ident, &received_number, &received_volume) :
  703                                                recv_ping6(sock, ident, &received_number, &received_volume)) {
  704                                 if (received_number >= transmitted_number) {
  705                                     break;
  706                                 }
  707                             }
  708                         }
  709 
  710                         get_time(&now);
  711 
  712                         if (ts_sub(&now, &start) >= current_interval) {
  713                             if ((uint64_t)pkt_size * transmitted_number >= volume) {
  714                                 finish = true;
  715                             } else {
  716                                 interval_error += ts_sub(&now, &start) - current_interval;
  717 
  718                                 if (interval_error >= interval / 2) {
  719                                     current_interval  = interval / 2;
  720                                     interval_error   -= interval / 2;
  721                                 } else {
  722                                     current_interval = interval;
  723                                 }
  724                             }
  725 
  726                             break;
  727                         } else {
  728                             select_timeout = current_interval - ts_sub(&now, &start);
  729                         }
  730                     }
  731 
  732                     get_time(&end);
  733 
  734                     if (reporting_period != 0 && end.tv_sec - report.tv_sec >= reporting_period) {
  735                         printf("Periodic: pkts sent/rcvd: %" PRIu32 "/%" PRIu32 ", volume sent/rcvd: %" PRIu64 "/%" PRIu64 " bytes, time: %ld sec, speed: %" PRIu64 " kbps, rtt min/max/average: %" PRId64 "/%" PRId64 "/%" PRId64 " ms\n",
  736                                transmitted_number, received_number, transmitted_volume, received_volume, (long int)(end.tv_sec - begin.tv_sec),
  737                                end.tv_sec - begin.tv_sec ? ((received_volume / (end.tv_sec - begin.tv_sec)) * 8) / 1000 : (received_volume * 8) / 1000,
  738                                min_rtt == INT64_MAX ? 0 : min_rtt, max_rtt, average_rtt);
  739 
  740                         get_time(&report);
  741                     }
  742                 }
  743 
  744                 printf("Total: pkts sent/rcvd: %" PRIu32 "/%" PRIu32 ", volume sent/rcvd: %" PRIu64 "/%" PRIu64 " bytes, time: %ld sec, speed: %" PRIu64 " kbps, rtt min/max/average: %" PRId64 "/%" PRId64 "/%" PRId64 " ms\n",
  745                        transmitted_number, received_number, transmitted_volume, received_volume, (long int)(end.tv_sec - begin.tv_sec),
  746                        end.tv_sec - begin.tv_sec ? ((received_volume / (end.tv_sec - begin.tv_sec)) * 8) / 1000 : (received_volume * 8) / 1000,
  747                        min_rtt == INT64_MAX ? 0 : min_rtt, max_rtt, average_rtt);
  748             } else {
  749                 exit_val = EX_SOFTWARE;
  750             }
  751         }
  752     }
  753 
  754     close(sock);
  755 
  756     exit(exit_val);
  757 }