Diff for /embedaddon/iperf/src/iperf_api.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2021/03/17 00:36:46 version 1.1.1.3, 2023/09/27 11:14:54
Line 1 Line 1
 /*  /*
 * iperf, Copyright (c) 2014-2020, The Regents of the University of * iperf, Copyright (c) 2014-2022, The Regents of the University of
  * California, through Lawrence Berkeley National Laboratory (subject   * California, through Lawrence Berkeley National Laboratory (subject
  * to receipt of any required approvals from the U.S. Dept. of   * to receipt of any required approvals from the U.S. Dept. of
  * Energy).  All rights reserved.   * Energy).  All rights reserved.
Line 49 Line 49
 #ifdef HAVE_STDINT_H  #ifdef HAVE_STDINT_H
 #include <stdint.h>  #include <stdint.h>
 #endif  #endif
 #include <netinet/tcp.h>  
 #include <sys/time.h>  #include <sys/time.h>
 #include <sys/resource.h>  #include <sys/resource.h>
 #include <sys/mman.h>  #include <sys/mman.h>
Line 89 Line 88
 #include "version.h"  #include "version.h"
 #if defined(HAVE_SSL)  #if defined(HAVE_SSL)
 #include <openssl/bio.h>  #include <openssl/bio.h>
   #include <openssl/err.h>
 #include "iperf_auth.h"  #include "iperf_auth.h"
 #endif /* HAVE_SSL */  #endif /* HAVE_SSL */
   
Line 116  usage() Line 116  usage()
 void  void
 usage_long(FILE *f)  usage_long(FILE *f)
 {  {
    fprintf(f, usage_longstr, UDP_RATE / (1024*1024), DURATION, DEFAULT_TCP_BLKSIZE / 1024, DEFAULT_UDP_BLKSIZE);    fprintf(f, usage_longstr, DEFAULT_NO_MSG_RCVD_TIMEOUT, UDP_RATE / (1024*1024), DEFAULT_PACING_TIMER, DURATION, DEFAULT_TCP_BLKSIZE / 1024, DEFAULT_UDP_BLKSIZE);
 }  }
   
   
Line 225  iperf_get_test_reverse(struct iperf_test *ipt) Line 225  iperf_get_test_reverse(struct iperf_test *ipt)
 }  }
   
 int  int
   iperf_get_test_bidirectional(struct iperf_test *ipt)
   {
       return ipt->bidirectional;
   }
   
   int
 iperf_get_test_blksize(struct iperf_test *ipt)  iperf_get_test_blksize(struct iperf_test *ipt)
 {  {
     return ipt->settings->blksize;      return ipt->settings->blksize;
Line 279  iperf_get_test_repeating_payload(struct iperf_test *ip Line 285  iperf_get_test_repeating_payload(struct iperf_test *ip
 }  }
   
 int  int
   iperf_get_test_bind_port(struct iperf_test *ipt)
   {
       return ipt->bind_port;
   }
   
   int
 iperf_get_test_server_port(struct iperf_test *ipt)  iperf_get_test_server_port(struct iperf_test *ipt)
 {  {
     return ipt->server_port;      return ipt->server_port;
Line 338  iperf_get_test_bind_address(struct iperf_test *ipt) Line 350  iperf_get_test_bind_address(struct iperf_test *ipt)
     return ipt->bind_address;      return ipt->bind_address;
 }  }
   
   char *
   iperf_get_test_bind_dev(struct iperf_test *ipt)
   {
       return ipt->bind_dev;
   }
   
 int  int
 iperf_get_test_udp_counters_64bit(struct iperf_test *ipt)  iperf_get_test_udp_counters_64bit(struct iperf_test *ipt)
 {  {
Line 381  iperf_get_test_connect_timeout(struct iperf_test *ipt) Line 399  iperf_get_test_connect_timeout(struct iperf_test *ipt)
     return ipt->settings->connect_timeout;      return ipt->settings->connect_timeout;
 }  }
   
   int
   iperf_get_test_idle_timeout(struct iperf_test *ipt)
   {
       return ipt->settings->idle_timeout;
   }
   
   int
   iperf_get_dont_fragment(struct iperf_test *ipt)
   {
       return ipt->settings->dont_fragment;
   }
   
   struct iperf_time*
   iperf_get_test_rcv_timeout(struct iperf_test *ipt)
   {
       return &ipt->settings->rcv_timeout;
   }
   
   char*
   iperf_get_test_congestion_control(struct iperf_test* ipt)
   {
       return ipt->congestion;
   }
   
   int
   iperf_get_test_mss(struct iperf_test *ipt)
   {
       return ipt->settings->mss;
   }
   
   int
   iperf_get_mapped_v4(struct iperf_test* ipt)
   {
       return ipt->mapped_v4;
   }
   
 /************** Setter routines for some fields inside iperf_test *************/  /************** Setter routines for some fields inside iperf_test *************/
   
 void  void
Line 492  iperf_set_test_burst(struct iperf_test *ipt, int burst Line 546  iperf_set_test_burst(struct iperf_test *ipt, int burst
 }  }
   
 void  void
   iperf_set_test_bind_port(struct iperf_test *ipt, int bind_port)
   {
       ipt->bind_port = bind_port;
   }
   
   void
 iperf_set_test_server_port(struct iperf_test *ipt, int srv_port)  iperf_set_test_server_port(struct iperf_test *ipt, int srv_port)
 {  {
     ipt->server_port = srv_port;      ipt->server_port = srv_port;
Line 527  iperf_set_test_timestamp_format(struct iperf_test *ipt Line 587  iperf_set_test_timestamp_format(struct iperf_test *ipt
     ipt->timestamp_format = strdup(tf);      ipt->timestamp_format = strdup(tf);
 }  }
   
   void
   iperf_set_mapped_v4(struct iperf_test *ipt, const int val)
   {
       ipt->mapped_v4 = val;
   }
   
   void 
   iperf_set_on_new_stream_callback(struct iperf_test* ipt, void (*callback)())
   {
           ipt->on_new_stream = callback;
   }
   
   void 
   iperf_set_on_test_start_callback(struct iperf_test* ipt, void (*callback)())
   {
           ipt->on_test_start = callback;
   }
   
   void 
   iperf_set_on_test_connect_callback(struct iperf_test* ipt, void (*callback)())
   {
           ipt->on_connect = callback;
   }
   
   void 
   iperf_set_on_test_finish_callback(struct iperf_test* ipt, void (*callback)())
   {
           ipt->on_test_finish = callback;
   }
   
 static void  static void
 check_sender_has_retransmits(struct iperf_test *ipt)  check_sender_has_retransmits(struct iperf_test *ipt)
 {  {
Line 642  iperf_set_test_server_authorized_users(struct iperf_te Line 732  iperf_set_test_server_authorized_users(struct iperf_te
 }  }
   
 void  void
   iperf_set_test_server_skew_threshold(struct iperf_test *ipt, int server_skew_threshold)
   {
       ipt->server_skew_threshold = server_skew_threshold;
   }
   
   void
 iperf_set_test_server_rsa_privkey(struct iperf_test *ipt, const char *server_rsa_privkey_base64)  iperf_set_test_server_rsa_privkey(struct iperf_test *ipt, const char *server_rsa_privkey_base64)
 {  {
     ipt->server_rsa_private_key = load_privkey_from_base64(server_rsa_privkey_base64);      ipt->server_rsa_private_key = load_privkey_from_base64(server_rsa_privkey_base64);
Line 655  iperf_set_test_bind_address(struct iperf_test *ipt, co Line 751  iperf_set_test_bind_address(struct iperf_test *ipt, co
 }  }
   
 void  void
   iperf_set_test_bind_dev(struct iperf_test *ipt, const char *bnd_dev)
   {
       ipt->bind_dev = strdup(bnd_dev);
   }
   
   void
 iperf_set_test_udp_counters_64bit(struct iperf_test *ipt, int udp_counters_64bit)  iperf_set_test_udp_counters_64bit(struct iperf_test *ipt, int udp_counters_64bit)
 {  {
     ipt->udp_counters_64bit = udp_counters_64bit;      ipt->udp_counters_64bit = udp_counters_64bit;
Line 700  iperf_set_test_connect_timeout(struct iperf_test* ipt, Line 802  iperf_set_test_connect_timeout(struct iperf_test* ipt,
     ipt->settings->connect_timeout = ct;      ipt->settings->connect_timeout = ct;
 }  }
   
   void
   iperf_set_test_idle_timeout(struct iperf_test* ipt, int to)
   {
       ipt->settings->idle_timeout = to;
   }
   
   void
   iperf_set_dont_fragment(struct iperf_test* ipt, int dnf)
   {
       ipt->settings->dont_fragment = dnf;
   }
   
   void
   iperf_set_test_rcv_timeout(struct iperf_test* ipt, struct iperf_time* to)
   {
       ipt->settings->rcv_timeout.secs = to->secs;
       ipt->settings->rcv_timeout.usecs = to->usecs;
   }
   
   void
   iperf_set_test_congestion_control(struct iperf_test* ipt, char* cc)
   {
       ipt->congestion = strdup(cc);
   }
   
   void
   iperf_set_test_mss(struct iperf_test *ipt, int mss)
   {
       ipt->settings->mss = mss;
   }
   
 /********************** Get/set test protocol structure ***********************/  /********************** Get/set test protocol structure ***********************/
   
 struct protocol *  struct protocol *
Line 749  void Line 881  void
 iperf_on_test_start(struct iperf_test *test)  iperf_on_test_start(struct iperf_test *test)
 {  {
     if (test->json_output) {      if (test->json_output) {
        cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s  num_streams: %d  blksize: %d  omit: %d  duration: %d  bytes: %d  blocks: %d  reverse: %d  tos: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->omit, (int64_t) test->duration, (int64_t) test->settings->bytes, (int64_t) test->settings->blocks, test->reverse?(int64_t)1:(int64_t)0, (int64_t) test->settings->tos));        cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s  num_streams: %d  blksize: %d  omit: %d  duration: %d  bytes: %d  blocks: %d  reverse: %d  tos: %d  target_bitrate: %d bidir: %d fqrate: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->omit, (int64_t) test->duration, (int64_t) test->settings->bytes, (int64_t) test->settings->blocks, test->reverse?(int64_t)1:(int64_t)0, (int64_t) test->settings->tos, (int64_t) test->settings->rate, (int64_t) test->bidirectional, (uint64_t) test->settings->fqrate));
     } else {      } else {
         if (test->verbose) {          if (test->verbose) {
             if (test->settings->bytes)              if (test->settings->bytes)
Line 766  iperf_on_test_start(struct iperf_test *test) Line 898  iperf_on_test_start(struct iperf_test *test)
 ** old IPv4 format, which is easier on the eyes of network veterans.  ** old IPv4 format, which is easier on the eyes of network veterans.
 **  **
 ** If the v6 address is not v4-mapped it is left alone.  ** If the v6 address is not v4-mapped it is left alone.
   **
   ** Returns 1 if the v6 address is v4-mapped, 0 otherwise.
 */  */
static voidstatic int
 mapped_v4_to_regular_v4(char *str)  mapped_v4_to_regular_v4(char *str)
 {  {
     char *prefix = "::ffff:";      char *prefix = "::ffff:";
Line 777  mapped_v4_to_regular_v4(char *str) Line 911  mapped_v4_to_regular_v4(char *str)
     if (strncmp(str, prefix, prefix_len) == 0) {      if (strncmp(str, prefix, prefix_len) == 0) {
         int str_len = strlen(str);          int str_len = strlen(str);
         memmove(str, str + prefix_len, str_len - prefix_len + 1);          memmove(str, str + prefix_len, str_len - prefix_len + 1);
           return 1;
     }      }
       return 0;
 }  }
   
 void  void
Line 820  iperf_on_connect(struct iperf_test *test) Line 956  iperf_on_connect(struct iperf_test *test)
             inet_ntop(AF_INET6, &sa_in6P->sin6_addr, ipr, sizeof(ipr));              inet_ntop(AF_INET6, &sa_in6P->sin6_addr, ipr, sizeof(ipr));
             port = ntohs(sa_in6P->sin6_port);              port = ntohs(sa_in6P->sin6_port);
         }          }
        mapped_v4_to_regular_v4(ipr);        if (mapped_v4_to_regular_v4(ipr)) {
             iperf_set_mapped_v4(test, 1);
         }
         if (test->json_output)          if (test->json_output)
             cJSON_AddItemToObject(test->json_start, "accepted_connection", iperf_json_printf("host: %s  port: %d", ipr, (int64_t) port));              cJSON_AddItemToObject(test->json_start, "accepted_connection", iperf_json_printf("host: %s  port: %d", ipr, (int64_t) port));
         else          else
Line 834  iperf_on_connect(struct iperf_test *test) Line 972  iperf_on_connect(struct iperf_test *test)
             else {              else {
                 cJSON_AddNumberToObject(test->json_start, "tcp_mss_default", test->ctrl_sck_mss);                  cJSON_AddNumberToObject(test->json_start, "tcp_mss_default", test->ctrl_sck_mss);
             }              }
         if (test->settings->rate)  
             cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);  
         }          }
           // Duplicate to make sure it appears on all output
           cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);
           cJSON_AddNumberToObject(test->json_start, "fq_rate", test->settings->fqrate);
     } else if (test->verbose) {      } else if (test->verbose) {
         iperf_printf(test, report_cookie, test->cookie);          iperf_printf(test, report_cookie, test->cookie);
         if (test->protocol->id == SOCK_STREAM) {          if (test->protocol->id == SOCK_STREAM) {
Line 859  iperf_on_test_finish(struct iperf_test *test) Line 998  iperf_on_test_finish(struct iperf_test *test)
   
 /******************************************************************************/  /******************************************************************************/
   
   /*
    * iperf_parse_hostname tries to split apart a string into hostname %
    * interface parts, which are returned in **p and **p1, if they
    * exist. If the %interface part is detected, and it's not an IPv6
    * link local address, then returns 1, else returns 0.
    *
    * Modifies the string pointed to by spec in-place due to the use of
    * strtok(3). The caller should strdup(3) or otherwise copy the string
    * if an unmodified copy is needed.
    */
 int  int
   iperf_parse_hostname(struct iperf_test *test, char *spec, char **p, char **p1) {
       struct in6_addr ipv6_addr;
   
       // Format is <addr>[%<device>]
       if ((*p = strtok(spec, "%")) != NULL &&
           (*p1 = strtok(NULL, "%")) != NULL) {
   
           /*
            * If an IPv6 literal for a link-local address, then
            * tell the caller to leave the "%" in the hostname.
            */
           if (inet_pton(AF_INET6, *p, &ipv6_addr) == 1 &&
               IN6_IS_ADDR_LINKLOCAL(&ipv6_addr)) {
               if (test->debug) {
                   iperf_printf(test, "IPv6 link-local address literal detected\n");
               }
               return 0;
           }
           /*
            * Other kind of address or FQDN. The interface name after
            * "%" is a shorthand for --bind-dev.
            */
           else {
               if (test->debug) {
                   iperf_printf(test, "p %s p1 %s\n", *p, *p1);
               }
               return 1;
           }
       }
       else {
           if (test->debug) {
               iperf_printf(test, "noparse\n");
           }
           return 0;
       }
   }
   
   int
 iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)  iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
 {  {
     static struct option longopts[] =      static struct option longopts[] =
Line 887  iperf_parse_arguments(struct iperf_test *test, int arg Line 1074  iperf_parse_arguments(struct iperf_test *test, int arg
         {"bidir", no_argument, NULL, OPT_BIDIRECTIONAL},          {"bidir", no_argument, NULL, OPT_BIDIRECTIONAL},
         {"window", required_argument, NULL, 'w'},          {"window", required_argument, NULL, 'w'},
         {"bind", required_argument, NULL, 'B'},          {"bind", required_argument, NULL, 'B'},
   #if defined(HAVE_SO_BINDTODEVICE)
           {"bind-dev", required_argument, NULL, OPT_BIND_DEV},
   #endif /* HAVE_SO_BINDTODEVICE */
         {"cport", required_argument, NULL, OPT_CLIENT_PORT},          {"cport", required_argument, NULL, OPT_CLIENT_PORT},
         {"set-mss", required_argument, NULL, 'M'},          {"set-mss", required_argument, NULL, 'M'},
         {"no-delay", no_argument, NULL, 'N'},          {"no-delay", no_argument, NULL, 'N'},
Line 922  iperf_parse_arguments(struct iperf_test *test, int arg Line 1112  iperf_parse_arguments(struct iperf_test *test, int arg
         {"get-server-output", no_argument, NULL, OPT_GET_SERVER_OUTPUT},          {"get-server-output", no_argument, NULL, OPT_GET_SERVER_OUTPUT},
         {"udp-counters-64bit", no_argument, NULL, OPT_UDP_COUNTERS_64BIT},          {"udp-counters-64bit", no_argument, NULL, OPT_UDP_COUNTERS_64BIT},
         {"no-fq-socket-pacing", no_argument, NULL, OPT_NO_FQ_SOCKET_PACING},          {"no-fq-socket-pacing", no_argument, NULL, OPT_NO_FQ_SOCKET_PACING},
   #if defined(HAVE_DONT_FRAGMENT)
           {"dont-fragment", no_argument, NULL, OPT_DONT_FRAGMENT},
   #endif /* HAVE_DONT_FRAGMENT */
 #if defined(HAVE_SSL)  #if defined(HAVE_SSL)
     {"username", required_argument, NULL, OPT_CLIENT_USERNAME},      {"username", required_argument, NULL, OPT_CLIENT_USERNAME},
     {"rsa-public-key-path", required_argument, NULL, OPT_CLIENT_RSA_PUBLIC_KEY},      {"rsa-public-key-path", required_argument, NULL, OPT_CLIENT_RSA_PUBLIC_KEY},
     {"rsa-private-key-path", required_argument, NULL, OPT_SERVER_RSA_PRIVATE_KEY},      {"rsa-private-key-path", required_argument, NULL, OPT_SERVER_RSA_PRIVATE_KEY},
     {"authorized-users-path", required_argument, NULL, OPT_SERVER_AUTHORIZED_USERS},      {"authorized-users-path", required_argument, NULL, OPT_SERVER_AUTHORIZED_USERS},
       {"time-skew-threshold", required_argument, NULL, OPT_SERVER_SKEW_THRESHOLD},
 #endif /* HAVE_SSL */  #endif /* HAVE_SSL */
         {"fq-rate", required_argument, NULL, OPT_FQ_RATE},          {"fq-rate", required_argument, NULL, OPT_FQ_RATE},
         {"pacing-timer", required_argument, NULL, OPT_PACING_TIMER},          {"pacing-timer", required_argument, NULL, OPT_PACING_TIMER},
         {"connect-timeout", required_argument, NULL, OPT_CONNECT_TIMEOUT},          {"connect-timeout", required_argument, NULL, OPT_CONNECT_TIMEOUT},
        {"debug", no_argument, NULL, 'd'},        {"idle-timeout", required_argument, NULL, OPT_IDLE_TIMEOUT},
         {"rcv-timeout", required_argument, NULL, OPT_RCV_TIMEOUT},
         {"snd-timeout", required_argument, NULL, OPT_SND_TIMEOUT},
         {"debug", optional_argument, NULL, 'd'},
         {"help", no_argument, NULL, 'h'},          {"help", no_argument, NULL, 'h'},
         {NULL, 0, NULL, 0}          {NULL, 0, NULL, 0}
     };      };
     int flag;      int flag;
     int portno;      int portno;
     int blksize;      int blksize;
    int server_flag, client_flag, rate_flag, duration_flag;    int server_flag, client_flag, rate_flag, duration_flag, rcv_timeout_flag, snd_timeout_flag;
     char *endptr;      char *endptr;
 #if defined(HAVE_CPU_AFFINITY)  #if defined(HAVE_CPU_AFFINITY)
     char* comma;      char* comma;
 #endif /* HAVE_CPU_AFFINITY */  #endif /* HAVE_CPU_AFFINITY */
     char* slash;      char* slash;
       char *p, *p1;
     struct xbind_entry *xbe;      struct xbind_entry *xbe;
     double farg;      double farg;
       int rcv_timeout_in = 0;
   
     blksize = 0;      blksize = 0;
    server_flag = client_flag = rate_flag = duration_flag = 0;    server_flag = client_flag = rate_flag = duration_flag = rcv_timeout_flag = snd_timeout_flag =0;
 #if defined(HAVE_SSL)  #if defined(HAVE_SSL)
     char *client_username = NULL, *client_rsa_public_key = NULL, *server_rsa_private_key = NULL;      char *client_username = NULL, *client_rsa_public_key = NULL, *server_rsa_private_key = NULL;
 #endif /* HAVE_SSL */  #endif /* HAVE_SSL */
Line 1025  iperf_parse_arguments(struct iperf_test *test, int arg Line 1224  iperf_parse_arguments(struct iperf_test *test, int arg
                 }                  }
                 iperf_set_test_role(test, 'c');                  iperf_set_test_role(test, 'c');
                 iperf_set_test_server_hostname(test, optarg);                  iperf_set_test_server_hostname(test, optarg);
   
                   if (iperf_parse_hostname(test, optarg, &p, &p1)) {
   #if defined(HAVE_SO_BINDTODEVICE)
                       /* Get rid of the hostname we saved earlier. */
                       free(iperf_get_test_server_hostname(test));
                       iperf_set_test_server_hostname(test, p);
                       iperf_set_test_bind_dev(test, p1);
   #else /* HAVE_SO_BINDTODEVICE */
                       i_errno = IEBINDDEVNOSUPPORT;
                       return -1;
   #endif /* HAVE_SO_BINDTODEVICE */
                   }
                 break;                  break;
             case 'u':              case 'u':
                 set_protocol(test, Pudp);                  set_protocol(test, Pudp);
Line 1126  iperf_parse_arguments(struct iperf_test *test, int arg Line 1337  iperf_parse_arguments(struct iperf_test *test, int arg
                 break;                  break;
             case 'w':              case 'w':
                 // XXX: This is a socket buffer, not specific to TCP                  // XXX: This is a socket buffer, not specific to TCP
                // Do sanity checks as double-precision floating point                 // Do sanity checks as double-precision floating point
                 // to avoid possible integer overflows.                  // to avoid possible integer overflows.
                 farg = unit_atof(optarg);                  farg = unit_atof(optarg);
                 if (farg > (double) MAX_TCP_BUFFER) {                  if (farg > (double) MAX_TCP_BUFFER) {
Line 1136  iperf_parse_arguments(struct iperf_test *test, int arg Line 1347  iperf_parse_arguments(struct iperf_test *test, int arg
                 test->settings->socket_bufsize = (int) farg;                  test->settings->socket_bufsize = (int) farg;
                 client_flag = 1;                  client_flag = 1;
                 break;                  break;
   
             case 'B':              case 'B':
                test->bind_address = strdup(optarg);                iperf_set_test_bind_address(test, optarg);
 
                 if (iperf_parse_hostname(test, optarg, &p, &p1)) {
 #if defined(HAVE_SO_BINDTODEVICE)
                     /* Get rid of the hostname we saved earlier. */
                     free(iperf_get_test_bind_address(test));
                     iperf_set_test_bind_address(test, p);
                     iperf_set_test_bind_dev(test, p1);
 #else /* HAVE_SO_BINDTODEVICE */
                     i_errno = IEBINDDEVNOSUPPORT;
                     return -1;
 #endif /* HAVE_SO_BINDTODEVICE */
                 }
                 break;                  break;
   #if defined (HAVE_SO_BINDTODEVICE)
               case OPT_BIND_DEV:
                   iperf_set_test_bind_dev(test, optarg);
                   break;
   #endif /* HAVE_SO_BINDTODEVICE */
             case OPT_CLIENT_PORT:              case OPT_CLIENT_PORT:
                 portno = atoi(optarg);                  portno = atoi(optarg);
                 if (portno < 1 || portno > 65535) {                  if (portno < 1 || portno > 65535) {
Line 1247  iperf_parse_arguments(struct iperf_test *test, int arg Line 1476  iperf_parse_arguments(struct iperf_test *test, int arg
             case 'F':              case 'F':
                 test->diskfile_name = optarg;                  test->diskfile_name = optarg;
                 break;                  break;
               case OPT_IDLE_TIMEOUT:
                   test->settings->idle_timeout = atoi(optarg);
                   if (test->settings->idle_timeout < 1 || test->settings->idle_timeout > MAX_TIME) {
                       i_errno = IEIDLETIMEOUT;
                       return -1;
                   }
                   server_flag = 1;
                   break;
               case OPT_RCV_TIMEOUT:
                   rcv_timeout_in = atoi(optarg);
                   if (rcv_timeout_in < MIN_NO_MSG_RCVD_TIMEOUT || rcv_timeout_in > MAX_TIME * SEC_TO_mS) {
                       i_errno = IERCVTIMEOUT;
                       return -1;
                   }
                   test->settings->rcv_timeout.secs = rcv_timeout_in / SEC_TO_mS;
                   test->settings->rcv_timeout.usecs = (rcv_timeout_in % SEC_TO_mS) * mS_TO_US;
                   rcv_timeout_flag = 1;
                   break;
   #if defined(HAVE_TCP_USER_TIMEOUT)
               case OPT_SND_TIMEOUT:
                   test->settings->snd_timeout = atoi(optarg);
                   if (test->settings->snd_timeout < 0 || test->settings->snd_timeout > MAX_TIME * SEC_TO_mS) {
                       i_errno = IESNDTIMEOUT;
                       return -1;
                   }
                   snd_timeout_flag = 1;
                   break;
   #endif /* HAVE_TCP_USER_TIMEOUT */
             case 'A':              case 'A':
 #if defined(HAVE_CPU_AFFINITY)  #if defined(HAVE_CPU_AFFINITY)
                 test->affinity = strtol(optarg, &endptr, 0);                  test->affinity = strtol(optarg, &endptr, 0);
                if (endptr == optarg ||                 if (endptr == optarg ||
                     test->affinity < 0 || test->affinity > 1024) {                      test->affinity < 0 || test->affinity > 1024) {
                     i_errno = IEAFFINITY;                      i_errno = IEAFFINITY;
                     return -1;                      return -1;
Line 1284  iperf_parse_arguments(struct iperf_test *test, int arg Line 1541  iperf_parse_arguments(struct iperf_test *test, int arg
                 break;                  break;
             case 'd':              case 'd':
                 test->debug = 1;                  test->debug = 1;
                   test->debug_level = DEBUG_LEVEL_MAX;
                   if (optarg) {
                       test->debug_level = atoi(optarg);
                       if (test->debug_level < 0)
                           test->debug_level = DEBUG_LEVEL_MAX;
                   }
                 break;                  break;
             case 'I':              case 'I':
                 test->pidfile = strdup(optarg);                  test->pidfile = strdup(optarg);
                 server_flag = 1;  
                 break;                  break;
             case OPT_LOGFILE:              case OPT_LOGFILE:
                 test->logfile = strdup(optarg);                  test->logfile = strdup(optarg);
Line 1321  iperf_parse_arguments(struct iperf_test *test, int arg Line 1583  iperf_parse_arguments(struct iperf_test *test, int arg
                 return -1;                  return -1;
 #endif  #endif
                 break;                  break;
   #if defined(HAVE_DONT_FRAGMENT)
           case OPT_DONT_FRAGMENT:
               test->settings->dont_fragment = 1;
               client_flag = 1;
               break;
   #endif /* HAVE_DONT_FRAGMENT */
 #if defined(HAVE_SSL)  #if defined(HAVE_SSL)
         case OPT_CLIENT_USERNAME:          case OPT_CLIENT_USERNAME:
             client_username = strdup(optarg);              client_username = strdup(optarg);
Line 1334  iperf_parse_arguments(struct iperf_test *test, int arg Line 1602  iperf_parse_arguments(struct iperf_test *test, int arg
         case OPT_SERVER_AUTHORIZED_USERS:          case OPT_SERVER_AUTHORIZED_USERS:
             test->server_authorized_users = strdup(optarg);              test->server_authorized_users = strdup(optarg);
             break;              break;
           case OPT_SERVER_SKEW_THRESHOLD:
               test->server_skew_threshold = atoi(optarg);
               if(test->server_skew_threshold <= 0){
                   i_errno = IESKEWTHRESHOLD;
                   return -1;
               }
               break;
 #endif /* HAVE_SSL */  #endif /* HAVE_SSL */
             case OPT_PACING_TIMER:              case OPT_PACING_TIMER:
                 test->settings->pacing_timer = unit_atoi(optarg);                  test->settings->pacing_timer = unit_atoi(optarg);
Line 1347  iperf_parse_arguments(struct iperf_test *test, int arg Line 1622  iperf_parse_arguments(struct iperf_test *test, int arg
                 usage_long(stdout);                  usage_long(stdout);
                 exit(0);                  exit(0);
             default:              default:
                usage_long(stderr);                fprintf(stderr, "\n");
                 usage();
                 exit(1);                  exit(1);
         }          }
     }      }
Line 1367  iperf_parse_arguments(struct iperf_test *test, int arg Line 1643  iperf_parse_arguments(struct iperf_test *test, int arg
     if (test->role == 's' && (client_username || client_rsa_public_key)){      if (test->role == 's' && (client_username || client_rsa_public_key)){
         i_errno = IECLIENTONLY;          i_errno = IECLIENTONLY;
         return -1;          return -1;
    } else if (test->role == 'c' && (client_username || client_rsa_public_key) &&     } else if (test->role == 'c' && (client_username || client_rsa_public_key) &&
         !(client_username && client_rsa_public_key)) {          !(client_username && client_rsa_public_key)) {
         i_errno = IESETCLIENTAUTH;          i_errno = IESETCLIENTAUTH;
         return -1;          return -1;
Line 1375  iperf_parse_arguments(struct iperf_test *test, int arg Line 1651  iperf_parse_arguments(struct iperf_test *test, int arg
   
         char *client_password = NULL;          char *client_password = NULL;
         size_t s;          size_t s;
           if (test_load_pubkey_from_file(client_rsa_public_key) < 0){
               iperf_err(test, "%s\n", ERR_error_string(ERR_get_error(), NULL));
               i_errno = IESETCLIENTAUTH;
               return -1;
           }
         /* Need to copy env var, so we can do a common free */          /* Need to copy env var, so we can do a common free */
         if ((client_password = getenv("IPERF3_PASSWORD")) != NULL)          if ((client_password = getenv("IPERF3_PASSWORD")) != NULL)
              client_password = strdup(client_password);               client_password = strdup(client_password);
         else if (iperf_getpass(&client_password, &s, stdin) < 0){          else if (iperf_getpass(&client_password, &s, stdin) < 0){
             i_errno = IESETCLIENTAUTH;              i_errno = IESETCLIENTAUTH;
             return -1;              return -1;
         }   
         if (test_load_pubkey_from_file(client_rsa_public_key) < 0){  
             i_errno = IESETCLIENTAUTH;  
             return -1;  
         }          }
   
         test->settings->client_username = client_username;          test->settings->client_username = client_username;
Line 1397  iperf_parse_arguments(struct iperf_test *test, int arg Line 1674  iperf_parse_arguments(struct iperf_test *test, int arg
     if (test->role == 'c' && (server_rsa_private_key || test->server_authorized_users)){      if (test->role == 'c' && (server_rsa_private_key || test->server_authorized_users)){
         i_errno = IESERVERONLY;          i_errno = IESERVERONLY;
         return -1;          return -1;
    } else if (test->role == 's' && (server_rsa_private_key || test->server_authorized_users) &&     } else if (test->role == 'c' && (test->server_skew_threshold != 0)){
         i_errno = IESERVERONLY;
         return -1;
     } else if (test->role == 'c' && rcv_timeout_flag && test->mode == SENDER){
         i_errno = IERVRSONLYRCVTIMEOUT;
         return -1;
     } else if (test->role == 's' && (server_rsa_private_key || test->server_authorized_users) &&
         !(server_rsa_private_key && test->server_authorized_users)) {          !(server_rsa_private_key && test->server_authorized_users)) {
          i_errno = IESETSERVERAUTH;           i_errno = IESETSERVERAUTH;
         return -1;          return -1;
     } else if (test->role == 's' && server_rsa_private_key) {      } else if (test->role == 's' && server_rsa_private_key) {
         test->server_rsa_private_key = load_privkey_from_file(server_rsa_private_key);          test->server_rsa_private_key = load_privkey_from_file(server_rsa_private_key);
         if (test->server_rsa_private_key == NULL){          if (test->server_rsa_private_key == NULL){
               iperf_err(test, "%s\n", ERR_error_string(ERR_get_error(), NULL));
             i_errno = IESETSERVERAUTH;              i_errno = IESETSERVERAUTH;
             return -1;              return -1;
         }          }
        free(server_rsa_private_key);            free(server_rsa_private_key);
        server_rsa_private_key = NULL;            server_rsa_private_key = NULL;
 
         if(test->server_skew_threshold == 0){
             // Set default value for time skew threshold
             test->server_skew_threshold=10;
         }
     }      }
   
 #endif //HAVE_SSL  #endif //HAVE_SSL
   
       // File cannot be transferred using UDP because of the UDP packets header (packet number, etc.)
       if(test->role == 'c' && test->diskfile_name != (char*) 0 && test->protocol->id == Pudp) {
           i_errno = IEUDPFILETRANSFER;
           return -1;
       }
   
     if (blksize == 0) {      if (blksize == 0) {
         if (test->protocol->id == Pudp)          if (test->protocol->id == Pudp)
             blksize = 0;        /* try to dynamically determine from MSS */              blksize = 0;        /* try to dynamically determine from MSS */
Line 1420  iperf_parse_arguments(struct iperf_test *test, int arg Line 1716  iperf_parse_arguments(struct iperf_test *test, int arg
         else          else
             blksize = DEFAULT_TCP_BLKSIZE;              blksize = DEFAULT_TCP_BLKSIZE;
     }      }
    if ((test->protocol->id != Pudp && blksize <= 0)     if ((test->protocol->id != Pudp && blksize <= 0)
         || blksize > MAX_BLOCKSIZE) {          || blksize > MAX_BLOCKSIZE) {
         i_errno = IEBLOCKSIZE;          i_errno = IEBLOCKSIZE;
         return -1;          return -1;
Line 1436  iperf_parse_arguments(struct iperf_test *test, int arg Line 1732  iperf_parse_arguments(struct iperf_test *test, int arg
     if (!rate_flag)      if (!rate_flag)
         test->settings->rate = test->protocol->id == Pudp ? UDP_RATE : 0;          test->settings->rate = test->protocol->id == Pudp ? UDP_RATE : 0;
   
       /* if no bytes or blocks specified, nor a duration_flag, and we have -F,
       ** get the file-size as the bytes count to be transferred
       */
       if (test->settings->bytes == 0 &&
           test->settings->blocks == 0 &&
           ! duration_flag &&
           test->diskfile_name != (char*) 0 &&
           test->role == 'c'
           ){
           struct stat st;
           if( stat(test->diskfile_name, &st) == 0 ){
               iperf_size_t file_bytes = st.st_size;
               test->settings->bytes = file_bytes;
               if (test->debug)
                   printf("End condition set to file-size: %"PRIu64" bytes\n", test->settings->bytes);
           }
           // if failing to read file stat, it should fallback to default duration mode
       }
   
     if ((test->settings->bytes != 0 || test->settings->blocks != 0) && ! duration_flag)      if ((test->settings->bytes != 0 || test->settings->blocks != 0) && ! duration_flag)
         test->duration = 0;          test->duration = 0;
   
Line 1499  int iperf_open_logfile(struct iperf_test *test) Line 1814  int iperf_open_logfile(struct iperf_test *test)
     return 0;      return 0;
 }  }
   
   void iperf_close_logfile(struct iperf_test *test)
   {
       if (test->outfile && test->outfile != stdout) {
           fclose(test->outfile);
           test->outfile = NULL;
       }
   }
   
 int  int
 iperf_set_send_state(struct iperf_test *test, signed char state)  iperf_set_send_state(struct iperf_test *test, signed char state)
 {  {
    test->state = state;    if (test->ctrl_sck >= 0) {
    if (Nwrite(test->ctrl_sck, (char*) &state, sizeof(state), Ptcp) < 0) {        test->state = state;
        i_errno = IESENDMESSAGE;        if (Nwrite(test->ctrl_sck, (char*) &state, sizeof(state), Ptcp) < 0) {
        return -1;            i_errno = IESENDMESSAGE;
             return -1;
         }
     }      }
     return 0;      return 0;
 }  }
Line 1517  iperf_check_throttle(struct iperf_stream *sp, struct i Line 1842  iperf_check_throttle(struct iperf_stream *sp, struct i
     double seconds;      double seconds;
     uint64_t bits_per_second;      uint64_t bits_per_second;
   
    if (sp->test->done || sp->test->settings->rate == 0 || sp->test->settings->burst != 0)    if (sp->test->done || sp->test->settings->rate == 0)
         return;          return;
     iperf_time_diff(&sp->result->start_time_fixed, nowP, &temp_time);      iperf_time_diff(&sp->result->start_time_fixed, nowP, &temp_time);
     seconds = iperf_time_in_secs(&temp_time);      seconds = iperf_time_in_secs(&temp_time);
Line 1531  iperf_check_throttle(struct iperf_stream *sp, struct i Line 1856  iperf_check_throttle(struct iperf_stream *sp, struct i
     }      }
 }  }
   
/* Verify that average traffic is not greater than the specifid limit *//* Verify that average traffic is not greater than the specified limit */
 void  void
 iperf_check_total_rate(struct iperf_test *test, iperf_size_t last_interval_bytes_transferred)  iperf_check_total_rate(struct iperf_test *test, iperf_size_t last_interval_bytes_transferred)
 {  {
Line 1542  iperf_check_total_rate(struct iperf_test *test, iperf_ Line 1867  iperf_check_total_rate(struct iperf_test *test, iperf_
   
     if (test->done || test->settings->bitrate_limit == 0)    // Continue only if check should be done      if (test->done || test->settings->bitrate_limit == 0)    // Continue only if check should be done
         return;          return;
    
    /* Add last inetrval's transffered bytes to the array */    /* Add last inetrval's transferred bytes to the array */
     if (++test->bitrate_limit_last_interval_index >= test->settings->bitrate_limit_stats_per_interval)      if (++test->bitrate_limit_last_interval_index >= test->settings->bitrate_limit_stats_per_interval)
         test->bitrate_limit_last_interval_index = 0;          test->bitrate_limit_last_interval_index = 0;
     test->bitrate_limit_intervals_traffic_bytes[test->bitrate_limit_last_interval_index] = last_interval_bytes_transferred;      test->bitrate_limit_intervals_traffic_bytes[test->bitrate_limit_last_interval_index] = last_interval_bytes_transferred;
Line 1552  iperf_check_total_rate(struct iperf_test *test, iperf_ Line 1877  iperf_check_total_rate(struct iperf_test *test, iperf_
     test->bitrate_limit_stats_count += 1;      test->bitrate_limit_stats_count += 1;
     if (test->bitrate_limit_stats_count < test->settings->bitrate_limit_stats_per_interval)      if (test->bitrate_limit_stats_count < test->settings->bitrate_limit_stats_per_interval)
         return;          return;
 
      /* Calculating total bytes traffic to be averaged */       /* Calculating total bytes traffic to be averaged */
     for (total_bytes = 0, i = 0; i < test->settings->bitrate_limit_stats_per_interval; i++) {      for (total_bytes = 0, i = 0; i < test->settings->bitrate_limit_stats_per_interval; i++) {
         total_bytes += test->bitrate_limit_intervals_traffic_bytes[i];          total_bytes += test->bitrate_limit_intervals_traffic_bytes[i];
Line 1565  iperf_check_total_rate(struct iperf_test *test, iperf_ Line 1890  iperf_check_total_rate(struct iperf_test *test, iperf_
     }      }
   
     if (bits_per_second  > test->settings->bitrate_limit) {      if (bits_per_second  > test->settings->bitrate_limit) {
        iperf_err(test, "Total throughput of %" PRIu64 " bps exceeded %" PRIu64 " bps limit", bits_per_second, test->settings->bitrate_limit);        if (iperf_get_verbose(test))
             iperf_err(test, "Total throughput of %" PRIu64 " bps exceeded %" PRIu64 " bps limit", bits_per_second, test->settings->bitrate_limit);
         test->bitrate_limit_exceeded = 1;          test->bitrate_limit_exceeded = 1;
     }      }
 }  }
Line 1576  iperf_send(struct iperf_test *test, fd_set *write_setP Line 1902  iperf_send(struct iperf_test *test, fd_set *write_setP
     register int multisend, r, streams_active;      register int multisend, r, streams_active;
     register struct iperf_stream *sp;      register struct iperf_stream *sp;
     struct iperf_time now;      struct iperf_time now;
       int no_throttle_check;
   
     /* Can we do multisend mode? */      /* Can we do multisend mode? */
     if (test->settings->burst != 0)      if (test->settings->burst != 0)
Line 1585  iperf_send(struct iperf_test *test, fd_set *write_setP Line 1912  iperf_send(struct iperf_test *test, fd_set *write_setP
     else      else
         multisend = 1;  /* nope */          multisend = 1;  /* nope */
   
       /* Should bitrate throttle be checked for every send */
       no_throttle_check = test->settings->rate != 0 && test->settings->burst == 0;
   
     for (; multisend > 0; --multisend) {      for (; multisend > 0; --multisend) {
        if (test->settings->rate != 0 && test->settings->burst == 0)        if (no_throttle_check)
             iperf_time_now(&now);              iperf_time_now(&now);
         streams_active = 0;          streams_active = 0;
         SLIST_FOREACH(sp, &test->streams, streams) {          SLIST_FOREACH(sp, &test->streams, streams) {
             if ((sp->green_light && sp->sender &&              if ((sp->green_light && sp->sender &&
                  (write_setP == NULL || FD_ISSET(sp->socket, write_setP)))) {                   (write_setP == NULL || FD_ISSET(sp->socket, write_setP)))) {
           if (multisend > 1 && test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes)
               break;
           if (multisend > 1 && test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks)
               break;
                 if ((r = sp->snd(sp)) < 0) {                  if ((r = sp->snd(sp)) < 0) {
                     if (r == NET_SOFTERROR)                      if (r == NET_SOFTERROR)
                         break;                          break;
Line 1600  iperf_send(struct iperf_test *test, fd_set *write_setP Line 1934  iperf_send(struct iperf_test *test, fd_set *write_setP
                 }                  }
                 streams_active = 1;                  streams_active = 1;
                 test->bytes_sent += r;                  test->bytes_sent += r;
                ++test->blocks_sent;                if (!sp->pending_size)
                iperf_check_throttle(sp, &now);                    ++test->blocks_sent;
                if (multisend > 1 && test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes)                if (no_throttle_check)
                    break;                    iperf_check_throttle(sp, &now);
                if (multisend > 1 && test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks) 
                    break; 
             }              }
         }          }
         if (!streams_active)          if (!streams_active)
             break;              break;
     }      }
    if (test->settings->burst != 0) {    if (!no_throttle_check) {   /* Throttle check if was not checked for each send */
         iperf_time_now(&now);          iperf_time_now(&now);
         SLIST_FOREACH(sp, &test->streams, streams)          SLIST_FOREACH(sp, &test->streams, streams)
             if (sp->sender)              if (sp->sender)
Line 1722  int test_is_authorized(struct iperf_test *test){ Line 2054  int test_is_authorized(struct iperf_test *test){
         if (rc) {          if (rc) {
             return -1;              return -1;
         }          }
        int ret = check_authentication(username, password, ts, test->server_authorized_users);        int ret = check_authentication(username, password, ts, test->server_authorized_users, test->server_skew_threshold);
         if (ret == 0){          if (ret == 0){
            iperf_printf(test, report_authentication_succeeded, username, ts);            if (test->debug) {
               iperf_printf(test, report_authentication_succeeded, username, ts);
             }
             free(username);              free(username);
             free(password);              free(password);
             return 0;              return 0;
         } else {          } else {
            iperf_printf(test, report_authentication_failed, username, ts);            if (test->debug) {
                 iperf_printf(test, report_authentication_failed, ret, username, ts);
             }
             free(username);              free(username);
             free(password);              free(password);
             return -1;              return -1;
Line 1849  send_parameters(struct iperf_test *test) Line 2185  send_parameters(struct iperf_test *test)
         if (test->server_affinity != -1)          if (test->server_affinity != -1)
             cJSON_AddNumberToObject(j, "server_affinity", test->server_affinity);              cJSON_AddNumberToObject(j, "server_affinity", test->server_affinity);
         cJSON_AddNumberToObject(j, "time", test->duration);          cJSON_AddNumberToObject(j, "time", test->duration);
        if (test->settings->bytes)        cJSON_AddNumberToObject(j, "num", test->settings->bytes);
            cJSON_AddNumberToObject(j, "num", test->settings->bytes);        cJSON_AddNumberToObject(j, "blockcount", test->settings->blocks);
        if (test->settings->blocks) 
            cJSON_AddNumberToObject(j, "blockcount", test->settings->blocks); 
         if (test->settings->mss)          if (test->settings->mss)
             cJSON_AddNumberToObject(j, "MSS", test->settings->mss);              cJSON_AddNumberToObject(j, "MSS", test->settings->mss);
         if (test->no_delay)          if (test->no_delay)
Line 1892  send_parameters(struct iperf_test *test) Line 2226  send_parameters(struct iperf_test *test)
             cJSON_AddNumberToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));              cJSON_AddNumberToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));
         if (test->repeating_payload)          if (test->repeating_payload)
             cJSON_AddNumberToObject(j, "repeating_payload", test->repeating_payload);              cJSON_AddNumberToObject(j, "repeating_payload", test->repeating_payload);
           if (test->zerocopy)
               cJSON_AddNumberToObject(j, "zerocopy", test->zerocopy);
   #if defined(HAVE_DONT_FRAGMENT)
           if (test->settings->dont_fragment)
               cJSON_AddNumberToObject(j, "dont_fragment", test->settings->dont_fragment);
   #endif /* HAVE_DONT_FRAGMENT */
 #if defined(HAVE_SSL)  #if defined(HAVE_SSL)
         /* Send authentication parameters */          /* Send authentication parameters */
         if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){          if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){
Line 1902  send_parameters(struct iperf_test *test) Line 2242  send_parameters(struct iperf_test *test)
                 i_errno = IESENDPARAMS;                  i_errno = IESENDPARAMS;
                 return -1;                  return -1;
             }              }
            
             cJSON_AddStringToObject(j, "authtoken", test->settings->authtoken);              cJSON_AddStringToObject(j, "authtoken", test->settings->authtoken);
         }          }
 #endif // HAVE_SSL  #endif // HAVE_SSL
Line 1956  get_parameters(struct iperf_test *test) Line 2296  get_parameters(struct iperf_test *test)
             test->server_affinity = j_p->valueint;              test->server_affinity = j_p->valueint;
         if ((j_p = cJSON_GetObjectItem(j, "time")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "time")) != NULL)
             test->duration = j_p->valueint;              test->duration = j_p->valueint;
           test->settings->bytes = 0;
         if ((j_p = cJSON_GetObjectItem(j, "num")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "num")) != NULL)
             test->settings->bytes = j_p->valueint;              test->settings->bytes = j_p->valueint;
           test->settings->blocks = 0;
         if ((j_p = cJSON_GetObjectItem(j, "blockcount")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "blockcount")) != NULL)
             test->settings->blocks = j_p->valueint;              test->settings->blocks = j_p->valueint;
         if ((j_p = cJSON_GetObjectItem(j, "MSS")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "MSS")) != NULL)
Line 2000  get_parameters(struct iperf_test *test) Line 2342  get_parameters(struct iperf_test *test)
             iperf_set_test_udp_counters_64bit(test, 1);              iperf_set_test_udp_counters_64bit(test, 1);
         if ((j_p = cJSON_GetObjectItem(j, "repeating_payload")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "repeating_payload")) != NULL)
             test->repeating_payload = 1;              test->repeating_payload = 1;
           if ((j_p = cJSON_GetObjectItem(j, "zerocopy")) != NULL)
               test->zerocopy = j_p->valueint;
   #if defined(HAVE_DONT_FRAGMENT)
           if ((j_p = cJSON_GetObjectItem(j, "dont_fragment")) != NULL)
               test->settings->dont_fragment = j_p->valueint;
   #endif /* HAVE_DONT_FRAGMENT */
 #if defined(HAVE_SSL)  #if defined(HAVE_SSL)
         if ((j_p = cJSON_GetObjectItem(j, "authtoken")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "authtoken")) != NULL)
         test->settings->authtoken = strdup(j_p->valuestring);          test->settings->authtoken = strdup(j_p->valuestring);
Line 2094  send_results(struct iperf_test *test) Line 2442  send_results(struct iperf_test *test)
                     cJSON_AddNumberToObject(j_stream, "retransmits", retransmits);                      cJSON_AddNumberToObject(j_stream, "retransmits", retransmits);
                     cJSON_AddNumberToObject(j_stream, "jitter", sp->jitter);                      cJSON_AddNumberToObject(j_stream, "jitter", sp->jitter);
                     cJSON_AddNumberToObject(j_stream, "errors", sp->cnt_error);                      cJSON_AddNumberToObject(j_stream, "errors", sp->cnt_error);
                       cJSON_AddNumberToObject(j_stream, "omitted_errors", sp->omitted_cnt_error);
                     cJSON_AddNumberToObject(j_stream, "packets", sp->packet_count);                      cJSON_AddNumberToObject(j_stream, "packets", sp->packet_count);
                       cJSON_AddNumberToObject(j_stream, "omitted_packets", sp->omitted_packet_count);
   
                     iperf_time_diff(&sp->result->start_time, &sp->result->start_time, &temp_time);                      iperf_time_diff(&sp->result->start_time, &sp->result->start_time, &temp_time);
                     start_time = iperf_time_in_secs(&temp_time);                      start_time = iperf_time_in_secs(&temp_time);
Line 2141  get_results(struct iperf_test *test) Line 2491  get_results(struct iperf_test *test)
     cJSON *j_retransmits;      cJSON *j_retransmits;
     cJSON *j_jitter;      cJSON *j_jitter;
     cJSON *j_errors;      cJSON *j_errors;
       cJSON *j_omitted_errors;
     cJSON *j_packets;      cJSON *j_packets;
       cJSON *j_omitted_packets;
     cJSON *j_server_output;      cJSON *j_server_output;
     cJSON *j_start_time, *j_end_time;      cJSON *j_start_time, *j_end_time;
    int sid, cerror, pcount;    int sid;
     int64_t cerror, pcount, omitted_cerror, omitted_pcount;
     double jitter;      double jitter;
     iperf_size_t bytes_transferred;      iperf_size_t bytes_transferred;
     int retransmits;      int retransmits;
Line 2197  get_results(struct iperf_test *test) Line 2550  get_results(struct iperf_test *test)
                         j_retransmits = cJSON_GetObjectItem(j_stream, "retransmits");                          j_retransmits = cJSON_GetObjectItem(j_stream, "retransmits");
                         j_jitter = cJSON_GetObjectItem(j_stream, "jitter");                          j_jitter = cJSON_GetObjectItem(j_stream, "jitter");
                         j_errors = cJSON_GetObjectItem(j_stream, "errors");                          j_errors = cJSON_GetObjectItem(j_stream, "errors");
                           j_omitted_errors = cJSON_GetObjectItem(j_stream, "omitted_errors");
                         j_packets = cJSON_GetObjectItem(j_stream, "packets");                          j_packets = cJSON_GetObjectItem(j_stream, "packets");
                           j_omitted_packets = cJSON_GetObjectItem(j_stream, "omitted_packets");
                         j_start_time = cJSON_GetObjectItem(j_stream, "start_time");                          j_start_time = cJSON_GetObjectItem(j_stream, "start_time");
                         j_end_time = cJSON_GetObjectItem(j_stream, "end_time");                          j_end_time = cJSON_GetObjectItem(j_stream, "end_time");
                         if (j_id == NULL || j_bytes == NULL || j_retransmits == NULL || j_jitter == NULL || j_errors == NULL || j_packets == NULL) {                          if (j_id == NULL || j_bytes == NULL || j_retransmits == NULL || j_jitter == NULL || j_errors == NULL || j_packets == NULL) {
                             i_errno = IERECVRESULTS;                              i_errno = IERECVRESULTS;
                             r = -1;                              r = -1;
                           } else if ( (j_omitted_errors == NULL && j_omitted_packets != NULL) || (j_omitted_errors != NULL && j_omitted_packets == NULL) ) {
                               /* For backward compatibility allow to not receive "omitted" statistcs */
                               i_errno = IERECVRESULTS;
                               r = -1;
                         } else {                          } else {
                             sid = j_id->valueint;                              sid = j_id->valueint;
                             bytes_transferred = j_bytes->valueint;                              bytes_transferred = j_bytes->valueint;
Line 2210  get_results(struct iperf_test *test) Line 2569  get_results(struct iperf_test *test)
                             jitter = j_jitter->valuedouble;                              jitter = j_jitter->valuedouble;
                             cerror = j_errors->valueint;                              cerror = j_errors->valueint;
                             pcount = j_packets->valueint;                              pcount = j_packets->valueint;
                               if (j_omitted_packets != NULL) {
                                   omitted_cerror = j_omitted_errors->valueint;
                                   omitted_pcount = j_omitted_packets->valueint;
                               }
                             SLIST_FOREACH(sp, &test->streams, streams)                              SLIST_FOREACH(sp, &test->streams, streams)
                                 if (sp->id == sid) break;                                  if (sp->id == sid) break;
                             if (sp == NULL) {                              if (sp == NULL) {
Line 2221  get_results(struct iperf_test *test) Line 2584  get_results(struct iperf_test *test)
                                     sp->cnt_error = cerror;                                      sp->cnt_error = cerror;
                                     sp->peer_packet_count = pcount;                                      sp->peer_packet_count = pcount;
                                     sp->result->bytes_received = bytes_transferred;                                      sp->result->bytes_received = bytes_transferred;
                                       if (j_omitted_packets != NULL) {
                                           sp->omitted_cnt_error = omitted_cerror;
                                           sp->peer_omitted_packet_count = omitted_pcount;
                                       } else {
                                           sp->peer_omitted_packet_count = sp->omitted_packet_count;
                                           if (sp->peer_omitted_packet_count > 0) {
                                               /* -1 indicates unknown error count since it includes the omitted count */
                                               sp->omitted_cnt_error = (sp->cnt_error > 0) ? -1 : 0;
                                           } else {
                                               sp->omitted_cnt_error = sp->cnt_error;
                                           }
                                       }
                                     /*                                      /*
                                     * We have to handle the possibilty that                                     * We have to handle the possibility that
                                      * start_time and end_time might not be                                       * start_time and end_time might not be
                                      * available; this is the case for older (pre-3.2)                                       * available; this is the case for older (pre-3.2)
                                      * servers.                                       * servers.
Line 2240  get_results(struct iperf_test *test) Line 2615  get_results(struct iperf_test *test)
                                     sp->peer_packet_count = pcount;                                      sp->peer_packet_count = pcount;
                                     sp->result->bytes_sent = bytes_transferred;                                      sp->result->bytes_sent = bytes_transferred;
                                     sp->result->stream_retrans = retransmits;                                      sp->result->stream_retrans = retransmits;
                                       if (j_omitted_packets != NULL) {
                                           sp->peer_omitted_packet_count = omitted_pcount;
                                       } else {
                                           sp->peer_omitted_packet_count = sp->peer_packet_count;
                                       }
                                     if (j_start_time && j_end_time) {                                      if (j_start_time && j_end_time) {
                                         sp->result->sender_time = j_end_time->valuedouble - j_start_time->valuedouble;                                          sp->result->sender_time = j_end_time->valuedouble - j_start_time->valuedouble;
                                     }                                      }
Line 2314  static cJSON * Line 2694  static cJSON *
 JSON_read(int fd)  JSON_read(int fd)
 {  {
     uint32_t hsize, nsize;      uint32_t hsize, nsize;
       size_t strsize;
     char *str;      char *str;
     cJSON *json = NULL;      cJSON *json = NULL;
     int rc;      int rc;
Line 2326  JSON_read(int fd) Line 2707  JSON_read(int fd)
     if (Nread(fd, (char*) &nsize, sizeof(nsize), Ptcp) >= 0) {      if (Nread(fd, (char*) &nsize, sizeof(nsize), Ptcp) >= 0) {
         hsize = ntohl(nsize);          hsize = ntohl(nsize);
         /* Allocate a buffer to hold the JSON */          /* Allocate a buffer to hold the JSON */
        str = (char *) calloc(sizeof(char), hsize+1);    /* +1 for trailing null */        strsize = hsize + 1;              /* +1 for trailing NULL */
         if (strsize) {
         str = (char *) calloc(sizeof(char), strsize);
         if (str != NULL) {          if (str != NULL) {
             rc = Nread(fd, str, hsize, Ptcp);              rc = Nread(fd, str, hsize, Ptcp);
             if (rc >= 0) {              if (rc >= 0) {
Line 2345  JSON_read(int fd) Line 2728  JSON_read(int fd)
             }              }
         }          }
         free(str);          free(str);
           }
           else {
               printf("WARNING:  Data length overflow\n");
           }
     }      }
     return json;      return json;
 }  }
Line 2427  iperf_new_test() Line 2814  iperf_new_test()
   
     test->bitrate_limit_intervals_traffic_bytes = (iperf_size_t *) malloc(sizeof(iperf_size_t) * MAX_INTERVAL);      test->bitrate_limit_intervals_traffic_bytes = (iperf_size_t *) malloc(sizeof(iperf_size_t) * MAX_INTERVAL);
     if (!test->bitrate_limit_intervals_traffic_bytes) {      if (!test->bitrate_limit_intervals_traffic_bytes) {
           free(test->settings);
         free(test);          free(test);
         i_errno = IENEWTEST;          i_errno = IENEWTEST;
         return NULL;          return NULL;
     }      }
    memset(test->bitrate_limit_intervals_traffic_bytes, 0, sizeof(sizeof(iperf_size_t) * MAX_INTERVAL));       memset(test->bitrate_limit_intervals_traffic_bytes, 0, sizeof(sizeof(iperf_size_t) * MAX_INTERVAL));
   
     /* By default all output goes to stdout */      /* By default all output goes to stdout */
     test->outfile = stdout;      test->outfile = stdout;
Line 2458  protocol_new(void) Line 2846  protocol_new(void)
 void  void
 protocol_free(struct protocol *proto)  protocol_free(struct protocol *proto)
 {  {
    free(proto);     free(proto);
 }  }
   
 /**************************************************************************/  /**************************************************************************/
Line 2486  iperf_defaults(struct iperf_test *testp) Line 2874  iperf_defaults(struct iperf_test *testp)
     testp->remote_congestion_used = NULL;      testp->remote_congestion_used = NULL;
     testp->server_port = PORT;      testp->server_port = PORT;
     testp->ctrl_sck = -1;      testp->ctrl_sck = -1;
       testp->listener = -1;
     testp->prot_listener = -1;      testp->prot_listener = -1;
     testp->other_side_has_retransmits = 0;      testp->other_side_has_retransmits = 0;
   
Line 2504  iperf_defaults(struct iperf_test *testp) Line 2893  iperf_defaults(struct iperf_test *testp)
     testp->settings->bitrate_limit_interval = 5;      testp->settings->bitrate_limit_interval = 5;
     testp->settings->bitrate_limit_stats_per_interval = 0;      testp->settings->bitrate_limit_stats_per_interval = 0;
     testp->settings->fqrate = 0;      testp->settings->fqrate = 0;
    testp->settings->pacing_timer = 1000;    testp->settings->pacing_timer = DEFAULT_PACING_TIMER;
     testp->settings->burst = 0;      testp->settings->burst = 0;
     testp->settings->mss = 0;      testp->settings->mss = 0;
     testp->settings->bytes = 0;      testp->settings->bytes = 0;
     testp->settings->blocks = 0;      testp->settings->blocks = 0;
     testp->settings->connect_timeout = -1;      testp->settings->connect_timeout = -1;
       testp->settings->rcv_timeout.secs = DEFAULT_NO_MSG_RCVD_TIMEOUT / SEC_TO_mS;
       testp->settings->rcv_timeout.usecs = (DEFAULT_NO_MSG_RCVD_TIMEOUT % SEC_TO_mS) * mS_TO_US;
       testp->zerocopy = 0;
   
     memset(testp->cookie, 0, COOKIE_SIZE);      memset(testp->cookie, 0, COOKIE_SIZE);
   
     testp->multisend = 10;      /* arbitrary */      testp->multisend = 10;      /* arbitrary */
Line 2600  iperf_free_test(struct iperf_test *test) Line 2993  iperf_free_test(struct iperf_test *test)
         free(test->tmp_template);          free(test->tmp_template);
     if (test->bind_address)      if (test->bind_address)
         free(test->bind_address);          free(test->bind_address);
       if (test->bind_dev)
           free(test->bind_dev);
     if (!TAILQ_EMPTY(&test->xbind_addrs)) {      if (!TAILQ_EMPTY(&test->xbind_addrs)) {
         struct xbind_entry *xbe;          struct xbind_entry *xbe;
   
Line 2658  iperf_free_test(struct iperf_test *test) Line 3053  iperf_free_test(struct iperf_test *test)
     /* Free protocol list */      /* Free protocol list */
     while (!SLIST_EMPTY(&test->protocols)) {      while (!SLIST_EMPTY(&test->protocols)) {
         prot = SLIST_FIRST(&test->protocols);          prot = SLIST_FIRST(&test->protocols);
        SLIST_REMOVE_HEAD(&test->protocols, protocols);                SLIST_REMOVE_HEAD(&test->protocols, protocols);
         free(prot);          free(prot);
     }      }
   
     if (test->logfile) {      if (test->logfile) {
         free(test->logfile);          free(test->logfile);
         test->logfile = NULL;          test->logfile = NULL;
        if (test->outfile) {        iperf_close_logfile(test);
            fclose(test->outfile); 
            test->outfile = NULL; 
        } 
     }      }
   
     if (test->server_output_text) {      if (test->server_output_text) {
Line 2702  iperf_free_test(struct iperf_test *test) Line 3094  iperf_free_test(struct iperf_test *test)
         }          }
     }      }
   
    /* Free interval's traffic array for avrage rate calculations */    /* Free interval's traffic array for average rate calculations */
     if (test->bitrate_limit_intervals_traffic_bytes != NULL)      if (test->bitrate_limit_intervals_traffic_bytes != NULL)
         free(test->bitrate_limit_intervals_traffic_bytes);          free(test->bitrate_limit_intervals_traffic_bytes);
   
Line 2720  iperf_reset_test(struct iperf_test *test) Line 3112  iperf_reset_test(struct iperf_test *test)
     struct iperf_stream *sp;      struct iperf_stream *sp;
     int i;      int i;
   
       iperf_close_logfile(test);
   
     /* Free streams */      /* Free streams */
     while (!SLIST_EMPTY(&test->streams)) {      while (!SLIST_EMPTY(&test->streams)) {
         sp = SLIST_FIRST(&test->streams);          sp = SLIST_FIRST(&test->streams);
Line 2760  iperf_reset_test(struct iperf_test *test) Line 3154  iperf_reset_test(struct iperf_test *test)
     CPU_ZERO(&test->cpumask);      CPU_ZERO(&test->cpumask);
 #endif /* HAVE_CPUSET_SETAFFINITY */  #endif /* HAVE_CPUSET_SETAFFINITY */
     test->state = 0;      test->state = 0;
    
     test->ctrl_sck = -1;      test->ctrl_sck = -1;
       test->listener = -1;
     test->prot_listener = -1;      test->prot_listener = -1;
   
     test->bytes_sent = 0;      test->bytes_sent = 0;
Line 2785  iperf_reset_test(struct iperf_test *test) Line 3180  iperf_reset_test(struct iperf_test *test)
   
     FD_ZERO(&test->read_set);      FD_ZERO(&test->read_set);
     FD_ZERO(&test->write_set);      FD_ZERO(&test->write_set);
    
     test->num_streams = 1;      test->num_streams = 1;
     test->settings->socket_bufsize = 0;      test->settings->socket_bufsize = 0;
     test->settings->blksize = DEFAULT_TCP_BLKSIZE;      test->settings->blksize = DEFAULT_TCP_BLKSIZE;
Line 2793  iperf_reset_test(struct iperf_test *test) Line 3188  iperf_reset_test(struct iperf_test *test)
     test->settings->burst = 0;      test->settings->burst = 0;
     test->settings->mss = 0;      test->settings->mss = 0;
     test->settings->tos = 0;      test->settings->tos = 0;
       test->settings->dont_fragment = 0;
       test->zerocopy = 0;
   
 #if defined(HAVE_SSL)  #if defined(HAVE_SSL)
     if (test->settings->authtoken) {      if (test->settings->authtoken) {
Line 2891  iperf_stats_callback(struct iperf_test *test) Line 3288  iperf_stats_callback(struct iperf_test *test)
   
         // Total bytes transferred this interval          // Total bytes transferred this interval
         total_interval_bytes_transferred += rp->bytes_sent_this_interval + rp->bytes_received_this_interval;          total_interval_bytes_transferred += rp->bytes_sent_this_interval + rp->bytes_received_this_interval;
    
         irp = TAILQ_LAST(&rp->interval_results, irlisthead);          irp = TAILQ_LAST(&rp->interval_results, irlisthead);
         /* result->end_time contains timestamp of previous interval */          /* result->end_time contains timestamp of previous interval */
         if ( irp != NULL ) /* not the 1st interval */          if ( irp != NULL ) /* not the 1st interval */
Line 2916  iperf_stats_callback(struct iperf_test *test) Line 3313  iperf_stats_callback(struct iperf_test *test)
                     if (temp.snd_cwnd > rp->stream_max_snd_cwnd) {                      if (temp.snd_cwnd > rp->stream_max_snd_cwnd) {
                         rp->stream_max_snd_cwnd = temp.snd_cwnd;                          rp->stream_max_snd_cwnd = temp.snd_cwnd;
                     }                      }
                    
                     temp.snd_wnd = get_snd_wnd(&temp);
                     if (temp.snd_wnd > rp->stream_max_snd_wnd) {
                         rp->stream_max_snd_wnd = temp.snd_wnd;
                     }
 
                     temp.rtt = get_rtt(&temp);                      temp.rtt = get_rtt(&temp);
                     if (temp.rtt > rp->stream_max_rtt) {                      if (temp.rtt > rp->stream_max_rtt) {
                         rp->stream_max_rtt = temp.rtt;                          rp->stream_max_rtt = temp.rtt;
Line 3000  iperf_print_intermediate(struct iperf_test *test) Line 3402  iperf_print_intermediate(struct iperf_test *test)
   
             /*              /*
              * If the interval is at least 10% the normal interval               * If the interval is at least 10% the normal interval
             * length, or if there were actual bytes transferrred,             * length, or if there were actual bytes transferred,
              * then we want to keep this interval.               * then we want to keep this interval.
              */               */
             if (interval_len >= test->stats_interval * 0.10 ||              if (interval_len >= test->stats_interval * 0.10 ||
Line 3067  iperf_print_intermediate(struct iperf_test *test) Line 3469  iperf_print_intermediate(struct iperf_test *test)
         int retransmits = 0;          int retransmits = 0;
         double start_time, end_time;          double start_time, end_time;
   
        int total_packets = 0, lost_packets = 0;        int64_t total_packets = 0, lost_packets = 0;
         double avg_jitter = 0.0, lost_percent;          double avg_jitter = 0.0, lost_percent;
         int stream_must_be_sender = current_mode * current_mode;          int stream_must_be_sender = current_mode * current_mode;
   
           char *sum_name;
   
         /*  Print stream role just for bidirectional mode. */          /*  Print stream role just for bidirectional mode. */
   
         if (test->mode == BIDIRECTIONAL) {          if (test->mode == BIDIRECTIONAL) {
Line 3105  iperf_print_intermediate(struct iperf_test *test) Line 3509  iperf_print_intermediate(struct iperf_test *test)
   
         /* next build string with sum of all streams */          /* next build string with sum of all streams */
         if (test->num_streams > 1 || test->json_output) {          if (test->num_streams > 1 || test->json_output) {
               /*
                * With BIDIR give a different JSON object name to the one sent/receive sums.
                * The different name is given to the data sent from the server, which is
                * the "reverse" channel.  This makes sure that the name reported on the server
                * and client are compatible, and the names are the same as with non-bidir,
                * except for when reverse is used.
                */
               sum_name = "sum";
               if (test->mode == BIDIRECTIONAL) {
                   if ((test->role == 'c' && !stream_must_be_sender) ||
                       (test->role != 'c' && stream_must_be_sender))
                   {
                       sum_name = "sum_bidir_reverse";
                   }
               }
   
             sp = SLIST_FIRST(&test->streams); /* reset back to 1st stream */              sp = SLIST_FIRST(&test->streams); /* reset back to 1st stream */
             /* Only do this of course if there was a first stream */              /* Only do this of course if there was a first stream */
             if (sp) {              if (sp) {
Line 3122  iperf_print_intermediate(struct iperf_test *test) Line 3542  iperf_print_intermediate(struct iperf_test *test)
                     if (test->sender_has_retransmits == 1 && stream_must_be_sender) {                      if (test->sender_has_retransmits == 1 && stream_must_be_sender) {
                         /* Interval sum, TCP with retransmits. */                          /* Interval sum, TCP with retransmits. */
                         if (test->json_output)                          if (test->json_output)
                            cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) retransmits, irp->omitted, stream_must_be_sender)); /* XXX irp->omitted or test->omitting? */                            cJSON_AddItemToObject(json_interval, sum_name, iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) retransmits, irp->omitted, stream_must_be_sender)); /* XXX irp->omitted or test->omitting? */
                         else                          else
                             iperf_printf(test, report_sum_bw_retrans_format, mbuf, start_time, end_time, ubuf, nbuf, retransmits, irp->omitted?report_omitted:""); /* XXX irp->omitted or test->omitting? */                              iperf_printf(test, report_sum_bw_retrans_format, mbuf, start_time, end_time, ubuf, nbuf, retransmits, irp->omitted?report_omitted:""); /* XXX irp->omitted or test->omitting? */
                     } else {                      } else {
                         /* Interval sum, TCP without retransmits. */                          /* Interval sum, TCP without retransmits. */
                         if (test->json_output)                          if (test->json_output)
                            cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, test->omitting, stream_must_be_sender));                            cJSON_AddItemToObject(json_interval, sum_name, iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, test->omitting, stream_must_be_sender));
                         else                          else
                             iperf_printf(test, report_sum_bw_format, mbuf, start_time, end_time, ubuf, nbuf, test->omitting?report_omitted:"");                              iperf_printf(test, report_sum_bw_format, mbuf, start_time, end_time, ubuf, nbuf, test->omitting?report_omitted:"");
                     }                      }
Line 3136  iperf_print_intermediate(struct iperf_test *test) Line 3556  iperf_print_intermediate(struct iperf_test *test)
                     /* Interval sum, UDP. */                      /* Interval sum, UDP. */
                     if (stream_must_be_sender) {                      if (stream_must_be_sender) {
                         if (test->json_output)                          if (test->json_output)
                            cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  packets: %d  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) total_packets, test->omitting, stream_must_be_sender));                            cJSON_AddItemToObject(json_interval, sum_name, iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  packets: %d  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) total_packets, test->omitting, stream_must_be_sender));
                         else                          else
                             iperf_printf(test, report_sum_bw_udp_sender_format, mbuf, start_time, end_time, ubuf, nbuf, zbuf, total_packets, test->omitting?report_omitted:"");                              iperf_printf(test, report_sum_bw_udp_sender_format, mbuf, start_time, end_time, ubuf, nbuf, zbuf, total_packets, test->omitting?report_omitted:"");
                     } else {                      } else {
Line 3148  iperf_print_intermediate(struct iperf_test *test) Line 3568  iperf_print_intermediate(struct iperf_test *test)
                             lost_percent = 0.0;                              lost_percent = 0.0;
                         }                          }
                         if (test->json_output)                          if (test->json_output)
                            cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent, test->omitting, stream_must_be_sender));                            cJSON_AddItemToObject(json_interval, sum_name, iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f  omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent, test->omitting, stream_must_be_sender));
                         else                          else
                             iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, end_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, total_packets, lost_percent, test->omitting?report_omitted:"");                              iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, end_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, total_packets, lost_percent, test->omitting?report_omitted:"");
                     }                      }
Line 3170  iperf_print_results(struct iperf_test *test) Line 3590  iperf_print_results(struct iperf_test *test)
     int lower_mode, upper_mode;      int lower_mode, upper_mode;
     int current_mode;      int current_mode;
   
       char *sum_sent_name, *sum_received_name, *sum_name;
   
     int tmp_sender_has_retransmits = test->sender_has_retransmits;      int tmp_sender_has_retransmits = test->sender_has_retransmits;
   
     /* print final summary for all intervals */      /* print final summary for all intervals */
Line 3229  iperf_print_results(struct iperf_test *test) Line 3651  iperf_print_results(struct iperf_test *test)
   
     for (current_mode = lower_mode; current_mode <= upper_mode; ++current_mode) {      for (current_mode = lower_mode; current_mode <= upper_mode; ++current_mode) {
         cJSON *json_summary_stream = NULL;          cJSON *json_summary_stream = NULL;
        int total_retransmits = 0;        int64_t total_retransmits = 0;
        int total_packets = 0, lost_packets = 0;        int64_t total_packets = 0, lost_packets = 0;
        int sender_packet_count = 0, receiver_packet_count = 0; /* for this stream, this interval */        int64_t sender_packet_count = 0, receiver_packet_count = 0; /* for this stream, this interval */
        int sender_total_packets = 0, receiver_total_packets = 0; /* running total */        int64_t sender_omitted_packet_count = 0, receiver_omitted_packet_count = 0; /* for this stream, this interval */
         int64_t sender_total_packets = 0, receiver_total_packets = 0; /* running total */
         char ubuf[UNIT_LEN];          char ubuf[UNIT_LEN];
         char nbuf[UNIT_LEN];          char nbuf[UNIT_LEN];
         struct stat sb;          struct stat sb;
Line 3242  iperf_print_results(struct iperf_test *test) Line 3665  iperf_print_results(struct iperf_test *test)
         iperf_size_t bytes_received, total_received = 0;          iperf_size_t bytes_received, total_received = 0;
         double start_time, end_time = 0.0, avg_jitter = 0.0, lost_percent = 0.0;          double start_time, end_time = 0.0, avg_jitter = 0.0, lost_percent = 0.0;
         double sender_time = 0.0, receiver_time = 0.0;          double sender_time = 0.0, receiver_time = 0.0;
    struct iperf_time temp_time;        struct iperf_time temp_time;
         double bandwidth;          double bandwidth;
   
         char mbuf[UNIT_LEN];          char mbuf[UNIT_LEN];
Line 3272  iperf_print_results(struct iperf_test *test) Line 3695  iperf_print_results(struct iperf_test *test)
          * the streams.  It's possible to not have any streams at all           * the streams.  It's possible to not have any streams at all
          * if the client got interrupted before it got to do anything.           * if the client got interrupted before it got to do anything.
          *           *
         * Also note that we try to keep seperate values for the sender         * Also note that we try to keep separate values for the sender
          * and receiver ending times.  Earlier iperf (3.1 and earlier)           * and receiver ending times.  Earlier iperf (3.1 and earlier)
          * servers didn't send that to the clients, so in this case we fall           * servers didn't send that to the clients, so in this case we fall
          * back to using the client's ending timestamp.  The fallback is           * back to using the client's ending timestamp.  The fallback is
Line 3280  iperf_print_results(struct iperf_test *test) Line 3703  iperf_print_results(struct iperf_test *test)
          */           */
   
         if (sp) {          if (sp) {
    iperf_time_diff(&sp->result->start_time, &sp->result->end_time, &temp_time);        iperf_time_diff(&sp->result->start_time, &sp->result->end_time, &temp_time);
    end_time = iperf_time_in_secs(&temp_time);        end_time = iperf_time_in_secs(&temp_time);
         if (sp->sender) {          if (sp->sender) {
             sp->result->sender_time = end_time;              sp->result->sender_time = end_time;
             if (sp->result->receiver_time == 0.0) {              if (sp->result->receiver_time == 0.0) {
Line 3312  iperf_print_results(struct iperf_test *test) Line 3735  iperf_print_results(struct iperf_test *test)
   
                 if (sp->sender) {                  if (sp->sender) {
                     sender_packet_count = sp->packet_count;                      sender_packet_count = sp->packet_count;
                       sender_omitted_packet_count = sp->omitted_packet_count;
                     receiver_packet_count = sp->peer_packet_count;                      receiver_packet_count = sp->peer_packet_count;
                       receiver_omitted_packet_count = sp->peer_omitted_packet_count;
                 }                  }
                 else {                  else {
                     sender_packet_count = sp->peer_packet_count;                      sender_packet_count = sp->peer_packet_count;
                       sender_omitted_packet_count = sp->peer_omitted_packet_count;
                     receiver_packet_count = sp->packet_count;                      receiver_packet_count = sp->packet_count;
                       receiver_omitted_packet_count = sp->omitted_packet_count;
                 }                  }
   
                 if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {                  if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
Line 3328  iperf_print_results(struct iperf_test *test) Line 3755  iperf_print_results(struct iperf_test *test)
                      * Running total of the total number of packets.  Use the sender packet count if we                       * Running total of the total number of packets.  Use the sender packet count if we
                      * have it, otherwise use the receiver packet count.                       * have it, otherwise use the receiver packet count.
                      */                       */
                    int packet_count = sender_packet_count ? sender_packet_count : receiver_packet_count;                    int64_t packet_count = sender_packet_count ? sender_packet_count : receiver_packet_count;
                     total_packets += (packet_count - sp->omitted_packet_count);                      total_packets += (packet_count - sp->omitted_packet_count);
                    sender_total_packets += (sender_packet_count - sp->omitted_packet_count);                    sender_total_packets += (sender_packet_count - sender_omitted_packet_count);
                    receiver_total_packets += (receiver_packet_count - sp->omitted_packet_count);                    receiver_total_packets += (receiver_packet_count - receiver_omitted_packet_count);
                    lost_packets += (sp->cnt_error - sp->omitted_cnt_error);                    lost_packets += sp->cnt_error;
                     if (sp->omitted_cnt_error > -1)
                          lost_packets -= sp->omitted_cnt_error;
                     avg_jitter += sp->jitter;                      avg_jitter += sp->jitter;
                 }                  }
   
Line 3348  iperf_print_results(struct iperf_test *test) Line 3777  iperf_print_results(struct iperf_test *test)
                     if (test->sender_has_retransmits) {                      if (test->sender_has_retransmits) {
                         /* Sender summary, TCP and SCTP with retransmits. */                          /* Sender summary, TCP and SCTP with retransmits. */
                         if (test->json_output)                          if (test->json_output)
                            cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d  max_snd_cwnd:  %d  max_rtt:  %d  min_rtt:  %d  mean_rtt:  %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->stream_retrans, (int64_t) sp->result->stream_max_snd_cwnd, (int64_t) sp->result->stream_max_rtt, (int64_t) sp->result->stream_min_rtt, (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt), stream_must_be_sender));                            cJSON_AddItemToObject(json_summary_stream, report_sender, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d  max_snd_cwnd:  %d  max_snd_wnd:  %d  max_rtt:  %d  min_rtt:  %d  mean_rtt:  %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->stream_retrans, (int64_t) sp->result->stream_max_snd_cwnd, (int64_t) sp->result->stream_max_snd_wnd, (int64_t) sp->result->stream_max_rtt, (int64_t) sp->result->stream_min_rtt, (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt), stream_must_be_sender));
                         else                          else
                             if (test->role == 's' && !sp->sender) {                              if (test->role == 's' && !sp->sender) {
                                 if (test->verbose)                                  if (test->verbose)
Line 3360  iperf_print_results(struct iperf_test *test) Line 3789  iperf_print_results(struct iperf_test *test)
                     } else {                      } else {
                         /* Sender summary, TCP and SCTP without retransmits. */                          /* Sender summary, TCP and SCTP without retransmits. */
                         if (test->json_output)                          if (test->json_output)
                            cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8,  stream_must_be_sender));                            cJSON_AddItemToObject(json_summary_stream, report_sender, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8,  stream_must_be_sender));
                         else                          else
                             if (test->role == 's' && !sp->sender) {                              if (test->role == 's' && !sp->sender) {
                                 if (test->verbose)                                  if (test->verbose)
Line 3372  iperf_print_results(struct iperf_test *test) Line 3801  iperf_print_results(struct iperf_test *test)
                     }                      }
                 } else {                  } else {
                     /* Sender summary, UDP. */                      /* Sender summary, UDP. */
                    if (sender_packet_count - sp->omitted_packet_count > 0) {                    if (sender_packet_count - sender_omitted_packet_count > 0) {
                        lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (sender_packet_count - sp->omitted_packet_count);                        lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (sender_packet_count - sender_omitted_packet_count);
                     }                      }
                     else {                      else {
                         lost_percent = 0.0;                          lost_percent = 0.0;
                     }                      }
                     if (test->json_output) {                      if (test->json_output) {
                         /*                          /*
                         * For hysterical raisins, we only emit one JSON                         * For historical reasons, we only emit one JSON
                          * object for the UDP summary, and it contains                           * object for the UDP summary, and it contains
                          * information for both the sender and receiver                           * information for both the sender and receiver
                          * side.                           * side.
Line 3395  iperf_print_results(struct iperf_test *test) Line 3824  iperf_print_results(struct iperf_test *test)
                          * is the case, then use the receiver's count of packets                           * is the case, then use the receiver's count of packets
                          * instead.                           * instead.
                          */                           */
                        int packet_count = sender_packet_count ? sender_packet_count : receiver_packet_count;                        int64_t packet_count = sender_packet_count ? sender_packet_count : receiver_packet_count;
                         cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f  out_of_order: %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets), stream_must_be_sender));                          cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f  out_of_order: %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets), stream_must_be_sender));
                     }                      }
                     else {                      else {
Line 3411  iperf_print_results(struct iperf_test *test) Line 3840  iperf_print_results(struct iperf_test *test)
                                 iperf_printf(test, report_sender_not_available_format, sp->socket);                                  iperf_printf(test, report_sender_not_available_format, sp->socket);
                         }                          }
                         else {                          else {
                            iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, 0, (sender_packet_count - sp->omitted_packet_count), (double) 0, report_sender);                            iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, (int64_t) 0, (sender_packet_count - sender_omitted_packet_count), (double) 0, report_sender);
                         }                          }
                         if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0)                          if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0)
                           iperf_printf(test, report_sum_outoforder, mbuf, start_time, sender_time, (sp->outoforder_packets - sp->omitted_outoforder_packets));                            iperf_printf(test, report_sum_outoforder, mbuf, start_time, sender_time, (sp->outoforder_packets - sp->omitted_outoforder_packets));
Line 3451  iperf_print_results(struct iperf_test *test) Line 3880  iperf_print_results(struct iperf_test *test)
                 if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {                  if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
                     /* Receiver summary, TCP and SCTP */                      /* Receiver summary, TCP and SCTP */
                     if (test->json_output)                      if (test->json_output)
                        cJSON_AddItemToObject(json_summary_stream, "receiver", iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (int64_t) sp->socket, (double) start_time, (double) receiver_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8, stream_must_be_sender));                        cJSON_AddItemToObject(json_summary_stream, report_receiver, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (int64_t) sp->socket, (double) start_time, (double) receiver_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8, stream_must_be_sender));
                     else                      else
                         if (test->role == 's' && sp->sender) {                          if (test->role == 's' && sp->sender) {
                             if (test->verbose)                              if (test->verbose)
Line 3468  iperf_print_results(struct iperf_test *test) Line 3897  iperf_print_results(struct iperf_test *test)
                      * data here.                       * data here.
                      */                       */
                     if (! test->json_output) {                      if (! test->json_output) {
                        if (receiver_packet_count - sp->omitted_packet_count > 0) {                        if (receiver_packet_count - receiver_omitted_packet_count > 0 && sp->omitted_cnt_error > -1) {
                            lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (receiver_packet_count - sp->omitted_packet_count);                            lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (receiver_packet_count - receiver_omitted_packet_count);
                         }                          }
                         else {                          else {
                             lost_percent = 0.0;                              lost_percent = 0.0;
Line 3480  iperf_print_results(struct iperf_test *test) Line 3909  iperf_print_results(struct iperf_test *test)
                                 iperf_printf(test, report_receiver_not_available_format, sp->socket);                                  iperf_printf(test, report_receiver_not_available_format, sp->socket);
                         }                          }
                         else {                          else {
                            iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (receiver_packet_count - sp->omitted_packet_count), lost_percent, report_receiver);                            if (sp->omitted_cnt_error > -1) {
                                 iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (receiver_packet_count - receiver_omitted_packet_count), lost_percent, report_receiver);
                             } else {
                                 iperf_printf(test, report_bw_udp_format_no_omitted_error, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, sp->jitter * 1000.0, (receiver_packet_count - receiver_omitted_packet_count), report_receiver);
                             }
                         }                          }
                     }                      }
                 }                  }
Line 3489  iperf_print_results(struct iperf_test *test) Line 3922  iperf_print_results(struct iperf_test *test)
         }          }
   
         if (test->num_streams > 1 || test->json_output) {          if (test->num_streams > 1 || test->json_output) {
               /*
                * With BIDIR give a different JSON object name to the one sent/receive sums.
                * The different name is given to the data sent from the server, which is
                * the "reverse" channel.  This makes sure that the name reported on the server
                * and client are compatible, and the names are the same as with non-bidir,
                * except for when reverse is used.
                */
               sum_name = "sum";
               sum_sent_name = "sum_sent";
               sum_received_name = "sum_received";
               if (test->mode == BIDIRECTIONAL) {
                   if ((test->role == 'c' && !stream_must_be_sender) ||
                       (test->role != 'c' && stream_must_be_sender))
                   {
                       sum_name = "sum_bidir_reverse";
                       sum_sent_name = "sum_sent_bidir_reverse";
                       sum_received_name = "sum_received_bidir_reverse";
                   }
   
               }
   
             unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');              unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
             /* If no tests were run, arbitrarily set bandwidth to 0. */              /* If no tests were run, arbitrarily set bandwidth to 0. */
             if (sender_time > 0.0) {              if (sender_time > 0.0) {
Line 3502  iperf_print_results(struct iperf_test *test) Line 3956  iperf_print_results(struct iperf_test *test)
                 if (test->sender_has_retransmits) {                  if (test->sender_has_retransmits) {
                     /* Summary sum, TCP with retransmits. */                      /* Summary sum, TCP with retransmits. */
                     if (test->json_output)                      if (test->json_output)
                        cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, bandwidth * 8, (int64_t) total_retransmits, stream_must_be_sender));                        cJSON_AddItemToObject(test->json_end, sum_sent_name, iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, bandwidth * 8, (int64_t) total_retransmits, stream_must_be_sender));
                     else                      else
                         if (test->role == 's' && !stream_must_be_sender) {                          if (test->role == 's' && !stream_must_be_sender) {
                             if (test->verbose)                              if (test->verbose)
Line 3514  iperf_print_results(struct iperf_test *test) Line 3968  iperf_print_results(struct iperf_test *test)
                 } else {                  } else {
                     /* Summary sum, TCP without retransmits. */                      /* Summary sum, TCP without retransmits. */
                     if (test->json_output)                      if (test->json_output)
                        cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, bandwidth * 8, stream_must_be_sender));                        cJSON_AddItemToObject(test->json_end, sum_sent_name, iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, bandwidth * 8, stream_must_be_sender));
                     else                      else
                         if (test->role == 's' && !stream_must_be_sender) {                          if (test->role == 's' && !stream_must_be_sender) {
                             if (test->verbose)                              if (test->verbose)
Line 3534  iperf_print_results(struct iperf_test *test) Line 3988  iperf_print_results(struct iperf_test *test)
                 }                  }
                 unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);                  unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
                 if (test->json_output)                  if (test->json_output)
                    cJSON_AddItemToObject(test->json_end, "sum_received", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_received, bandwidth * 8, stream_must_be_sender));                    cJSON_AddItemToObject(test->json_end, sum_received_name, iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_received, bandwidth * 8, stream_must_be_sender));
                 else                  else
                     if (test->role == 's' && stream_must_be_sender) {                      if (test->role == 's' && stream_must_be_sender) {
                         if (test->verbose)                          if (test->verbose)
Line 3553  iperf_print_results(struct iperf_test *test) Line 4007  iperf_print_results(struct iperf_test *test)
                 else {                  else {
                     lost_percent = 0.0;                      lost_percent = 0.0;
                 }                  }
                if (test->json_output)                if (test->json_output) {
                    cJSON_AddItemToObject(test->json_end, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_sent, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent, stream_must_be_sender)); 
                else { 
                     /*                      /*
                        * Original, summary structure. Using this
                        * structure is not recommended due to
                        * ambiguities between the sender and receiver.
                        */
                       cJSON_AddItemToObject(test->json_end, sum_name, iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_sent, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent, stream_must_be_sender));
                       /*
                        * Separate sum_sent and sum_received structures.
                        * Using these structures to get the most complete
                        * information about UDP transfer.
                        */
                       cJSON_AddItemToObject(test->json_end, sum_sent_name, iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f  sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, (double) total_sent * 8 / sender_time, (double) 0.0, (int64_t) 0, (int64_t) sender_total_packets, (double) 0.0, 1));
                       cJSON_AddItemToObject(test->json_end, sum_received_name, iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f  sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_received, (double) total_received * 8 / receiver_time, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) receiver_total_packets, (double) lost_percent, 0));
                   } else {
                       /*
                      * On the client we have both sender and receiver overall summary                       * On the client we have both sender and receiver overall summary
                      * stats.  On the server we have only the side that was on the                       * stats.  On the server we have only the side that was on the
                      * server.  Output whatever we have.                       * server.  Output whatever we have.
                      */                       */
                     if (! (test->role == 's' && !stream_must_be_sender) ) {                      if (! (test->role == 's' && !stream_must_be_sender) ) {
                         unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');                          unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
                        iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, 0, sender_total_packets, 0.0, "sender");                        iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, (int64_t) 0, sender_total_packets, 0.0, report_sender);
                     }                      }
                     if (! (test->role == 's' && stream_must_be_sender) ) {                      if (! (test->role == 's' && stream_must_be_sender) ) {
   
Line 3576  iperf_print_results(struct iperf_test *test) Line 4042  iperf_print_results(struct iperf_test *test)
                             bandwidth = 0.0;                              bandwidth = 0.0;
                         }                          }
                         unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);                          unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
                        iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, receiver_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, receiver_total_packets, lost_percent, "receiver");                        iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, receiver_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, receiver_total_packets, lost_percent, report_receiver);
                     }                      }
                 }                  }
             }              }
Line 3656  iperf_print_results(struct iperf_test *test) Line 4122  iperf_print_results(struct iperf_test *test)
   
 /**  /**
  * Main report-printing callback.   * Main report-printing callback.
 * Prints results either during a test (interval report only) or  * Prints results either during a test (interval report only) or
 * after the entire test has been run (last interval report plus  * after the entire test has been run (last interval report plus
  * overall summary).   * overall summary).
  */   */
 void  void
Line 3674  iperf_reporter_callback(struct iperf_test *test) Line 4140  iperf_reporter_callback(struct iperf_test *test)
             iperf_print_intermediate(test);              iperf_print_intermediate(test);
             iperf_print_results(test);              iperf_print_results(test);
             break;              break;
    }     }
   
 }  }
   
Line 3752  print_interval_results(struct iperf_test *test, struct Line 4218  print_interval_results(struct iperf_test *test, struct
         bandwidth = 0.0;          bandwidth = 0.0;
     }      }
     unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);      unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
    
     iperf_time_diff(&sp->result->start_time, &irp->interval_start_time, &temp_time);      iperf_time_diff(&sp->result->start_time, &irp->interval_start_time, &temp_time);
     st = iperf_time_in_secs(&temp_time);      st = iperf_time_in_secs(&temp_time);
     iperf_time_diff(&sp->result->start_time, &irp->interval_end_time, &temp_time);      iperf_time_diff(&sp->result->start_time, &irp->interval_end_time, &temp_time);
     et = iperf_time_in_secs(&temp_time);      et = iperf_time_in_secs(&temp_time);
    
     if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {      if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
         if (test->sender_has_retransmits == 1 && sp->sender) {          if (test->sender_has_retransmits == 1 && sp->sender) {
             /* Interval, TCP with retransmits. */              /* Interval, TCP with retransmits. */
             if (test->json_output)              if (test->json_output)
                cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d  snd_cwnd:  %d  rtt:  %d  rttvar: %d  pmtu: %d  omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_retrans, (int64_t) irp->snd_cwnd, (int64_t) irp->rtt, (int64_t) irp->rttvar, (int64_t) irp->pmtu, irp->omitted, sp->sender));                cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d  snd_cwnd:  %d  snd_wnd:  %d  rtt:  %d  rttvar: %d  pmtu: %d  omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_retrans, (int64_t) irp->snd_cwnd, (int64_t) irp->snd_wnd, (int64_t) irp->rtt, (int64_t) irp->rttvar, (int64_t) irp->pmtu, irp->omitted, sp->sender));
             else {              else {
                 unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A');                  unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A');
                 iperf_printf(test, report_bw_retrans_cwnd_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:"");                  iperf_printf(test, report_bw_retrans_cwnd_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:"");
Line 3840  iperf_new_stream(struct iperf_test *test, int s, int s Line 4306  iperf_new_stream(struct iperf_test *test, int s, int s
             tempdir = getenv("TMP");              tempdir = getenv("TMP");
         }          }
         if (tempdir == 0){          if (tempdir == 0){
   #if defined(__ANDROID__)
               tempdir = "/data/local/tmp";
   #else
             tempdir = "/tmp";              tempdir = "/tmp";
   #endif
         }          }
         snprintf(template, sizeof(template) / sizeof(char), "%s/iperf3.XXXXXX", tempdir);          snprintf(template, sizeof(template) / sizeof(char), "%s/iperf3.XXXXXX", tempdir);
     }      }
Line 3865  iperf_new_stream(struct iperf_test *test, int s, int s Line 4335  iperf_new_stream(struct iperf_test *test, int s, int s
   
     memset(sp->result, 0, sizeof(struct iperf_stream_result));      memset(sp->result, 0, sizeof(struct iperf_stream_result));
     TAILQ_INIT(&sp->result->interval_results);      TAILQ_INIT(&sp->result->interval_results);
    
     /* Create and randomize the buffer */      /* Create and randomize the buffer */
     sp->buffer_fd = mkstemp(template);      sp->buffer_fd = mkstemp(template);
     if (sp->buffer_fd == -1) {      if (sp->buffer_fd == -1) {
Line 3893  iperf_new_stream(struct iperf_test *test, int s, int s Line 4363  iperf_new_stream(struct iperf_test *test, int s, int s
         free(sp);          free(sp);
         return NULL;          return NULL;
     }      }
       sp->pending_size = 0;
   
     /* Set socket */      /* Set socket */
     sp->socket = s;      sp->socket = s;
Line 3936  iperf_new_stream(struct iperf_test *test, int s, int s Line 4407  iperf_new_stream(struct iperf_test *test, int s, int s
   
 /**************************************************************************/  /**************************************************************************/
 int  int
iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)iperf_common_sockopts(struct iperf_test *test, int s)
 {  {
     socklen_t len;  
     int opt;      int opt;
   
     len = sizeof(struct sockaddr_storage);  
     if (getsockname(sp->socket, (struct sockaddr *) &sp->local_addr, &len) < 0) {  
         i_errno = IEINITSTREAM;  
         return -1;  
     }  
     len = sizeof(struct sockaddr_storage);  
     if (getpeername(sp->socket, (struct sockaddr *) &sp->remote_addr, &len) < 0) {  
         i_errno = IEINITSTREAM;  
         return -1;  
     }  
   
     /* Set IP TOS */      /* Set IP TOS */
     if ((opt = test->settings->tos)) {      if ((opt = test->settings->tos)) {
        if (getsockdomain(sp->socket) == AF_INET6) {        if (getsockdomain(s) == AF_INET6) {
 #ifdef IPV6_TCLASS  #ifdef IPV6_TCLASS
            if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) {            if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) {
                 i_errno = IESETCOS;                  i_errno = IESETCOS;
                 return -1;                  return -1;
             }              }
   
               /* if the control connection was established with a mapped v4 address
                  then set IP_TOS on v6 stream socket as well */
               if (iperf_get_mapped_v4(test)) {
                   if (setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {
                       /* ignore any failure of v4 TOS in IPv6 case */
                   }
               }
 #else  #else
             i_errno = IESETCOS;              i_errno = IESETCOS;
             return -1;              return -1;
 #endif  #endif
         } else {          } else {
            if (setsockopt(sp->socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {            if (setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {
                 i_errno = IESETTOS;                  i_errno = IESETTOS;
                 return -1;                  return -1;
             }              }
         }          }
     }      }
       return 0;
   }
   
   /**************************************************************************/
   int
   iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
   {
       int opt;
       socklen_t len;
   
       len = sizeof(struct sockaddr_storage);
       if (getsockname(sp->socket, (struct sockaddr *) &sp->local_addr, &len) < 0) {
           i_errno = IEINITSTREAM;
           return -1;
       }
       len = sizeof(struct sockaddr_storage);
       if (getpeername(sp->socket, (struct sockaddr *) &sp->remote_addr, &len) < 0) {
           i_errno = IEINITSTREAM;
           return -1;
       }
   
   #if defined(HAVE_DONT_FRAGMENT)
       /* Set Don't Fragment (DF). Only applicable to IPv4/UDP tests. */
       if (iperf_get_test_protocol_id(test) == Pudp &&
           getsockdomain(sp->socket) == AF_INET &&
           iperf_get_dont_fragment(test)) {
   
           /*
            * There are multiple implementations of this feature depending on the OS.
            * We need to handle separately Linux, UNIX, and Windows, as well as
            * the case that DF isn't supported at all (such as on macOS).
            */
   #if defined(IP_MTU_DISCOVER) /* Linux version of IP_DONTFRAG */
           opt = IP_PMTUDISC_DO;
           if (setsockopt(sp->socket, IPPROTO_IP, IP_MTU_DISCOVER, &opt, sizeof(opt)) < 0) {
               i_errno = IESETDONTFRAGMENT;
               return -1;
           }
   #else
   #if defined(IP_DONTFRAG) /* UNIX does IP_DONTFRAG */
           opt = 1;
           if (setsockopt(sp->socket, IPPROTO_IP, IP_DONTFRAG, &opt, sizeof(opt)) < 0) {
               i_errno = IESETDONTFRAGMENT;
               return -1;
           }
   #else
   #if defined(IP_DONTFRAGMENT) /* Windows does IP_DONTFRAGMENT */
           opt = 1;
           if (setsockopt(sp->socket, IPPROTO_IP, IP_DONTFRAGMENT, &opt, sizeof(opt)) < 0) {
               i_errno = IESETDONTFRAGMENT;
               return -1;
           }
   #else
           i_errno = IESETDONTFRAGMENT;
           return -1;
   #endif /* IP_DONTFRAGMENT */
   #endif /* IP_DONTFRAG */
   #endif /* IP_MTU_DISCOVER */
       }
   #endif /* HAVE_DONT_FRAGMENT */
   
     return 0;      return 0;
 }  }
   
Line 3987  iperf_add_stream(struct iperf_test *test, struct iperf Line 4514  iperf_add_stream(struct iperf_test *test, struct iperf
         sp->id = 1;          sp->id = 1;
     } else {      } else {
         // for (n = test->streams, i = 2; n->next; n = n->next, ++i);          // for (n = test->streams, i = 2; n->next; n = n->next, ++i);
           // NOTE: this would ideally be set to 1, however this will not
           //       be changed since it is not causing a significant problem
           //       and changing it would break multi-stream tests between old
           //       and new iperf3 versions.
         i = 2;          i = 2;
           prev = NULL;
         SLIST_FOREACH(n, &test->streams, streams) {          SLIST_FOREACH(n, &test->streams, streams) {
             prev = n;              prev = n;
             ++i;              ++i;
         }          }
        SLIST_INSERT_AFTER(prev, sp, streams);        if (prev) {
        sp->id = i;            SLIST_INSERT_AFTER(prev, sp, streams);
             sp->id = i;
          }
     }      }
 }  }
   
Line 4009  static int Line 4543  static int
 diskfile_send(struct iperf_stream *sp)  diskfile_send(struct iperf_stream *sp)
 {  {
     int r;      int r;
       int buffer_left = sp->diskfile_left; // represents total data in buffer to be sent out
     static int rtot;      static int rtot;
   
     /* if needed, read enough data from the disk to fill up the buffer */      /* if needed, read enough data from the disk to fill up the buffer */
     if (sp->diskfile_left < sp->test->settings->blksize && !sp->test->done) {      if (sp->diskfile_left < sp->test->settings->blksize && !sp->test->done) {
        r = read(sp->diskfile_fd, sp->buffer, sp->test->settings->blksize -        r = read(sp->diskfile_fd, sp->buffer, sp->test->settings->blksize -
                 sp->diskfile_left);                 sp->diskfile_left);
        rtot += r;        buffer_left += r;
        if (sp->test->debug) {        rtot += r;
            printf("read %d bytes from file, %d total\n", r, rtot);        if (sp->test->debug) {
            if (r != sp->test->settings->blksize - sp->diskfile_left)            printf("read %d bytes from file, %d total\n", r, rtot);
                printf("possible eof\n");        }
        }
        /* If there's no data left in the file or in the buffer, we're done */        // If the buffer doesn't contain a full buffer at this point,
        if (r == 0 && sp->diskfile_left == 0) {        // adjust the size of the data to send.
            sp->test->done = 1;        if (buffer_left != sp->test->settings->blksize) {
            if (sp->test->debug)            if (sp->test->debug)
                printf("done\n");                printf("possible eof\n");
        }            // setting data size to be sent,
             // which is less than full block/buffer size
             // (to be used by iperf_tcp_send, etc.)
             sp->pending_size = buffer_left;
         }
 
         // If there's no work left, we're done.
         if (buffer_left == 0) {
             sp->test->done = 1;
             if (sp->test->debug)
                   printf("done\n");
         }
     }      }
   
       // If there's no data left in the file or in the buffer, we're done.
       // No more data available to be sent.
       // Return without sending data to the network
       if( sp->test->done || buffer_left == 0 ){
           if (sp->test->debug)
                 printf("already done\n");
           sp->test->done = 1;
           return 0;
       }
   
     r = sp->snd2(sp);      r = sp->snd2(sp);
     if (r < 0) {      if (r < 0) {
         return r;          return r;
Line 4039  diskfile_send(struct iperf_stream *sp) Line 4595  diskfile_send(struct iperf_stream *sp)
      * front of the buffer so they can hopefully go out on the next       * front of the buffer so they can hopefully go out on the next
      * pass.       * pass.
      */       */
    sp->diskfile_left = sp->test->settings->blksize - r;    sp->diskfile_left = buffer_left - r;
     if (sp->diskfile_left && sp->diskfile_left < sp->test->settings->blksize) {      if (sp->diskfile_left && sp->diskfile_left < sp->test->settings->blksize) {
         memcpy(sp->buffer,          memcpy(sp->buffer,
                sp->buffer + (sp->test->settings->blksize - sp->diskfile_left),                 sp->buffer + (sp->test->settings->blksize - sp->diskfile_left),
Line 4057  diskfile_recv(struct iperf_stream *sp) Line 4613  diskfile_recv(struct iperf_stream *sp)
   
     r = sp->rcv2(sp);      r = sp->rcv2(sp);
     if (r > 0) {      if (r > 0) {
        (void) write(sp->diskfile_fd, sp->buffer, r);        // NOTE: Currently ignoring the return value of writing to disk
        (void) fsync(sp->diskfile_fd);        (void) (write(sp->diskfile_fd, sp->buffer, r) + 1);
     }      }
     return r;      return r;
 }  }
Line 4143  iperf_create_pidfile(struct iperf_test *test) Line 4699  iperf_create_pidfile(struct iperf_test *test)
                 }                  }
             }              }
         }          }
        
         /*          /*
         * File didn't exist, we couldn't read it, or it didn't correspond to          * File didn't exist, we couldn't read it, or it didn't correspond to
         * a running process.  Try to create it.          * a running process.  Try to create it.
          */           */
         fd = open(test->pidfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR);          fd = open(test->pidfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR);
         if (fd < 0) {          if (fd < 0) {
             return -1;              return -1;
         }          }
         snprintf(buf, sizeof(buf), "%d", getpid()); /* no trailing newline */          snprintf(buf, sizeof(buf), "%d", getpid()); /* no trailing newline */
        if (write(fd, buf, strlen(buf) + 1) < 0) {        if (write(fd, buf, strlen(buf)) < 0) {
             (void)close(fd);
             return -1;              return -1;
         }          }
         if (close(fd) < 0) {          if (close(fd) < 0) {
Line 4203  iperf_json_start(struct iperf_test *test) Line 4760  iperf_json_start(struct iperf_test *test)
 int  int
 iperf_json_finish(struct iperf_test *test)  iperf_json_finish(struct iperf_test *test)
 {  {
    if (test->title)    if (test->json_top) {
        cJSON_AddStringToObject(test->json_top, "title", test->title);        if (test->title) {
    if (test->extra_data)            cJSON_AddStringToObject(test->json_top, "title", test->title);
        cJSON_AddStringToObject(test->json_top, "extra_data", test->extra_data);        }
    /* Include server output */        if (test->extra_data) {
    if (test->json_server_output) {            cJSON_AddStringToObject(test->json_top, "extra_data", test->extra_data);
        cJSON_AddItemToObject(test->json_top, "server_output_json", test->json_server_output);        }
         /* Include server output */
         if (test->json_server_output) {
             cJSON_AddItemToObject(test->json_top, "server_output_json", test->json_server_output);
         }
         if (test->server_output_text) {
             cJSON_AddStringToObject(test->json_top, "server_output_text", test->server_output_text);
         }
         // Get ASCII rendering of JSON structure.  Then make our
         // own copy of it and return the storage that cJSON allocated
         // on our behalf.  We keep our own copy around.
         char *str = cJSON_Print(test->json_top);
         if (str == NULL) {
             return -1;
         }
         test->json_output_string = strdup(str);
         cJSON_free(str);
         if (test->json_output_string == NULL) {
             return -1;
         }
         fprintf(test->outfile, "%s\n", test->json_output_string);
         iflush(test);
         cJSON_Delete(test->json_top);
         test->json_top = NULL;
     }      }
    if (test->server_output_text) {    test->json_start = test->json_connected = test->json_intervals = test->json_server_output = test->json_end = NULL;
        cJSON_AddStringToObject(test->json_top, "server_output_text", test->server_output_text); 
    } 
    test->json_output_string = cJSON_Print(test->json_top); 
    if (test->json_output_string == NULL) 
        return -1; 
    fprintf(test->outfile, "%s\n", test->json_output_string); 
    iflush(test); 
    cJSON_free(test->json_output_string); 
    test->json_output_string = NULL; 
    cJSON_Delete(test->json_top); 
    test->json_top = test->json_start = test->json_connected = test->json_intervals = test->json_server_output = test->json_end = NULL; 
     return 0;      return 0;
 }  }
   
Line 4314  iperf_clearaffinity(struct iperf_test *test) Line 4883  iperf_clearaffinity(struct iperf_test *test)
 #endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */  #endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
 }  }
   
char iperf_timestr[100];static char iperf_timestr[100];
 static char linebuffer[1024];
   
 int  int
 iperf_printf(struct iperf_test *test, const char* format, ...)  iperf_printf(struct iperf_test *test, const char* format, ...)
 {  {
     va_list argp;      va_list argp;
    int r = -1;    int r = 0, r0;
     time_t now;      time_t now;
     struct tm *ltm = NULL;      struct tm *ltm = NULL;
     char *ct = NULL;      char *ct = NULL;
Line 4347  iperf_printf(struct iperf_test *test, const char* form Line 4917  iperf_printf(struct iperf_test *test, const char* form
      */       */
     if (test->role == 'c') {      if (test->role == 'c') {
         if (ct) {          if (ct) {
            fprintf(test->outfile, "%s", ct);            r0 = fprintf(test->outfile, "%s", ct);
             if (r0 < 0)
                 return r0;
             r += r0;
         }          }
        if (test->title)        if (test->title) {
            fprintf(test->outfile, "%s:  ", test->title);            r0 = fprintf(test->outfile, "%s:  ", test->title);
             if (r0 < 0)
                 return r0;
             r += r0;
         }
         va_start(argp, format);          va_start(argp, format);
        r = vfprintf(test->outfile, format, argp);        r0 = vfprintf(test->outfile, format, argp);
         va_end(argp);          va_end(argp);
           if (r0 < 0)
               return r0;
           r += r0;
     }      }
     else if (test->role == 's') {      else if (test->role == 's') {
         char linebuffer[1024];  
         int i = 0;  
         if (ct) {          if (ct) {
            i = sprintf(linebuffer, "%s", ct);            r0 = snprintf(linebuffer, sizeof(linebuffer), "%s", ct);
             if (r0 < 0)
                 return r0;
             r += r0;
         }          }
        va_start(argp, format);        /* Should always be true as long as sizeof(ct) < sizeof(linebuffer) */
        r = vsnprintf(linebuffer + i, sizeof(linebuffer), format, argp);        if (r < sizeof(linebuffer)) {
        va_end(argp);            va_start(argp, format);
             r0 = vsnprintf(linebuffer + r, sizeof(linebuffer) - r, format, argp);
             va_end(argp);
             if (r0 < 0)
                 return r0;
             r += r0;
         }
         fprintf(test->outfile, "%s", linebuffer);          fprintf(test->outfile, "%s", linebuffer);
   
         if (test->role == 's' && iperf_get_test_get_server_output(test)) {          if (test->role == 's' && iperf_get_test_get_server_output(test)) {

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>