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

version 1.1.1.1, 2016/10/18 13:28:18 version 1.1.1.3, 2023/09/27 11:14:54
Line 1 Line 1
 /*  /*
 * iperf, Copyright (c) 2014, 2015, 2016, 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 24 Line 24
  * This code is distributed under a BSD style license, see the LICENSE file   * This code is distributed under a BSD style license, see the LICENSE file
  * for complete information.   * for complete information.
  */   */
#define _GNU_SOURCE#ifndef _GNU_SOURCE
 # define _GNU_SOURCE
 #endif
 #define __USE_GNU  #define __USE_GNU
   
 #include "iperf_config.h"  #include "iperf_config.h"
Line 32 Line 34
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
   #include <time.h>
 #include <getopt.h>  #include <getopt.h>
 #include <errno.h>  #include <errno.h>
 #include <signal.h>  #include <signal.h>
Line 43 Line 46
 #include <netinet/in.h>  #include <netinet/in.h>
 #include <arpa/inet.h>  #include <arpa/inet.h>
 #include <netdb.h>  #include <netdb.h>
 #include <pthread.h>  
 #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 55 Line 56
 #include <sched.h>  #include <sched.h>
 #include <setjmp.h>  #include <setjmp.h>
 #include <stdarg.h>  #include <stdarg.h>
   #include <math.h>
   
 #if defined(HAVE_CPUSET_SETAFFINITY)  #if defined(HAVE_CPUSET_SETAFFINITY)
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/cpuset.h>  #include <sys/cpuset.h>
 #endif /* HAVE_CPUSET_SETAFFINITY */  #endif /* HAVE_CPUSET_SETAFFINITY */
   
   #if defined(__CYGWIN__) || defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
   #define CPU_SETSIZE __CPU_SETSIZE
   #endif /* __CYGWIN__, _WIN32, _WIN64, __WINDOWS__ */
   
   #if defined(HAVE_SETPROCESSAFFINITYMASK)
   #include <Windows.h>
   #endif /* HAVE_SETPROCESSAFFINITYMASK */
   
 #include "net.h"  #include "net.h"
 #include "iperf.h"  #include "iperf.h"
 #include "iperf_api.h"  #include "iperf_api.h"
 #include "iperf_udp.h"  #include "iperf_udp.h"
 #include "iperf_tcp.h"  #include "iperf_tcp.h"
#if defined(HAVE_SCTP)#if defined(HAVE_SCTP_H)
 #include "iperf_sctp.h"  #include "iperf_sctp.h"
#endif /* HAVE_SCTP */#endif /* HAVE_SCTP_H */
 #include "timer.h"  #include "timer.h"
   
 #include "cjson.h"  #include "cjson.h"
 #include "units.h"  #include "units.h"
 #include "tcp_window_size.h"  
 #include "iperf_util.h"  #include "iperf_util.h"
 #include "iperf_locale.h"  #include "iperf_locale.h"
 #include "version.h"  #include "version.h"
   #if defined(HAVE_SSL)
   #include <openssl/bio.h>
   #include <openssl/err.h>
   #include "iperf_auth.h"
   #endif /* HAVE_SSL */
   
 /* Forwards. */  /* Forwards. */
 static int send_parameters(struct iperf_test *test);  static int send_parameters(struct iperf_test *test);
Line 100  usage() Line 114  usage()
   
   
 void  void
usage_long()usage_long(FILE *f)
 {  {
    fprintf(stderr, usage_longstr, UDP_RATE / (1024*1024), DURATION, DEFAULT_TCP_BLKSIZE / 1024, DEFAULT_UDP_BLKSIZE / 1024);    fprintf(f, usage_longstr, DEFAULT_NO_MSG_RCVD_TIMEOUT, UDP_RATE / (1024*1024), DEFAULT_PACING_TIMER, DURATION, DEFAULT_TCP_BLKSIZE / 1024, DEFAULT_UDP_BLKSIZE);
 }  }
   
   
void warning(char *str)void warning(const char *str)
 {  {
     fprintf(stderr, "warning: %s\n", str);      fprintf(stderr, "warning: %s\n", str);
 }  }
Line 127  iperf_get_control_socket(struct iperf_test *ipt) Line 141  iperf_get_control_socket(struct iperf_test *ipt)
 }  }
   
 int  int
   iperf_get_control_socket_mss(struct iperf_test *ipt)
   {
       return ipt->ctrl_sck_mss;
   }
   
   int
 iperf_get_test_omit(struct iperf_test *ipt)  iperf_get_test_omit(struct iperf_test *ipt)
 {  {
     return ipt->omit;      return ipt->omit;
Line 144  iperf_get_test_rate(struct iperf_test *ipt) Line 164  iperf_get_test_rate(struct iperf_test *ipt)
     return ipt->settings->rate;      return ipt->settings->rate;
 }  }
   
   uint64_t
   iperf_get_test_bitrate_limit(struct iperf_test *ipt)
   {
       return ipt->settings->bitrate_limit;
   }
   
   double
   iperf_get_test_bitrate_limit_interval(struct iperf_test *ipt)
   {
       return ipt->settings->bitrate_limit_interval;
   }
   
 int  int
   iperf_get_test_bitrate_limit_stats_per_interval(struct iperf_test *ipt)
   {
       return ipt->settings->bitrate_limit_stats_per_interval;
   }
   
   uint64_t
   iperf_get_test_fqrate(struct iperf_test *ipt)
   {
       return ipt->settings->fqrate;
   }
   
   int
   iperf_get_test_pacing_timer(struct iperf_test *ipt)
   {
       return ipt->settings->pacing_timer;
   }
   
   uint64_t
   iperf_get_test_bytes(struct iperf_test *ipt)
   {
       return (uint64_t) ipt->settings->bytes;
   }
   
   uint64_t
   iperf_get_test_blocks(struct iperf_test *ipt)
   {
       return (uint64_t) ipt->settings->blocks;
   }
   
   int
 iperf_get_test_burst(struct iperf_test *ipt)  iperf_get_test_burst(struct iperf_test *ipt)
 {  {
     return ipt->settings->burst;      return ipt->settings->burst;
Line 163  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 199  iperf_get_test_num_streams(struct iperf_test *ipt) Line 267  iperf_get_test_num_streams(struct iperf_test *ipt)
 }  }
   
 int  int
   iperf_get_test_timestamps(struct iperf_test *ipt)
   {
       return ipt->timestamps;
   }
   
   const char *
   iperf_get_test_timestamp_format(struct iperf_test *ipt)
   {
       return ipt->timestamp_format;
   }
   
   int
   iperf_get_test_repeating_payload(struct iperf_test *ipt)
   {
       return ipt->repeating_payload;
   }
   
   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 258  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 271  iperf_get_test_one_off(struct iperf_test *ipt) Line 369  iperf_get_test_one_off(struct iperf_test *ipt)
 }  }
   
 int  int
iperf_get_no_fq_socket_pacing(struct iperf_test *ipt)iperf_get_test_tos(struct iperf_test *ipt)
 {  {
    return ipt->no_fq_socket_pacing;    return ipt->settings->tos;
 }  }
   
   char *
   iperf_get_test_extra_data(struct iperf_test *ipt)
   {
       return ipt->extra_data;
   }
   
   static const char iperf_version[] = IPERF_VERSION;
   char *
   iperf_get_iperf_version(void)
   {
       return (char*)iperf_version;
   }
   
   int
   iperf_get_test_no_delay(struct iperf_test *ipt)
   {
       return ipt->no_delay;
   }
   
   int
   iperf_get_test_connect_timeout(struct iperf_test *ipt)
   {
       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 327  iperf_set_test_blksize(struct iperf_test *ipt, int blk Line 486  iperf_set_test_blksize(struct iperf_test *ipt, int blk
 }  }
   
 void  void
   iperf_set_test_logfile(struct iperf_test *ipt, const char *logfile)
   {
       ipt->logfile = strdup(logfile);
   }
   
   void
 iperf_set_test_rate(struct iperf_test *ipt, uint64_t rate)  iperf_set_test_rate(struct iperf_test *ipt, uint64_t rate)
 {  {
     ipt->settings->rate = rate;      ipt->settings->rate = rate;
 }  }
   
 void  void
   iperf_set_test_bitrate_limit_maximum(struct iperf_test *ipt, uint64_t total_rate)
   {
       ipt->settings->bitrate_limit = total_rate;
   }
   
   void
   iperf_set_test_bitrate_limit_interval(struct iperf_test *ipt, uint64_t bitrate_limit_interval)
   {
       ipt->settings->bitrate_limit_interval = bitrate_limit_interval;
   }
   
   void
   iperf_set_test_bitrate_limit_stats_per_interval(struct iperf_test *ipt, uint64_t bitrate_limit_stats_per_interval)
   {
       ipt->settings->bitrate_limit_stats_per_interval = bitrate_limit_stats_per_interval;
   }
   
   void
   iperf_set_test_fqrate(struct iperf_test *ipt, uint64_t fqrate)
   {
       ipt->settings->fqrate = fqrate;
   }
   
   void
   iperf_set_test_pacing_timer(struct iperf_test *ipt, int pacing_timer)
   {
       ipt->settings->pacing_timer = pacing_timer;
   }
   
   void
   iperf_set_test_bytes(struct iperf_test *ipt, uint64_t bytes)
   {
       ipt->settings->bytes = (iperf_size_t) bytes;
   }
   
   void
   iperf_set_test_blocks(struct iperf_test *ipt, uint64_t blocks)
   {
       ipt->settings->blocks = (iperf_size_t) blocks;
   }
   
   void
 iperf_set_test_burst(struct iperf_test *ipt, int burst)  iperf_set_test_burst(struct iperf_test *ipt, int burst)
 {  {
     ipt->settings->burst = burst;      ipt->settings->burst = burst;
 }  }
   
 void  void
iperf_set_test_server_port(struct iperf_test *ipt, int server_port)iperf_set_test_bind_port(struct iperf_test *ipt, int bind_port)
 {  {
    ipt->server_port = server_port;    ipt->bind_port = bind_port;
 }  }
   
 void  void
   iperf_set_test_server_port(struct iperf_test *ipt, int srv_port)
   {
       ipt->server_port = srv_port;
   }
   
   void
 iperf_set_test_socket_bufsize(struct iperf_test *ipt, int socket_bufsize)  iperf_set_test_socket_bufsize(struct iperf_test *ipt, int socket_bufsize)
 {  {
     ipt->settings->socket_bufsize = socket_bufsize;      ipt->settings->socket_bufsize = socket_bufsize;
Line 356  iperf_set_test_num_streams(struct iperf_test *ipt, int Line 569  iperf_set_test_num_streams(struct iperf_test *ipt, int
     ipt->num_streams = num_streams;      ipt->num_streams = num_streams;
 }  }
   
   void
   iperf_set_test_repeating_payload(struct iperf_test *ipt, int repeating_payload)
   {
       ipt->repeating_payload = repeating_payload;
   }
   
   void
   iperf_set_test_timestamps(struct iperf_test *ipt, int timestamps)
   {
       ipt->timestamps = timestamps;
   }
   
   void
   iperf_set_test_timestamp_format(struct iperf_test *ipt, const char *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)
 {  {
    if (ipt->sender && ipt->protocol->id == Ptcp && has_tcpinfo_retransmits())    if (ipt->mode != RECEIVER && ipt->protocol->id == Ptcp && has_tcpinfo_retransmits())
         ipt->sender_has_retransmits = 1;          ipt->sender_has_retransmits = 1;
     else      else
         ipt->sender_has_retransmits = 0;          ipt->sender_has_retransmits = 0;
Line 369  void Line 630  void
 iperf_set_test_role(struct iperf_test *ipt, char role)  iperf_set_test_role(struct iperf_test *ipt, char role)
 {  {
     ipt->role = role;      ipt->role = role;
    if (role == 'c')    if (!ipt->reverse) {
        ipt->sender = 1;        if (ipt->bidirectional)
    else if (role == 's')            ipt->mode = BIDIRECTIONAL;
        ipt->sender = 0;        else if (role == 'c')
    if (ipt->reverse)            ipt->mode = SENDER;
        ipt->sender = ! ipt->sender;        else if (role == 's')
             ipt->mode = RECEIVER;
     } else {
         if (role == 'c')
             ipt->mode = RECEIVER;
         else if (role == 's')
             ipt->mode = SENDER;
     }
     check_sender_has_retransmits(ipt);      check_sender_has_retransmits(ipt);
 }  }
   
 void  void
iperf_set_test_server_hostname(struct iperf_test *ipt, char *server_hostname)iperf_set_test_server_hostname(struct iperf_test *ipt, const char *server_hostname)
 {  {
     ipt->server_hostname = strdup(server_hostname);      ipt->server_hostname = strdup(server_hostname);
 }  }
   
 void  void
iperf_set_test_template(struct iperf_test *ipt, char *tmp_template)iperf_set_test_template(struct iperf_test *ipt, const char *tmp_template)
 {  {
     ipt->tmp_template = strdup(tmp_template);      ipt->tmp_template = strdup(tmp_template);
 }  }
Line 394  void Line 662  void
 iperf_set_test_reverse(struct iperf_test *ipt, int reverse)  iperf_set_test_reverse(struct iperf_test *ipt, int reverse)
 {  {
     ipt->reverse = reverse;      ipt->reverse = reverse;
    if (ipt->reverse)    if (!ipt->reverse) {
        ipt->sender = ! ipt->sender;        if (ipt->role == 'c')
             ipt->mode = SENDER;
         else if (ipt->role == 's')
             ipt->mode = RECEIVER;
     } else {
         if (ipt->role == 'c')
             ipt->mode = RECEIVER;
         else if (ipt->role == 's')
             ipt->mode = SENDER;
     }
     check_sender_has_retransmits(ipt);      check_sender_has_retransmits(ipt);
 }  }
   
Line 429  iperf_set_test_unit_format(struct iperf_test *ipt, cha Line 706  iperf_set_test_unit_format(struct iperf_test *ipt, cha
     ipt->settings->unit_format = unit_format;      ipt->settings->unit_format = unit_format;
 }  }
   
   #if defined(HAVE_SSL)
 void  void
iperf_set_test_bind_address(struct iperf_test *ipt, char *bind_address)iperf_set_test_client_username(struct iperf_test *ipt, const char *client_username)
 {  {
    ipt->bind_address = strdup(bind_address);    ipt->settings->client_username = strdup(client_username);
 }  }
   
 void  void
   iperf_set_test_client_password(struct iperf_test *ipt, const char *client_password)
   {
       ipt->settings->client_password = strdup(client_password);
   }
   
   void
   iperf_set_test_client_rsa_pubkey(struct iperf_test *ipt, const char *client_rsa_pubkey_base64)
   {
       ipt->settings->client_rsa_pubkey = load_pubkey_from_base64(client_rsa_pubkey_base64);
   }
   
   void
   iperf_set_test_server_authorized_users(struct iperf_test *ipt, const char *server_authorized_users)
   {
       ipt->server_authorized_users = strdup(server_authorized_users);
   }
   
   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)
   {
       ipt->server_rsa_private_key = load_privkey_from_base64(server_rsa_privkey_base64);
   }
   #endif // HAVE_SSL
   
   void
   iperf_set_test_bind_address(struct iperf_test *ipt, const char *bnd_address)
   {
       ipt->bind_address = strdup(bnd_address);
   }
   
   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 448  iperf_set_test_one_off(struct iperf_test *ipt, int one Line 769  iperf_set_test_one_off(struct iperf_test *ipt, int one
 }  }
   
 void  void
iperf_set_no_fq_socket_pacing(struct iperf_test *ipt, int no_pacing)iperf_set_test_tos(struct iperf_test *ipt, int tos)
 {  {
    ipt->no_fq_socket_pacing = no_pacing;    ipt->settings->tos = tos;
 }  }
   
   void
   iperf_set_test_extra_data(struct iperf_test *ipt, const char *dat)
   {
       ipt->extra_data = strdup(dat);
   }
   
   void
   iperf_set_test_bidirectional(struct iperf_test* ipt, int bidirectional)
   {
       ipt->bidirectional = bidirectional;
       if (bidirectional)
           ipt->mode = BIDIRECTIONAL;
       else
           iperf_set_test_reverse(ipt, ipt->reverse);
   }
   
   void
   iperf_set_test_no_delay(struct iperf_test* ipt, int no_delay)
   {
       ipt->no_delay = no_delay;
   }
   
   void
   iperf_set_test_connect_timeout(struct iperf_test* ipt, int 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 501  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", 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));        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)
                iprintf(test, test_start_bytes, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->settings->bytes);                iperf_printf(test, test_start_bytes, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->settings->bytes, test->settings->tos);
             else if (test->settings->blocks)              else if (test->settings->blocks)
                iprintf(test, test_start_blocks, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->settings->blocks);                iperf_printf(test, test_start_blocks, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->settings->blocks, test->settings->tos);
             else              else
                iprintf(test, test_start_time, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->duration);                iperf_printf(test, test_start_time, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->duration, test->settings->tos);
         }          }
     }      }
 }  }
Line 518  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 529  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
 iperf_on_connect(struct iperf_test *test)  iperf_on_connect(struct iperf_test *test)
 {  {
     time_t now_secs;      time_t now_secs;
    const char* rfc1123_fmt = "%a, %d %b %Y %H:%M:%S GMT";    const char* rfc1123_fmt = "%a, %d %b %Y %H:%M:%S %Z";
     char now_str[100];      char now_str[100];
     char ipr[INET6_ADDRSTRLEN];      char ipr[INET6_ADDRSTRLEN];
     int port;      int port;
Line 544  iperf_on_connect(struct iperf_test *test) Line 928  iperf_on_connect(struct iperf_test *test)
     struct sockaddr_in *sa_inP;      struct sockaddr_in *sa_inP;
     struct sockaddr_in6 *sa_in6P;      struct sockaddr_in6 *sa_in6P;
     socklen_t len;      socklen_t len;
     int opt;  
   
     now_secs = time((time_t*) 0);      now_secs = time((time_t*) 0);
     (void) strftime(now_str, sizeof(now_str), rfc1123_fmt, gmtime(&now_secs));      (void) strftime(now_str, sizeof(now_str), rfc1123_fmt, gmtime(&now_secs));
     if (test->json_output)      if (test->json_output)
         cJSON_AddItemToObject(test->json_start, "timestamp", iperf_json_printf("time: %s  timesecs: %d", now_str, (int64_t) now_secs));          cJSON_AddItemToObject(test->json_start, "timestamp", iperf_json_printf("time: %s  timesecs: %d", now_str, (int64_t) now_secs));
     else if (test->verbose)      else if (test->verbose)
        iprintf(test, report_time, now_str);        iperf_printf(test, report_time, now_str);
   
     if (test->role == 'c') {      if (test->role == 'c') {
         if (test->json_output)          if (test->json_output)
             cJSON_AddItemToObject(test->json_start, "connecting_to", iperf_json_printf("host: %s  port: %d", test->server_hostname, (int64_t) test->server_port));              cJSON_AddItemToObject(test->json_start, "connecting_to", iperf_json_printf("host: %s  port: %d", test->server_hostname, (int64_t) test->server_port));
         else {          else {
            iprintf(test, report_connecting, test->server_hostname, test->server_port);            iperf_printf(test, report_connecting, test->server_hostname, test->server_port);
             if (test->reverse)              if (test->reverse)
                iprintf(test, report_reverse, test->server_hostname);                iperf_printf(test, report_reverse, test->server_hostname);
         }          }
     } else {      } else {
         len = sizeof(sa);          len = sizeof(sa);
Line 573  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
            iprintf(test, report_accepted, ipr, port);            iperf_printf(test, report_accepted, ipr, port);
     }      }
     if (test->json_output) {      if (test->json_output) {
         cJSON_AddStringToObject(test->json_start, "cookie", test->cookie);          cJSON_AddStringToObject(test->json_start, "cookie", test->cookie);
Line 585  iperf_on_connect(struct iperf_test *test) Line 970  iperf_on_connect(struct iperf_test *test)
             if (test->settings->mss)              if (test->settings->mss)
                 cJSON_AddNumberToObject(test->json_start, "tcp_mss", test->settings->mss);                  cJSON_AddNumberToObject(test->json_start, "tcp_mss", test->settings->mss);
             else {              else {
                len = sizeof(opt);                cJSON_AddNumberToObject(test->json_start, "tcp_mss_default", test->ctrl_sck_mss);
                getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len); 
                cJSON_AddNumberToObject(test->json_start, "tcp_mss_default", opt); 
             }              }
        }        }
         // 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) {
        iprintf(test, report_cookie, test->cookie);        iperf_printf(test, report_cookie, test->cookie);
         if (test->protocol->id == SOCK_STREAM) {          if (test->protocol->id == SOCK_STREAM) {
             if (test->settings->mss)              if (test->settings->mss)
                iprintf(test, "      TCP MSS: %d\n", test->settings->mss);                iperf_printf(test, "      TCP MSS: %d\n", test->settings->mss);
             else {              else {
                len = sizeof(opt);                iperf_printf(test, "      TCP MSS: %d (default)\n", test->ctrl_sck_mss);
                getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len); 
                iprintf(test, "      TCP MSS: %d (default)\n", opt); 
             }              }
         }          }
        if (test->settings->rate)
             iperf_printf(test, "      Target Bitrate: %"PRIu64"\n", test->settings->rate);
     }      }
 }  }
   
Line 613  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 629  iperf_parse_arguments(struct iperf_test *test, int arg Line 1062  iperf_parse_arguments(struct iperf_test *test, int arg
         {"server", no_argument, NULL, 's'},          {"server", no_argument, NULL, 's'},
         {"client", required_argument, NULL, 'c'},          {"client", required_argument, NULL, 'c'},
         {"udp", no_argument, NULL, 'u'},          {"udp", no_argument, NULL, 'u'},
           {"bitrate", required_argument, NULL, 'b'},
         {"bandwidth", required_argument, NULL, 'b'},          {"bandwidth", required_argument, NULL, 'b'},
           {"server-bitrate-limit", required_argument, NULL, OPT_SERVER_BITRATE_LIMIT},
         {"time", required_argument, NULL, 't'},          {"time", required_argument, NULL, 't'},
         {"bytes", required_argument, NULL, 'n'},          {"bytes", required_argument, NULL, 'n'},
         {"blockcount", required_argument, NULL, 'k'},          {"blockcount", required_argument, NULL, 'k'},
         {"length", required_argument, NULL, 'l'},          {"length", required_argument, NULL, 'l'},
         {"parallel", required_argument, NULL, 'P'},          {"parallel", required_argument, NULL, 'P'},
         {"reverse", no_argument, NULL, 'R'},          {"reverse", no_argument, NULL, 'R'},
           {"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'},
         {"version4", no_argument, NULL, '4'},          {"version4", no_argument, NULL, '4'},
         {"version6", no_argument, NULL, '6'},          {"version6", no_argument, NULL, '6'},
         {"tos", required_argument, NULL, 'S'},          {"tos", required_argument, NULL, 'S'},
           {"dscp", required_argument, NULL, OPT_DSCP},
           {"extra-data", required_argument, NULL, OPT_EXTRA_DATA},
 #if defined(HAVE_FLOWLABEL)  #if defined(HAVE_FLOWLABEL)
         {"flowlabel", required_argument, NULL, 'L'},          {"flowlabel", required_argument, NULL, 'L'},
 #endif /* HAVE_FLOWLABEL */  #endif /* HAVE_FLOWLABEL */
         {"zerocopy", no_argument, NULL, 'Z'},          {"zerocopy", no_argument, NULL, 'Z'},
         {"omit", required_argument, NULL, 'O'},          {"omit", required_argument, NULL, 'O'},
         {"file", required_argument, NULL, 'F'},          {"file", required_argument, NULL, 'F'},
           {"repeating-payload", no_argument, NULL, OPT_REPEATING_PAYLOAD},
           {"timestamps", optional_argument, NULL, OPT_TIMESTAMPS},
 #if defined(HAVE_CPU_AFFINITY)  #if defined(HAVE_CPU_AFFINITY)
         {"affinity", required_argument, NULL, 'A'},          {"affinity", required_argument, NULL, 'A'},
 #endif /* HAVE_CPU_AFFINITY */  #endif /* HAVE_CPU_AFFINITY */
Line 658  iperf_parse_arguments(struct iperf_test *test, int arg Line 1101  iperf_parse_arguments(struct iperf_test *test, int arg
         {"congestion", required_argument, NULL, 'C'},          {"congestion", required_argument, NULL, 'C'},
         {"linux-congestion", required_argument, NULL, 'C'},          {"linux-congestion", required_argument, NULL, 'C'},
 #endif /* HAVE_TCP_CONGESTION */  #endif /* HAVE_TCP_CONGESTION */
#if defined(HAVE_SCTP)#if defined(HAVE_SCTP_H)
         {"sctp", no_argument, NULL, OPT_SCTP},          {"sctp", no_argument, NULL, OPT_SCTP},
         {"nstreams", required_argument, NULL, OPT_NUMSTREAMS},          {"nstreams", required_argument, NULL, OPT_NUMSTREAMS},
         {"xbind", required_argument, NULL, 'X'},          {"xbind", required_argument, NULL, 'X'},
 #endif  #endif
         {"pidfile", required_argument, NULL, 'I'},          {"pidfile", required_argument, NULL, 'I'},
         {"logfile", required_argument, NULL, OPT_LOGFILE},          {"logfile", required_argument, NULL, OPT_LOGFILE},
           {"forceflush", no_argument, NULL, OPT_FORCEFLUSH},
         {"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},
        {"debug", no_argument, NULL, 'd'},#if defined(HAVE_DONT_FRAGMENT)
         {"dont-fragment", no_argument, NULL, OPT_DONT_FRAGMENT},
 #endif /* HAVE_DONT_FRAGMENT */
 #if defined(HAVE_SSL)
     {"username", required_argument, NULL, OPT_CLIENT_USERNAME},
     {"rsa-public-key-path", required_argument, NULL, OPT_CLIENT_RSA_PUBLIC_KEY},
     {"rsa-private-key-path", required_argument, NULL, OPT_SERVER_RSA_PRIVATE_KEY},
     {"authorized-users-path", required_argument, NULL, OPT_SERVER_AUTHORIZED_USERS},
     {"time-skew-threshold", required_argument, NULL, OPT_SERVER_SKEW_THRESHOLD},
 #endif /* HAVE_SSL */
         {"fq-rate", required_argument, NULL, OPT_FQ_RATE},
         {"pacing-timer", required_argument, NULL, OPT_PACING_TIMER},
         {"connect-timeout", required_argument, NULL, OPT_CONNECT_TIMEOUT},
         {"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 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;
       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)
     char *client_username = NULL, *client_rsa_public_key = NULL, *server_rsa_private_key = NULL;
 #endif /* HAVE_SSL */
 
     while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) {      while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) {
         switch (flag) {          switch (flag) {
             case 'p':              case 'p':
                test->server_port = atoi(optarg);                portno = atoi(optarg);
                 if (portno < 1 || portno > 65535) {
                     i_errno = IEBADPORT;
                     return -1;
                 }
                 test->server_port = portno;
                 break;                  break;
             case 'f':              case 'f':
                test->settings->unit_format = *optarg;                if (!optarg) {
                     i_errno = IEBADFORMAT;
                     return -1;
                 }
                 test->settings->unit_format = *optarg;
                 if (test->settings->unit_format == 'k' ||
                     test->settings->unit_format == 'K' ||
                     test->settings->unit_format == 'm' ||
                     test->settings->unit_format == 'M' ||
                     test->settings->unit_format == 'g' ||
                     test->settings->unit_format == 'G' ||
                     test->settings->unit_format == 't' ||
                     test->settings->unit_format == 'T') {
                         break;
                 }
                 else {
                     i_errno = IEBADFORMAT;
                     return -1;
                 }
                 break;                  break;
             case 'i':              case 'i':
                 /* XXX: could potentially want separate stat collection and reporting intervals,                  /* XXX: could potentially want separate stat collection and reporting intervals,
Line 716  iperf_parse_arguments(struct iperf_test *test, int arg Line 1207  iperf_parse_arguments(struct iperf_test *test, int arg
                 test->json_output = 1;                  test->json_output = 1;
                 break;                  break;
             case 'v':              case 'v':
                printf("%s\n%s\n%s\n", version, get_system_info(),                 printf("%s (cJSON %s)\n%s\n%s\n", version, cJSON_Version(), get_system_info(),
                        get_optional_features());                         get_optional_features());
                 exit(0);                  exit(0);
             case 's':              case 's':
Line 733  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);
                 client_flag = 1;                  client_flag = 1;
                 break;                  break;
             case OPT_SCTP:              case OPT_SCTP:
#if defined(HAVE_SCTP)#if defined(HAVE_SCTP_H)
                 set_protocol(test, Psctp);                  set_protocol(test, Psctp);
                 client_flag = 1;                  client_flag = 1;
#else /* HAVE_SCTP */                break;
 #else /* HAVE_SCTP_H */
                 i_errno = IEUNIMP;                  i_errno = IEUNIMP;
                 return -1;                  return -1;
#endif /* HAVE_SCTP */#endif /* HAVE_SCTP_H */
            break; 
   
             case OPT_NUMSTREAMS:              case OPT_NUMSTREAMS:
 #if defined(linux) || defined(__FreeBSD__)  #if defined(linux) || defined(__FreeBSD__)
Line 772  iperf_parse_arguments(struct iperf_test *test, int arg Line 1275  iperf_parse_arguments(struct iperf_test *test, int arg
                 rate_flag = 1;                  rate_flag = 1;
                 client_flag = 1;                  client_flag = 1;
                 break;                  break;
               case OPT_SERVER_BITRATE_LIMIT:
                   slash = strchr(optarg, '/');
                   if (slash) {
                       *slash = '\0';
                       ++slash;
                       test->settings->bitrate_limit_interval = atof(slash);
                       if (test->settings->bitrate_limit_interval != 0 &&  /* Using same Max/Min limits as for Stats Interval */
                           (test->settings->bitrate_limit_interval < MIN_INTERVAL || test->settings->bitrate_limit_interval > MAX_INTERVAL) ) {
                           i_errno = IETOTALINTERVAL;
                           return -1;
                       }
                   }
                   test->settings->bitrate_limit = unit_atof_rate(optarg);
                   server_flag = 1;
                   break;
             case 't':              case 't':
                 test->duration = atoi(optarg);                  test->duration = atoi(optarg);
                 if (test->duration > MAX_TIME) {                  if (test->duration > MAX_TIME) {
Line 802  iperf_parse_arguments(struct iperf_test *test, int arg Line 1320  iperf_parse_arguments(struct iperf_test *test, int arg
                 client_flag = 1;                  client_flag = 1;
                 break;                  break;
             case 'R':              case 'R':
                   if (test->bidirectional) {
                       i_errno = IEREVERSEBIDIR;
                       return -1;
                   }
                 iperf_set_test_reverse(test, 1);                  iperf_set_test_reverse(test, 1);
                 client_flag = 1;                  client_flag = 1;
                 break;                  break;
               case OPT_BIDIRECTIONAL:
                   if (test->reverse) {
                       i_errno = IEREVERSEBIDIR;
                       return -1;
                   }
                   iperf_set_test_bidirectional(test, 1);
                   client_flag = 1;
                   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
                test->settings->socket_bufsize = unit_atof(optarg);                // Do sanity checks as double-precision floating point
                if (test->settings->socket_bufsize > MAX_TCP_BUFFER) {                // to avoid possible integer overflows.
                 farg = unit_atof(optarg);
                 if (farg > (double) MAX_TCP_BUFFER) {
                     i_errno = IEBUFSIZE;                      i_errno = IEBUFSIZE;
                     return -1;                      return -1;
                 }                  }
                   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:
                test->bind_port = atoi(optarg);                portno = atoi(optarg);
                 if (portno < 1 || portno > 65535) {
                     i_errno = IEBADPORT;
                     return -1;
                 }
                 test->bind_port = portno;
                 break;                  break;
             case 'M':              case 'M':
                 test->settings->mss = atoi(optarg);                  test->settings->mss = atoi(optarg);
Line 848  iperf_parse_arguments(struct iperf_test *test, int arg Line 1404  iperf_parse_arguments(struct iperf_test *test, int arg
                 }                  }
                 client_flag = 1;                  client_flag = 1;
                 break;                  break;
               case OPT_DSCP:
                   test->settings->tos = parse_qos(optarg);
                   if(test->settings->tos < 0) {
                           i_errno = IEBADTOS;
                           return -1;
                   }
                   client_flag = 1;
                   break;
               case OPT_EXTRA_DATA:
                   test->extra_data = strdup(optarg);
                   client_flag = 1;
                   break;
             case 'L':              case 'L':
 #if defined(HAVE_FLOWLABEL)  #if defined(HAVE_FLOWLABEL)
                 test->settings->flowlabel = strtol(optarg, &endptr, 0);                  test->settings->flowlabel = strtol(optarg, &endptr, 0);
Line 884  iperf_parse_arguments(struct iperf_test *test, int arg Line 1452  iperf_parse_arguments(struct iperf_test *test, int arg
                 test->zerocopy = 1;                  test->zerocopy = 1;
                 client_flag = 1;                  client_flag = 1;
                 break;                  break;
               case OPT_REPEATING_PAYLOAD:
                   test->repeating_payload = 1;
                   client_flag = 1;
                   break;
               case OPT_TIMESTAMPS:
                   iperf_set_test_timestamps(test, 1);
                   if (optarg) {
                       iperf_set_test_timestamp_format(test, optarg);
                   }
                   else {
                       iperf_set_test_timestamp_format(test, TIMESTAMP_FORMAT);
                   }
                   break;
             case 'O':              case 'O':
                 test->omit = atoi(optarg);                  test->omit = atoi(optarg);
                 if (test->omit < 0 || test->omit > 60) {                  if (test->omit < 0 || test->omit > 60) {
Line 895  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 932  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);
                 break;                  break;
               case OPT_FORCEFLUSH:
                   test->forceflush = 1;
                   break;
             case OPT_GET_SERVER_OUTPUT:              case OPT_GET_SERVER_OUTPUT:
                 test->get_server_output = 1;                  test->get_server_output = 1;
                 client_flag = 1;                  client_flag = 1;
Line 949  iperf_parse_arguments(struct iperf_test *test, int arg Line 1566  iperf_parse_arguments(struct iperf_test *test, int arg
                 break;                  break;
             case OPT_NO_FQ_SOCKET_PACING:              case OPT_NO_FQ_SOCKET_PACING:
 #if defined(HAVE_SO_MAX_PACING_RATE)  #if defined(HAVE_SO_MAX_PACING_RATE)
                test->no_fq_socket_pacing = 1;                printf("Warning:  --no-fq-socket-pacing is deprecated\n");
                 test->settings->fqrate = 0;
                 client_flag = 1;
 #else /* HAVE_SO_MAX_PACING_RATE */  #else /* HAVE_SO_MAX_PACING_RATE */
                 i_errno = IEUNIMP;                  i_errno = IEUNIMP;
                 return -1;                  return -1;
 #endif  #endif
                 break;                  break;
            case 'h':            case OPT_FQ_RATE:
 #if defined(HAVE_SO_MAX_PACING_RATE)
                 test->settings->fqrate = unit_atof_rate(optarg);
                 client_flag = 1;
 #else /* HAVE_SO_MAX_PACING_RATE */
                 i_errno = IEUNIMP;
                 return -1;
 #endif
                 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)
         case OPT_CLIENT_USERNAME:
             client_username = strdup(optarg);
             break;
         case OPT_CLIENT_RSA_PUBLIC_KEY:
             client_rsa_public_key = strdup(optarg);
             break;
         case OPT_SERVER_RSA_PRIVATE_KEY:
             server_rsa_private_key = strdup(optarg);
             break;
         case OPT_SERVER_AUTHORIZED_USERS:
             test->server_authorized_users = strdup(optarg);
             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 */
             case OPT_PACING_TIMER:
                 test->settings->pacing_timer = unit_atoi(optarg);
                 client_flag = 1;
                 break;
             case OPT_CONNECT_TIMEOUT:
                 test->settings->connect_timeout = unit_atoi(optarg);
                 client_flag = 1;
                 break;
             case 'h':
                 usage_long(stdout);
                 exit(0);
             default:              default:
                usage_long();                fprintf(stderr, "\n");
                 usage();
                 exit(1);                  exit(1);
         }          }
     }      }
   
     /* Set logging to a file if specified, otherwise use the default (stdout) */  
     if (test->logfile) {  
         test->outfile = fopen(test->logfile, "a+");  
         if (test->outfile == NULL) {  
             i_errno = IELOGFILE;  
             return -1;  
         }  
     }  
   
     /* Check flag / role compatibility. */      /* Check flag / role compatibility. */
     if (test->role == 'c' && server_flag) {      if (test->role == 'c' && server_flag) {
        i_errno = IESERVERONLY;        i_errno = IESERVERONLY;
        return -1;        return -1;
     }      }
     if (test->role == 's' && client_flag) {      if (test->role == 's' && client_flag) {
        i_errno = IECLIENTONLY;        i_errno = IECLIENTONLY;
        return -1;        return -1;
     }      }
   
    if (!test->bind_address && test->bind_port) {#if defined(HAVE_SSL)
        i_errno = IEBIND;
     if (test->role == 's' && (client_username || client_rsa_public_key)){
         i_errno = IECLIENTONLY;
         return -1;          return -1;
       } else if (test->role == 'c' && (client_username || client_rsa_public_key) &&
           !(client_username && client_rsa_public_key)) {
           i_errno = IESETCLIENTAUTH;
           return -1;
       } else if (test->role == 'c' && (client_username && client_rsa_public_key)){
   
           char *client_password = NULL;
           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 */
           if ((client_password = getenv("IPERF3_PASSWORD")) != NULL)
                client_password = strdup(client_password);
           else if (iperf_getpass(&client_password, &s, stdin) < 0){
               i_errno = IESETCLIENTAUTH;
               return -1;
           }
   
           test->settings->client_username = client_username;
           test->settings->client_password = client_password;
           test->settings->client_rsa_pubkey = load_pubkey_from_file(client_rsa_public_key);
           free(client_rsa_public_key);
           client_rsa_public_key = NULL;
     }      }
   
       if (test->role == 'c' && (server_rsa_private_key || test->server_authorized_users)){
           i_errno = IESERVERONLY;
           return -1;
       } 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)) {
            i_errno = IESETSERVERAUTH;
           return -1;
       } else if (test->role == 's' && server_rsa_private_key) {
           test->server_rsa_private_key = load_privkey_from_file(server_rsa_private_key);
           if (test->server_rsa_private_key == NULL){
               iperf_err(test, "%s\n", ERR_error_string(ERR_get_error(), NULL));
               i_errno = IESETSERVERAUTH;
               return -1;
           }
               free(server_rsa_private_key);
               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
   
       // 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 = DEFAULT_UDP_BLKSIZE;            blksize = 0;      /* try to dynamically determine from MSS */
         else if (test->protocol->id == Psctp)          else if (test->protocol->id == Psctp)
             blksize = DEFAULT_SCTP_BLKSIZE;              blksize = DEFAULT_SCTP_BLKSIZE;
         else          else
             blksize = DEFAULT_TCP_BLKSIZE;              blksize = DEFAULT_TCP_BLKSIZE;
     }      }
    if (blksize <= 0 || blksize > MAX_BLOCKSIZE) {    if ((test->protocol->id != Pudp && blksize <= 0)
         || blksize > MAX_BLOCKSIZE) {
         i_errno = IEBLOCKSIZE;          i_errno = IEBLOCKSIZE;
         return -1;          return -1;
     }      }
     if (test->protocol->id == Pudp &&      if (test->protocol->id == Pudp &&
        blksize > MAX_UDP_BLOCKSIZE) {        (blksize > 0 &&
             (blksize < MIN_UDP_BLOCKSIZE || blksize > MAX_UDP_BLOCKSIZE))) {
         i_errno = IEUDPBLOCKSIZE;          i_errno = IEUDPBLOCKSIZE;
         return -1;          return -1;
     }      }
Line 1007  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 1033  iperf_parse_arguments(struct iperf_test *test, int arg Line 1777  iperf_parse_arguments(struct iperf_test *test, int arg
         return -1;          return -1;
     }      }
   
       /* Set Total-rate average interval to multiplicity of State interval */
       if (test->settings->bitrate_limit_interval != 0) {
           test->settings->bitrate_limit_stats_per_interval =
               (test->settings->bitrate_limit_interval <= test->stats_interval ?
               1 : round(test->settings->bitrate_limit_interval/test->stats_interval) );
       }
   
       /* Show warning if JSON output is used with explicit report format */
       if ((test->json_output) && (test->settings->unit_format != 'a')) {
           warning("Report format (-f) flag ignored with JSON output (-J)");
       }
   
       /* Show warning if JSON output is used with verbose or debug flags */
       if (test->json_output && test->verbose) {
           warning("Verbose output (-v) may interfere with JSON output (-J)");
       }
       if (test->json_output && test->debug) {
           warning("Debug output (-d) may interfere with JSON output (-J)");
       }
   
     return 0;      return 0;
 }  }
   
   /*
    * Open the file specified by test->logfile and set test->outfile to its' FD.
    */
   int iperf_open_logfile(struct iperf_test *test)
   {
       test->outfile = fopen(test->logfile, "a+");
       if (test->outfile == NULL) {
           i_errno = IELOGFILE;
           return -1;
       }
   
       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;
 }  }
   
 void  void
iperf_check_throttle(struct iperf_stream *sp, struct timeval *nowP)iperf_check_throttle(struct iperf_stream *sp, struct iperf_time *nowP)
 {  {
       struct iperf_time temp_time;
     double seconds;      double seconds;
     uint64_t bits_per_second;      uint64_t bits_per_second;
   
    if (sp->test->done)    if (sp->test->done || sp->test->settings->rate == 0)
         return;          return;
    seconds = timeval_diff(&sp->result->start_time_fixed, nowP);    iperf_time_diff(&sp->result->start_time_fixed, nowP, &temp_time);
     seconds = iperf_time_in_secs(&temp_time);
     bits_per_second = sp->result->bytes_sent * 8 / seconds;      bits_per_second = sp->result->bytes_sent * 8 / seconds;
     if (bits_per_second < sp->test->settings->rate) {      if (bits_per_second < sp->test->settings->rate) {
         sp->green_light = 1;          sp->green_light = 1;
Line 1066  iperf_check_throttle(struct iperf_stream *sp, struct t Line 1856  iperf_check_throttle(struct iperf_stream *sp, struct t
     }      }
 }  }
   
   /* Verify that average traffic is not greater than the specified limit */
   void
   iperf_check_total_rate(struct iperf_test *test, iperf_size_t last_interval_bytes_transferred)
   {
       double seconds;
       uint64_t bits_per_second;
       iperf_size_t total_bytes;
       int i;
   
       if (test->done || test->settings->bitrate_limit == 0)    // Continue only if check should be done
           return;
   
       /* Add last inetrval's transferred bytes to the array */
       if (++test->bitrate_limit_last_interval_index >= test->settings->bitrate_limit_stats_per_interval)
           test->bitrate_limit_last_interval_index = 0;
       test->bitrate_limit_intervals_traffic_bytes[test->bitrate_limit_last_interval_index] = last_interval_bytes_transferred;
   
       /* Ensure that enough stats periods passed to allow averaging throughput */
       test->bitrate_limit_stats_count += 1;
       if (test->bitrate_limit_stats_count < test->settings->bitrate_limit_stats_per_interval)
           return;
   
        /* Calculating total bytes traffic to be averaged */
       for (total_bytes = 0, i = 0; i < test->settings->bitrate_limit_stats_per_interval; i++) {
           total_bytes += test->bitrate_limit_intervals_traffic_bytes[i];
       }
   
       seconds = test->stats_interval * test->settings->bitrate_limit_stats_per_interval;
       bits_per_second = total_bytes * 8 / seconds;
       if (test->debug) {
           iperf_printf(test,"Interval %" PRIu64 " - throughput %" PRIu64 " bps (limit %" PRIu64 ")\n", test->bitrate_limit_stats_count, bits_per_second, test->settings->bitrate_limit);
       }
   
       if (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;
       }
   }
   
 int  int
 iperf_send(struct iperf_test *test, fd_set *write_setP)  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 timeval 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 1081  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)
            gettimeofday(&now, NULL);            iperf_time_now(&now);
         streams_active = 0;          streams_active = 0;
         SLIST_FOREACH(sp, &test->streams, streams) {          SLIST_FOREACH(sp, &test->streams, streams) {
            if (! test->no_fq_socket_pacing ||            if ((sp->green_light && sp->sender &&
                (sp->green_light && 
                  (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 1097  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)
                if (test->settings->rate != 0 && test->settings->burst == 0)                    ++test->blocks_sent;
                 if (no_throttle_check)
                     iperf_check_throttle(sp, &now);                      iperf_check_throttle(sp, &now);
                 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 (!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 */
        gettimeofday(&now, NULL);        iperf_time_now(&now);
         SLIST_FOREACH(sp, &test->streams, streams)          SLIST_FOREACH(sp, &test->streams, streams)
            iperf_check_throttle(sp, &now);            if (sp->sender)
                 iperf_check_throttle(sp, &now);
     }      }
     if (write_setP != NULL)      if (write_setP != NULL)
         SLIST_FOREACH(sp, &test->streams, streams)          SLIST_FOREACH(sp, &test->streams, streams)
Line 1129  iperf_recv(struct iperf_test *test, fd_set *read_setP) Line 1964  iperf_recv(struct iperf_test *test, fd_set *read_setP)
     struct iperf_stream *sp;      struct iperf_stream *sp;
   
     SLIST_FOREACH(sp, &test->streams, streams) {      SLIST_FOREACH(sp, &test->streams, streams) {
        if (FD_ISSET(sp->socket, read_setP)) {        if (FD_ISSET(sp->socket, read_setP) && !sp->sender) {
             if ((r = sp->rcv(sp)) < 0) {              if ((r = sp->rcv(sp)) < 0) {
                 i_errno = IESTREAMREAD;                  i_errno = IESTREAMREAD;
                 return r;                  return r;
             }              }
            test->bytes_sent += r;            test->bytes_received += r;
            ++test->blocks_sent;            ++test->blocks_received;
             FD_CLR(sp->socket, read_setP);              FD_CLR(sp->socket, read_setP);
         }          }
     }      }
Line 1146  iperf_recv(struct iperf_test *test, fd_set *read_setP) Line 1981  iperf_recv(struct iperf_test *test, fd_set *read_setP)
 int  int
 iperf_init_test(struct iperf_test *test)  iperf_init_test(struct iperf_test *test)
 {  {
    struct timeval now;    struct iperf_time now;
     struct iperf_stream *sp;      struct iperf_stream *sp;
   
     if (test->protocol->init) {      if (test->protocol->init) {
Line 1155  iperf_init_test(struct iperf_test *test) Line 1990  iperf_init_test(struct iperf_test *test)
     }      }
   
     /* Init each stream. */      /* Init each stream. */
    if (gettimeofday(&now, NULL) < 0) {    if (iperf_time_now(&now) < 0) {
         i_errno = IEINITTEST;          i_errno = IEINITTEST;
         return -1;          return -1;
     }      }
Line 1170  iperf_init_test(struct iperf_test *test) Line 2005  iperf_init_test(struct iperf_test *test)
 }  }
   
 static void  static void
send_timer_proc(TimerClientData client_data, struct timeval *nowP)send_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
 {  {
     struct iperf_stream *sp = client_data.p;      struct iperf_stream *sp = client_data.p;
   
Line 1184  send_timer_proc(TimerClientData client_data, struct ti Line 2019  send_timer_proc(TimerClientData client_data, struct ti
 int  int
 iperf_create_send_timers(struct iperf_test * test)  iperf_create_send_timers(struct iperf_test * test)
 {  {
    struct timeval now;    struct iperf_time now;
     struct iperf_stream *sp;      struct iperf_stream *sp;
     TimerClientData cd;      TimerClientData cd;
   
    if (gettimeofday(&now, NULL) < 0) {    if (iperf_time_now(&now) < 0) {
         i_errno = IEINITTEST;          i_errno = IEINITTEST;
         return -1;          return -1;
     }      }
     SLIST_FOREACH(sp, &test->streams, streams) {      SLIST_FOREACH(sp, &test->streams, streams) {
         sp->green_light = 1;          sp->green_light = 1;
        if (test->settings->rate != 0) {        if (test->settings->rate != 0 && sp->sender) {
             cd.p = sp;              cd.p = sp;
            sp->send_timer = tmr_create((struct timeval*) 0, send_timer_proc, cd, 100000L, 1);            sp->send_timer = tmr_create(NULL, send_timer_proc, cd, test->settings->pacing_timer, 1);
            /* (Repeat every tenth second - arbitrary often value.) */ 
             if (sp->send_timer == NULL) {              if (sp->send_timer == NULL) {
                 i_errno = IEINITTEST;                  i_errno = IEINITTEST;
                 return -1;                  return -1;
Line 1207  iperf_create_send_timers(struct iperf_test * test) Line 2041  iperf_create_send_timers(struct iperf_test * test)
     return 0;      return 0;
 }  }
   
   #if defined(HAVE_SSL)
   int test_is_authorized(struct iperf_test *test){
       if ( !(test->server_rsa_private_key && test->server_authorized_users)) {
           return 0;
       }
   
       if (test->settings->authtoken){
           char *username = NULL, *password = NULL;
           time_t ts;
           int rc = decode_auth_setting(test->debug, test->settings->authtoken, test->server_rsa_private_key, &username, &password, &ts);
           if (rc) {
               return -1;
           }
           int ret = check_authentication(username, password, ts, test->server_authorized_users, test->server_skew_threshold);
           if (ret == 0){
               if (test->debug) {
                 iperf_printf(test, report_authentication_succeeded, username, ts);
               }
               free(username);
               free(password);
               return 0;
           } else {
               if (test->debug) {
                   iperf_printf(test, report_authentication_failed, ret, username, ts);
               }
               free(username);
               free(password);
               return -1;
           }
       }
       return -1;
   }
   #endif //HAVE_SSL
   
 /**  /**
  * iperf_exchange_parameters - handles the param_Exchange part for client   * iperf_exchange_parameters - handles the param_Exchange part for client
  *   *
Line 1228  iperf_exchange_parameters(struct iperf_test *test) Line 2096  iperf_exchange_parameters(struct iperf_test *test)
         if (get_parameters(test) < 0)          if (get_parameters(test) < 0)
             return -1;              return -1;
   
   #if defined(HAVE_SSL)
           if (test_is_authorized(test) < 0){
               if (iperf_set_send_state(test, SERVER_ERROR) != 0)
                   return -1;
               i_errno = IEAUTHTEST;
               err = htonl(i_errno);
               if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
                   i_errno = IECTRLWRITE;
                   return -1;
               }
               return -1;
           }
   #endif //HAVE_SSL
   
         if ((s = test->protocol->listen(test)) < 0) {          if ((s = test->protocol->listen(test)) < 0) {
            if (iperf_set_send_state(test, SERVER_ERROR) != 0)                if (iperf_set_send_state(test, SERVER_ERROR) != 0)
                 return -1;                  return -1;
             err = htonl(i_errno);              err = htonl(i_errno);
             if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {              if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
Line 1243  iperf_exchange_parameters(struct iperf_test *test) Line 2125  iperf_exchange_parameters(struct iperf_test *test)
             }              }
             return -1;              return -1;
         }          }
   
         FD_SET(s, &test->read_set);          FD_SET(s, &test->read_set);
         test->max_fd = (s > test->max_fd) ? s : test->max_fd;          test->max_fd = (s > test->max_fd) ? s : test->max_fd;
         test->prot_listener = s;          test->prot_listener = s;
Line 1301  send_parameters(struct iperf_test *test) Line 2184  send_parameters(struct iperf_test *test)
         cJSON_AddNumberToObject(j, "omit", test->omit);          cJSON_AddNumberToObject(j, "omit", test->omit);
         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);
        if (test->duration)        cJSON_AddNumberToObject(j, "time", test->duration);
            cJSON_AddNumberToObject(j, "time", test->duration);        cJSON_AddNumberToObject(j, "num", test->settings->bytes);
        if (test->settings->bytes)        cJSON_AddNumberToObject(j, "blockcount", test->settings->blocks);
            cJSON_AddNumberToObject(j, "num", test->settings->bytes); 
        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 1314  send_parameters(struct iperf_test *test) Line 2194  send_parameters(struct iperf_test *test)
         cJSON_AddNumberToObject(j, "parallel", test->num_streams);          cJSON_AddNumberToObject(j, "parallel", test->num_streams);
         if (test->reverse)          if (test->reverse)
             cJSON_AddTrueToObject(j, "reverse");              cJSON_AddTrueToObject(j, "reverse");
           if (test->bidirectional)
                       cJSON_AddTrueToObject(j, "bidirectional");
         if (test->settings->socket_bufsize)          if (test->settings->socket_bufsize)
             cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);              cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);
         if (test->settings->blksize)          if (test->settings->blksize)
             cJSON_AddNumberToObject(j, "len", test->settings->blksize);              cJSON_AddNumberToObject(j, "len", test->settings->blksize);
         if (test->settings->rate)          if (test->settings->rate)
             cJSON_AddNumberToObject(j, "bandwidth", test->settings->rate);              cJSON_AddNumberToObject(j, "bandwidth", test->settings->rate);
           if (test->settings->fqrate)
               cJSON_AddNumberToObject(j, "fqrate", test->settings->fqrate);
           if (test->settings->pacing_timer)
               cJSON_AddNumberToObject(j, "pacing_timer", test->settings->pacing_timer);
         if (test->settings->burst)          if (test->settings->burst)
             cJSON_AddNumberToObject(j, "burst", test->settings->burst);              cJSON_AddNumberToObject(j, "burst", test->settings->burst);
         if (test->settings->tos)          if (test->settings->tos)
Line 1328  send_parameters(struct iperf_test *test) Line 2214  send_parameters(struct iperf_test *test)
             cJSON_AddNumberToObject(j, "flowlabel", test->settings->flowlabel);              cJSON_AddNumberToObject(j, "flowlabel", test->settings->flowlabel);
         if (test->title)          if (test->title)
             cJSON_AddStringToObject(j, "title", test->title);              cJSON_AddStringToObject(j, "title", test->title);
           if (test->extra_data)
               cJSON_AddStringToObject(j, "extra_data", test->extra_data);
         if (test->congestion)          if (test->congestion)
             cJSON_AddStringToObject(j, "congestion", test->congestion);              cJSON_AddStringToObject(j, "congestion", test->congestion);
           if (test->congestion_used)
               cJSON_AddStringToObject(j, "congestion_used", test->congestion_used);
         if (test->get_server_output)          if (test->get_server_output)
             cJSON_AddNumberToObject(j, "get_server_output", iperf_get_test_get_server_output(test));              cJSON_AddNumberToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
         if (test->udp_counters_64bit)          if (test->udp_counters_64bit)
             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->no_fq_socket_pacing)        if (test->repeating_payload)
            cJSON_AddNumberToObject(j, "no_fq_socket_pacing", iperf_get_no_fq_socket_pacing(test));            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)
         /* Send authentication parameters */
         if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){
             int rc = encode_auth_setting(test->settings->client_username, test->settings->client_password, test->settings->client_rsa_pubkey, &test->settings->authtoken);
   
               if (rc) {
                   cJSON_Delete(j);
                   i_errno = IESENDPARAMS;
                   return -1;
               }
   
               cJSON_AddStringToObject(j, "authtoken", test->settings->authtoken);
           }
   #endif // HAVE_SSL
         cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);          cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);
   
         if (test->debug) {          if (test->debug) {
            printf("send_parameters:\n%s\n", cJSON_Print(j));            char *str = cJSON_Print(j);
             printf("send_parameters:\n%s\n", str);
             cJSON_free(str);
         }          }
   
         if (JSON_write(test->ctrl_sck, j) < 0) {          if (JSON_write(test->ctrl_sck, j) < 0) {
Line 1367  get_parameters(struct iperf_test *test) Line 2278  get_parameters(struct iperf_test *test)
         r = -1;          r = -1;
     } else {      } else {
         if (test->debug) {          if (test->debug) {
            printf("get_parameters:\n%s\n", cJSON_Print(j));            char *str;
             str = cJSON_Print(j);
             printf("get_parameters:\n%s\n", str );
             cJSON_free(str);
         }          }
   
         if ((j_p = cJSON_GetObjectItem(j, "tcp")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "tcp")) != NULL)
Line 1382  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 1394  get_parameters(struct iperf_test *test) Line 2310  get_parameters(struct iperf_test *test)
             test->num_streams = j_p->valueint;              test->num_streams = j_p->valueint;
         if ((j_p = cJSON_GetObjectItem(j, "reverse")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "reverse")) != NULL)
             iperf_set_test_reverse(test, 1);              iperf_set_test_reverse(test, 1);
           if ((j_p = cJSON_GetObjectItem(j, "bidirectional")) != NULL)
               iperf_set_test_bidirectional(test, 1);
         if ((j_p = cJSON_GetObjectItem(j, "window")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "window")) != NULL)
             test->settings->socket_bufsize = j_p->valueint;              test->settings->socket_bufsize = j_p->valueint;
         if ((j_p = cJSON_GetObjectItem(j, "len")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "len")) != NULL)
             test->settings->blksize = j_p->valueint;              test->settings->blksize = j_p->valueint;
         if ((j_p = cJSON_GetObjectItem(j, "bandwidth")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "bandwidth")) != NULL)
             test->settings->rate = j_p->valueint;              test->settings->rate = j_p->valueint;
           if ((j_p = cJSON_GetObjectItem(j, "fqrate")) != NULL)
               test->settings->fqrate = j_p->valueint;
           if ((j_p = cJSON_GetObjectItem(j, "pacing_timer")) != NULL)
               test->settings->pacing_timer = j_p->valueint;
         if ((j_p = cJSON_GetObjectItem(j, "burst")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "burst")) != NULL)
             test->settings->burst = j_p->valueint;              test->settings->burst = j_p->valueint;
         if ((j_p = cJSON_GetObjectItem(j, "TOS")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "TOS")) != NULL)
Line 1408  get_parameters(struct iperf_test *test) Line 2330  get_parameters(struct iperf_test *test)
             test->settings->flowlabel = j_p->valueint;              test->settings->flowlabel = j_p->valueint;
         if ((j_p = cJSON_GetObjectItem(j, "title")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "title")) != NULL)
             test->title = strdup(j_p->valuestring);              test->title = strdup(j_p->valuestring);
           if ((j_p = cJSON_GetObjectItem(j, "extra_data")) != NULL)
               test->extra_data = strdup(j_p->valuestring);
         if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL)
             test->congestion = strdup(j_p->valuestring);              test->congestion = strdup(j_p->valuestring);
           if ((j_p = cJSON_GetObjectItem(j, "congestion_used")) != NULL)
               test->congestion_used = strdup(j_p->valuestring);
         if ((j_p = cJSON_GetObjectItem(j, "get_server_output")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "get_server_output")) != NULL)
             iperf_set_test_get_server_output(test, 1);              iperf_set_test_get_server_output(test, 1);
         if ((j_p = cJSON_GetObjectItem(j, "udp_counters_64bit")) != NULL)          if ((j_p = cJSON_GetObjectItem(j, "udp_counters_64bit")) != NULL)
             iperf_set_test_udp_counters_64bit(test, 1);              iperf_set_test_udp_counters_64bit(test, 1);
        if ((j_p = cJSON_GetObjectItem(j, "no_fq_socket_pacing")) != NULL)        if ((j_p = cJSON_GetObjectItem(j, "repeating_payload")) != NULL)
            iperf_set_no_fq_socket_pacing(test, 1);            test->repeating_payload = 1;
                if ((j_p = cJSON_GetObjectItem(j, "zerocopy")) != NULL)
        if (test->sender && test->protocol->id == Ptcp && has_tcpinfo_retransmits())            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 ((j_p = cJSON_GetObjectItem(j, "authtoken")) != NULL)
         test->settings->authtoken = strdup(j_p->valuestring);
 #endif //HAVE_SSL
         if (test->mode && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
             test->sender_has_retransmits = 1;              test->sender_has_retransmits = 1;
           if (test->settings->rate)
               cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);
         cJSON_Delete(j);          cJSON_Delete(j);
     }      }
     return r;      return r;
Line 1437  send_results(struct iperf_test *test) Line 2374  send_results(struct iperf_test *test)
     int sender_has_retransmits;      int sender_has_retransmits;
     iperf_size_t bytes_transferred;      iperf_size_t bytes_transferred;
     int retransmits;      int retransmits;
       struct iperf_time temp_time;
       double start_time, end_time;
   
     j = cJSON_CreateObject();      j = cJSON_CreateObject();
     if (j == NULL) {      if (j == NULL) {
Line 1446  send_results(struct iperf_test *test) Line 2385  send_results(struct iperf_test *test)
         cJSON_AddNumberToObject(j, "cpu_util_total", test->cpu_util[0]);          cJSON_AddNumberToObject(j, "cpu_util_total", test->cpu_util[0]);
         cJSON_AddNumberToObject(j, "cpu_util_user", test->cpu_util[1]);          cJSON_AddNumberToObject(j, "cpu_util_user", test->cpu_util[1]);
         cJSON_AddNumberToObject(j, "cpu_util_system", test->cpu_util[2]);          cJSON_AddNumberToObject(j, "cpu_util_system", test->cpu_util[2]);
        if ( ! test->sender )        if ( test->mode == RECEIVER )
             sender_has_retransmits = -1;              sender_has_retransmits = -1;
         else          else
             sender_has_retransmits = test->sender_has_retransmits;              sender_has_retransmits = test->sender_has_retransmits;
         cJSON_AddNumberToObject(j, "sender_has_retransmits", sender_has_retransmits);          cJSON_AddNumberToObject(j, "sender_has_retransmits", sender_has_retransmits);
           if ( test->congestion_used ) {
               cJSON_AddStringToObject(j, "congestion_used", test->congestion_used);
           }
   
         /* If on the server and sending server output, then do this */          /* If on the server and sending server output, then do this */
         if (test->role == 's' && test->get_server_output) {          if (test->role == 's' && test->get_server_output) {
Line 1476  send_results(struct iperf_test *test) Line 2418  send_results(struct iperf_test *test)
                 }                  }
   
                 cJSON_AddStringToObject(j, "server_output_text", output);                  cJSON_AddStringToObject(j, "server_output_text", output);
           free(output);
             }              }
         }          }
   
Line 1492  send_results(struct iperf_test *test) Line 2435  send_results(struct iperf_test *test)
                     r = -1;                      r = -1;
                 } else {                  } else {
                     cJSON_AddItemToArray(j_streams, j_stream);                      cJSON_AddItemToArray(j_streams, j_stream);
                    bytes_transferred = test->sender ? (sp->result->bytes_sent - sp->result->bytes_sent_omit) : sp->result->bytes_received;                    bytes_transferred = sp->sender ? (sp->result->bytes_sent - sp->result->bytes_sent_omit) : sp->result->bytes_received;
                    retransmits = (test->sender && test->sender_has_retransmits) ? sp->result->stream_retrans : -1;                    retransmits = (sp->sender && test->sender_has_retransmits) ? sp->result->stream_retrans : -1;
                     cJSON_AddNumberToObject(j_stream, "id", sp->id);                      cJSON_AddNumberToObject(j_stream, "id", sp->id);
                     cJSON_AddNumberToObject(j_stream, "bytes", bytes_transferred);                      cJSON_AddNumberToObject(j_stream, "bytes", bytes_transferred);
                     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);
                       start_time = iperf_time_in_secs(&temp_time);
                       iperf_time_diff(&sp->result->start_time, &sp->result->end_time, &temp_time);
                       end_time = iperf_time_in_secs(&temp_time);
                       cJSON_AddNumberToObject(j_stream, "start_time", start_time);
                       cJSON_AddNumberToObject(j_stream, "end_time", end_time);
   
                 }                  }
             }              }
             if (r == 0 && test->debug) {              if (r == 0 && test->debug) {
                printf("send_results\n%s\n", cJSON_Print(j));                char *str = cJSON_Print(j);
                 printf("send_results\n%s\n", str);
                 cJSON_free(str);
             }              }
             if (r == 0 && JSON_write(test->ctrl_sck, j) < 0) {              if (r == 0 && JSON_write(test->ctrl_sck, j) < 0) {
                 i_errno = IESENDRESULTS;                  i_errno = IESENDRESULTS;
Line 1525  get_results(struct iperf_test *test) Line 2480  get_results(struct iperf_test *test)
     cJSON *j_cpu_util_total;      cJSON *j_cpu_util_total;
     cJSON *j_cpu_util_user;      cJSON *j_cpu_util_user;
     cJSON *j_cpu_util_system;      cJSON *j_cpu_util_system;
       cJSON *j_remote_congestion_used;
     cJSON *j_sender_has_retransmits;      cJSON *j_sender_has_retransmits;
     int result_has_retransmits;      int result_has_retransmits;
     cJSON *j_streams;      cJSON *j_streams;
Line 1535  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;
    int sid, cerror, pcount;    cJSON *j_start_time, *j_end_time;
     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 1557  get_results(struct iperf_test *test) Line 2517  get_results(struct iperf_test *test)
             r = -1;              r = -1;
         } else {          } else {
             if (test->debug) {              if (test->debug) {
                printf("get_results\n%s\n", cJSON_Print(j));                char *str = cJSON_Print(j);
                 printf("get_results\n%s\n", str);
                 cJSON_free(str);
             }              }
   
             test->remote_cpu_util[0] = j_cpu_util_total->valuedouble;              test->remote_cpu_util[0] = j_cpu_util_total->valuedouble;
             test->remote_cpu_util[1] = j_cpu_util_user->valuedouble;              test->remote_cpu_util[1] = j_cpu_util_user->valuedouble;
             test->remote_cpu_util[2] = j_cpu_util_system->valuedouble;              test->remote_cpu_util[2] = j_cpu_util_system->valuedouble;
             result_has_retransmits = j_sender_has_retransmits->valueint;              result_has_retransmits = j_sender_has_retransmits->valueint;
            if (! test->sender)            if ( test->mode == RECEIVER ) {
                test->sender_has_retransmits = result_has_retransmits;                test->sender_has_retransmits = result_has_retransmits;
                 test->other_side_has_retransmits = 0;
             }
             else if ( test->mode == BIDIRECTIONAL )
                 test->other_side_has_retransmits = result_has_retransmits;
 
             j_streams = cJSON_GetObjectItem(j, "streams");              j_streams = cJSON_GetObjectItem(j, "streams");
             if (j_streams == NULL) {              if (j_streams == NULL) {
                 i_errno = IERECVRESULTS;                  i_errno = IERECVRESULTS;
Line 1583  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_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 1594  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) {
                                 i_errno = IESTREAMID;                                  i_errno = IESTREAMID;
                                 r = -1;                                  r = -1;
                             } else {                              } else {
                                if (test->sender) {                                if (sp->sender) {
                                     sp->jitter = jitter;                                      sp->jitter = jitter;
                                     sp->cnt_error = cerror;                                      sp->cnt_error = cerror;
                                    sp->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 possibility that
                                        * start_time and end_time might not be
                                        * available; this is the case for older (pre-3.2)
                                        * servers.
                                        *
                                        * We need to have result structure members to hold
                                        * the both sides' start_time and end_time.
                                        */
                                       if (j_start_time && j_end_time) {
                                           sp->result->receiver_time = j_end_time->valuedouble - j_start_time->valuedouble;
                                       }
                                       else {
                                           sp->result->receiver_time = 0.0;
                                       }
                                 } else {                                  } else {
                                       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) {
                                           sp->result->sender_time = j_end_time->valuedouble - j_start_time->valuedouble;
                                       }
                                       else {
                                           sp->result->sender_time = 0.0;
                                       }
                                 }                                  }
                             }                              }
                         }                          }
Line 1633  get_results(struct iperf_test *test) Line 2651  get_results(struct iperf_test *test)
                 }                  }
             }              }
         }          }
   
           j_remote_congestion_used = cJSON_GetObjectItem(j, "congestion_used");
           if (j_remote_congestion_used != NULL) {
               test->remote_congestion_used = strdup(j_remote_congestion_used->valuestring);
           }
   
         cJSON_Delete(j);          cJSON_Delete(j);
     }      }
     return r;      return r;
Line 1659  JSON_write(int fd, cJSON *json) Line 2683  JSON_write(int fd, cJSON *json)
             if (Nwrite(fd, str, hsize, Ptcp) < 0)              if (Nwrite(fd, str, hsize, Ptcp) < 0)
                 r = -1;                  r = -1;
         }          }
        free(str);        cJSON_free(str);
     }      }
     return r;      return r;
 }  }
Line 1670  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 1682  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 1701  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 1754  connect_msg(struct iperf_stream *sp) Line 2785  connect_msg(struct iperf_stream *sp)
     if (sp->test->json_output)      if (sp->test->json_output)
         cJSON_AddItemToArray(sp->test->json_connected, iperf_json_printf("socket: %d  local_host: %s  local_port: %d  remote_host: %s  remote_port: %d", (int64_t) sp->socket, ipl, (int64_t) lport, ipr, (int64_t) rport));          cJSON_AddItemToArray(sp->test->json_connected, iperf_json_printf("socket: %d  local_host: %s  local_port: %d  remote_host: %s  remote_port: %d", (int64_t) sp->socket, ipl, (int64_t) lport, ipr, (int64_t) rport));
     else      else
        iprintf(sp->test, report_connected, sp->socket, ipl, lport, ipr, rport);        iperf_printf(sp->test, report_connected, sp->socket, ipl, lport, ipr, rport);
 }  }
   
   
Line 1781  iperf_new_test() Line 2812  iperf_new_test()
     }      }
     memset(test->settings, 0, sizeof(struct iperf_settings));      memset(test->settings, 0, sizeof(struct iperf_settings));
   
       test->bitrate_limit_intervals_traffic_bytes = (iperf_size_t *) malloc(sizeof(iperf_size_t) * MAX_INTERVAL);
       if (!test->bitrate_limit_intervals_traffic_bytes) {
           free(test->settings);
           free(test);
           i_errno = IENEWTEST;
           return NULL;
       }
       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 1806  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 1814  int Line 2854  int
 iperf_defaults(struct iperf_test *testp)  iperf_defaults(struct iperf_test *testp)
 {  {
     struct protocol *tcp, *udp;      struct protocol *tcp, *udp;
#if defined(HAVE_SCTP)#if defined(HAVE_SCTP_H)
     struct protocol *sctp;      struct protocol *sctp;
#endif /* HAVE_SCTP */#endif /* HAVE_SCTP_H */
   
     testp->omit = OMIT;      testp->omit = OMIT;
     testp->duration = DURATION;      testp->duration = DURATION;
Line 1828  iperf_defaults(struct iperf_test *testp) Line 2868  iperf_defaults(struct iperf_test *testp)
     CPU_ZERO(&testp->cpumask);      CPU_ZERO(&testp->cpumask);
 #endif /* HAVE_CPUSET_SETAFFINITY */  #endif /* HAVE_CPUSET_SETAFFINITY */
     testp->title = NULL;      testp->title = NULL;
       testp->extra_data = NULL;
     testp->congestion = NULL;      testp->congestion = NULL;
       testp->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->stats_callback = iperf_stats_callback;      testp->stats_callback = iperf_stats_callback;
     testp->reporter_callback = iperf_reporter_callback;      testp->reporter_callback = iperf_reporter_callback;
Line 1844  iperf_defaults(struct iperf_test *testp) Line 2889  iperf_defaults(struct iperf_test *testp)
     testp->settings->socket_bufsize = 0;    /* use autotuning */      testp->settings->socket_bufsize = 0;    /* use autotuning */
     testp->settings->blksize = DEFAULT_TCP_BLKSIZE;      testp->settings->blksize = DEFAULT_TCP_BLKSIZE;
     testp->settings->rate = 0;      testp->settings->rate = 0;
       testp->settings->bitrate_limit = 0;
       testp->settings->bitrate_limit_interval = 5;
       testp->settings->bitrate_limit_stats_per_interval = 0;
       testp->settings->fqrate = 0;
       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->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 1888  iperf_defaults(struct iperf_test *testp) Line 2943  iperf_defaults(struct iperf_test *testp)
   
     set_protocol(testp, Ptcp);      set_protocol(testp, Ptcp);
   
#if defined(HAVE_SCTP)#if defined(HAVE_SCTP_H)
     sctp = protocol_new();      sctp = protocol_new();
     if (!sctp) {      if (!sctp) {
         protocol_free(tcp);          protocol_free(tcp);
Line 1906  iperf_defaults(struct iperf_test *testp) Line 2961  iperf_defaults(struct iperf_test *testp)
     sctp->init = iperf_sctp_init;      sctp->init = iperf_sctp_init;
   
     SLIST_INSERT_AFTER(udp, sctp, protocols);      SLIST_INSERT_AFTER(udp, sctp, protocols);
#endif /* HAVE_SCTP */#endif /* HAVE_SCTP_H */
   
     testp->on_new_stream = iperf_on_new_stream;      testp->on_new_stream = iperf_on_new_stream;
     testp->on_test_start = iperf_on_test_start;      testp->on_test_start = iperf_on_test_start;
Line 1932  iperf_free_test(struct iperf_test *test) Line 2987  iperf_free_test(struct iperf_test *test)
         SLIST_REMOVE_HEAD(&test->streams, streams);          SLIST_REMOVE_HEAD(&test->streams, streams);
         iperf_free_stream(sp);          iperf_free_stream(sp);
     }      }
   
     if (test->server_hostname)      if (test->server_hostname)
         free(test->server_hostname);          free(test->server_hostname);
     if (test->tmp_template)      if (test->tmp_template)
         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 1951  iperf_free_test(struct iperf_test *test) Line 3007  iperf_free_test(struct iperf_test *test)
             free(xbe);              free(xbe);
         }          }
     }      }
   #if defined(HAVE_SSL)
   
       if (test->server_rsa_private_key)
         EVP_PKEY_free(test->server_rsa_private_key);
       test->server_rsa_private_key = NULL;
   
       free(test->settings->authtoken);
       test->settings->authtoken = NULL;
   
       free(test->settings->client_username);
       test->settings->client_username = NULL;
   
       free(test->settings->client_password);
       test->settings->client_password = NULL;
   
       if (test->settings->client_rsa_pubkey)
         EVP_PKEY_free(test->settings->client_rsa_pubkey);
       test->settings->client_rsa_pubkey = NULL;
   #endif /* HAVE_SSL */
   
     if (test->settings)      if (test->settings)
     free(test->settings);      free(test->settings);
     if (test->title)      if (test->title)
         free(test->title);          free(test->title);
       if (test->extra_data)
           free(test->extra_data);
     if (test->congestion)      if (test->congestion)
         free(test->congestion);          free(test->congestion);
       if (test->congestion_used)
           free(test->congestion_used);
       if (test->remote_congestion_used)
           free(test->remote_congestion_used);
       if (test->timestamp_format)
           free(test->timestamp_format);
     if (test->omit_timer != NULL)      if (test->omit_timer != NULL)
         tmr_cancel(test->omit_timer);          tmr_cancel(test->omit_timer);
     if (test->timer != NULL)      if (test->timer != NULL)
Line 1969  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) {
           free(test->logfile);
           test->logfile = NULL;
           iperf_close_logfile(test);
       }
   
     if (test->server_output_text) {      if (test->server_output_text) {
         free(test->server_output_text);          free(test->server_output_text);
         test->server_output_text = NULL;          test->server_output_text = NULL;
Line 2004  iperf_free_test(struct iperf_test *test) Line 3094  iperf_free_test(struct iperf_test *test)
         }          }
     }      }
   
       /* Free interval's traffic array for average rate calculations */
       if (test->bitrate_limit_intervals_traffic_bytes != NULL)
           free(test->bitrate_limit_intervals_traffic_bytes);
   
     /* XXX: Why are we setting these values to NULL? */      /* XXX: Why are we setting these values to NULL? */
     // test->streams = NULL;      // test->streams = NULL;
     test->stats_callback = NULL;      test->stats_callback = NULL;
Line 2016  void Line 3110  void
 iperf_reset_test(struct iperf_test *test)  iperf_reset_test(struct iperf_test *test)
 {  {
     struct iperf_stream *sp;      struct iperf_stream *sp;
       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 2043  iperf_reset_test(struct iperf_test *test) Line 3140  iperf_reset_test(struct iperf_test *test)
   
     SLIST_INIT(&test->streams);      SLIST_INIT(&test->streams);
   
       if (test->remote_congestion_used)
           free(test->remote_congestion_used);
       test->remote_congestion_used = NULL;
     test->role = 's';      test->role = 's';
    test->sender = 0;    test->mode = RECEIVER;
     test->sender_has_retransmits = 0;      test->sender_has_retransmits = 0;
     set_protocol(test, Ptcp);      set_protocol(test, Ptcp);
     test->omit = OMIT;      test->omit = OMIT;
Line 2054  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;
     test->blocks_sent = 0;      test->blocks_sent = 0;
   
       test->bytes_received = 0;
       test->blocks_received = 0;
   
       test->other_side_has_retransmits = 0;
   
       test->bitrate_limit_stats_count = 0;
       test->bitrate_limit_last_interval_index = 0;
       test->bitrate_limit_exceeded = 0;
   
       for (i = 0; i < MAX_INTERVAL; i++)
           test->bitrate_limit_intervals_traffic_bytes[i] = 0;
   
     test->reverse = 0;      test->reverse = 0;
       test->bidirectional = 0;
     test->no_delay = 0;      test->no_delay = 0;
   
     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;
     test->settings->rate = 0;      test->settings->rate = 0;
     test->settings->burst = 0;      test->settings->burst = 0;
     test->settings->mss = 0;      test->settings->mss = 0;
       test->settings->tos = 0;
       test->settings->dont_fragment = 0;
       test->zerocopy = 0;
   
   #if defined(HAVE_SSL)
       if (test->settings->authtoken) {
           free(test->settings->authtoken);
           test->settings->authtoken = NULL;
       }
       if (test->settings->client_username) {
           free(test->settings->client_username);
           test->settings->client_username = NULL;
       }
       if (test->settings->client_password) {
           free(test->settings->client_password);
           test->settings->client_password = NULL;
       }
       if (test->settings->client_rsa_pubkey) {
           EVP_PKEY_free(test->settings->client_rsa_pubkey);
           test->settings->client_rsa_pubkey = NULL;
       }
   #endif /* HAVE_SSL */
   
     memset(test->cookie, 0, COOKIE_SIZE);      memset(test->cookie, 0, COOKIE_SIZE);
     test->multisend = 10;       /* arbitrary */      test->multisend = 10;       /* arbitrary */
     test->udp_counters_64bit = 0;      test->udp_counters_64bit = 0;
       if (test->title) {
           free(test->title);
           test->title = NULL;
       }
       if (test->extra_data) {
           free(test->extra_data);
           test->extra_data = NULL;
       }
   
     /* Free output line buffers, if any (on the server only) */      /* Free output line buffers, if any (on the server only) */
     struct iperf_textline *t;      struct iperf_textline *t;
Line 2094  iperf_reset_test(struct iperf_test *test) Line 3239  iperf_reset_test(struct iperf_test *test)
 void  void
 iperf_reset_stats(struct iperf_test *test)  iperf_reset_stats(struct iperf_test *test)
 {  {
    struct timeval now;    struct iperf_time now;
     struct iperf_stream *sp;      struct iperf_stream *sp;
     struct iperf_stream_result *rp;      struct iperf_stream_result *rp;
   
     test->bytes_sent = 0;      test->bytes_sent = 0;
     test->blocks_sent = 0;      test->blocks_sent = 0;
    gettimeofday(&now, NULL);    iperf_time_now(&now);
     SLIST_FOREACH(sp, &test->streams, streams) {      SLIST_FOREACH(sp, &test->streams, streams) {
         sp->omitted_packet_count = sp->packet_count;          sp->omitted_packet_count = sp->packet_count;
         sp->omitted_cnt_error = sp->cnt_error;          sp->omitted_cnt_error = sp->cnt_error;
Line 2110  iperf_reset_stats(struct iperf_test *test) Line 3255  iperf_reset_stats(struct iperf_test *test)
         rp->bytes_sent_omit = rp->bytes_sent;          rp->bytes_sent_omit = rp->bytes_sent;
         rp->bytes_received = 0;          rp->bytes_received = 0;
         rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;          rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
        if (test->sender && test->sender_has_retransmits) {        if (test->sender_has_retransmits == 1) {
             struct iperf_interval_results ir; /* temporary results structure */              struct iperf_interval_results ir; /* temporary results structure */
             save_tcpinfo(sp, &ir);              save_tcpinfo(sp, &ir);
             rp->stream_prev_total_retrans = get_total_retransmits(&ir);              rp->stream_prev_total_retrans = get_total_retransmits(&ir);
Line 2133  iperf_stats_callback(struct iperf_test *test) Line 3278  iperf_stats_callback(struct iperf_test *test)
     struct iperf_stream *sp;      struct iperf_stream *sp;
     struct iperf_stream_result *rp = NULL;      struct iperf_stream_result *rp = NULL;
     struct iperf_interval_results *irp, temp;      struct iperf_interval_results *irp, temp;
       struct iperf_time temp_time;
       iperf_size_t total_interval_bytes_transferred = 0;
   
     temp.omitted = test->omitting;      temp.omitted = test->omitting;
     SLIST_FOREACH(sp, &test->streams, streams) {      SLIST_FOREACH(sp, &test->streams, streams) {
         rp = sp->result;          rp = sp->result;
           temp.bytes_transferred = sp->sender ? rp->bytes_sent_this_interval : rp->bytes_received_this_interval;
   
        temp.bytes_transferred = test->sender ? rp->bytes_sent_this_interval : rp->bytes_received_this_interval;        // Total bytes transferred 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 */
            memcpy(&temp.interval_start_time, &rp->end_time, sizeof(struct timeval));            memcpy(&temp.interval_start_time, &rp->end_time, sizeof(struct iperf_time));
         else /* or use timestamp from beginning */          else /* or use timestamp from beginning */
            memcpy(&temp.interval_start_time, &rp->start_time, sizeof(struct timeval));            memcpy(&temp.interval_start_time, &rp->start_time, sizeof(struct iperf_time));
         /* now save time of end of this interval */          /* now save time of end of this interval */
        gettimeofday(&rp->end_time, NULL);        iperf_time_now(&rp->end_time);
        memcpy(&temp.interval_end_time, &rp->end_time, sizeof(struct timeval));        memcpy(&temp.interval_end_time, &rp->end_time, sizeof(struct iperf_time));
        temp.interval_duration = timeval_diff(&temp.interval_start_time, &temp.interval_end_time);        iperf_time_diff(&temp.interval_start_time, &temp.interval_end_time, &temp_time);
        //temp.interval_duration = timeval_diff(&temp.interval_start_time, &temp.interval_end_time);        temp.interval_duration = iperf_time_in_secs(&temp_time);
         if (test->protocol->id == Ptcp) {          if (test->protocol->id == Ptcp) {
             if ( has_tcpinfo()) {              if ( has_tcpinfo()) {
                 save_tcpinfo(sp, &temp);                  save_tcpinfo(sp, &temp);
                if (test->sender && test->sender_has_retransmits) {                if (test->sender_has_retransmits == 1) {
                     long total_retrans = get_total_retransmits(&temp);                      long total_retrans = get_total_retransmits(&temp);
                     temp.interval_retrans = total_retrans - rp->stream_prev_total_retrans;                      temp.interval_retrans = total_retrans - rp->stream_prev_total_retrans;
                     rp->stream_retrans += temp.interval_retrans;                      rp->stream_retrans += temp.interval_retrans;
Line 2164  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 2175  iperf_stats_callback(struct iperf_test *test) Line 3329  iperf_stats_callback(struct iperf_test *test)
                     }                      }
                     rp->stream_sum_rtt += temp.rtt;                      rp->stream_sum_rtt += temp.rtt;
                     rp->stream_count_rtt++;                      rp->stream_count_rtt++;
   
                       temp.rttvar = get_rttvar(&temp);
                       temp.pmtu = get_pmtu(&temp);
                 }                  }
             }              }
         } else {          } else {
Line 2195  iperf_stats_callback(struct iperf_test *test) Line 3352  iperf_stats_callback(struct iperf_test *test)
         add_to_interval_list(rp, &temp);          add_to_interval_list(rp, &temp);
         rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;          rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
     }      }
   
       /* Verify that total server's throughput is not above specified limit */
       if (test->role == 's') {
           iperf_check_total_rate(test, total_interval_bytes_transferred);
       }
 }  }
   
 /**  /**
Line 2206  iperf_stats_callback(struct iperf_test *test) Line 3368  iperf_stats_callback(struct iperf_test *test)
 static void  static void
 iperf_print_intermediate(struct iperf_test *test)  iperf_print_intermediate(struct iperf_test *test)
 {  {
     char ubuf[UNIT_LEN];  
     char nbuf[UNIT_LEN];  
     struct iperf_stream *sp = NULL;      struct iperf_stream *sp = NULL;
     struct iperf_interval_results *irp;      struct iperf_interval_results *irp;
    iperf_size_t bytes = 0;    struct iperf_time temp_time;
    double bandwidth; 
    int retransmits = 0; 
    double start_time, end_time; 
     cJSON *json_interval;      cJSON *json_interval;
     cJSON *json_interval_streams;      cJSON *json_interval_streams;
     int total_packets = 0, lost_packets = 0;  
     double avg_jitter = 0.0, lost_percent;  
   
       int lower_mode, upper_mode;
       int current_mode;
   
       /*
        * Due to timing oddities, there can be cases, especially on the
        * server side, where at the end of a test there is a fairly short
        * interval with no data transferred.  This could caused by
        * the control and data flows sharing the same path in the network,
        * and having the control messages for stopping the test being
        * queued behind the data packets.
        *
        * We'd like to try to omit that last interval when it happens, to
        * avoid cluttering data and output with useless stuff.
        * So we're going to try to ignore very short intervals (less than
        * 10% of the interval time) that have no data.
        */
       int interval_ok = 0;
       SLIST_FOREACH(sp, &test->streams, streams) {
           irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);
           if (irp) {
               iperf_time_diff(&irp->interval_start_time, &irp->interval_end_time, &temp_time);
               double interval_len = iperf_time_in_secs(&temp_time);
               if (test->debug) {
                   printf("interval_len %f bytes_transferred %" PRIu64 "\n", interval_len, irp->bytes_transferred);
               }
   
               /*
                * If the interval is at least 10% the normal interval
                * length, or if there were actual bytes transferred,
                * then we want to keep this interval.
                */
               if (interval_len >= test->stats_interval * 0.10 ||
                   irp->bytes_transferred > 0) {
                   interval_ok = 1;
                   if (test->debug) {
                       printf("interval forces keep\n");
                   }
               }
           }
       }
       if (!interval_ok) {
           if (test->debug) {
               printf("ignoring short interval with no data\n");
           }
           return;
       }
   
     if (test->json_output) {      if (test->json_output) {
         json_interval = cJSON_CreateObject();          json_interval = cJSON_CreateObject();
         if (json_interval == NULL)          if (json_interval == NULL)
Line 2233  iperf_print_intermediate(struct iperf_test *test) Line 3435  iperf_print_intermediate(struct iperf_test *test)
         json_interval_streams = NULL;          json_interval_streams = NULL;
     }      }
   
    SLIST_FOREACH(sp, &test->streams, streams) {    /*
        print_interval_results(test, sp, json_interval_streams);     * We must to sum streams separately.
        /* sum up all streams */     * For bidirectional mode we must to display
        irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);     * information about sender and receiver streams.
        if (irp == NULL) {     * For client side we must handle sender streams
            iperf_err(test, "iperf_print_intermediate error: interval_results is NULL");     * firstly and receiver streams for server side.
            return;     * The following design allows us to do this.
        }     */
        bytes += irp->bytes_transferred;
        if (test->protocol->id == Ptcp) {    if (test->mode == BIDIRECTIONAL) {
            if (test->sender && test->sender_has_retransmits) {        if (test->role == 'c') {
                retransmits += irp->interval_retrans;            lower_mode = -1;
            }            upper_mode = 0;
        } else {        } else {
            total_packets += irp->interval_packet_count;            lower_mode = 0;
            lost_packets += irp->interval_cnt_error;            upper_mode = 1;
            avg_jitter += irp->jitter;        }
        }    } else {
         lower_mode = test->mode;
         upper_mode = lower_mode;
     }      }
   
     /* next build string with sum of all streams */  
     if (test->num_streams > 1 || test->json_output) {  
         sp = SLIST_FIRST(&test->streams); /* reset back to 1st stream */  
         /* Only do this of course if there was a first stream */  
         if (sp) {  
         irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);    /* use 1st stream for timing info */  
   
        unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A');    for (current_mode = lower_mode; current_mode <= upper_mode; ++current_mode) {
        bandwidth = (double) bytes / (double) irp->interval_duration;        char ubuf[UNIT_LEN];
        unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);        char nbuf[UNIT_LEN];
         char mbuf[UNIT_LEN];
         char zbuf[] = "          ";
   
        start_time = timeval_diff(&sp->result->start_time,&irp->interval_start_time);        iperf_size_t bytes = 0;
        end_time = timeval_diff(&sp->result->start_time,&irp->interval_end_time);        double bandwidth;
        if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {        int retransmits = 0;
            if (test->sender && test->sender_has_retransmits) {        double start_time, end_time;
                /* Interval sum, TCP with retransmits. */
                if (test->json_output)        int64_t total_packets = 0, lost_packets = 0;
                    cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  retransmits: %d  omitted: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) retransmits, irp->omitted)); /* XXX irp->omitted or test->omitting? */        double avg_jitter = 0.0, lost_percent;
                else        int stream_must_be_sender = current_mode * current_mode;
                    iprintf(test, report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, retransmits, irp->omitted?report_omitted:""); /* XXX irp->omitted or test->omitting? */
            } else {        char *sum_name;
                /* Interval sum, TCP without retransmits. */
                if (test->json_output)        /*  Print stream role just for bidirectional mode. */
                    cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  omitted: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, test->omitting));
                else        if (test->mode == BIDIRECTIONAL) {
                    iprintf(test, report_sum_bw_format, start_time, end_time, ubuf, nbuf, test->omitting?report_omitted:"");            sprintf(mbuf, "[%s-%s]", stream_must_be_sender?"TX":"RX", test->role == 'c'?"C":"S");
            }        } else {
        } else {            mbuf[0] = '\0';
            /* Interval sum, UDP. */            zbuf[0] = '\0';
            if (test->sender) {        }
                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", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) total_packets, test->omitting));        SLIST_FOREACH(sp, &test->streams, streams) {
                else            if (sp->sender == stream_must_be_sender) {
                    iprintf(test, report_sum_bw_udp_sender_format, start_time, end_time, ubuf, nbuf, total_packets, test->omitting?report_omitted:"");                print_interval_results(test, sp, json_interval_streams);
            } else {                /* sum up all streams */
                avg_jitter /= test->num_streams;                irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);
                if (total_packets > 0) {                if (irp == NULL) {
                    lost_percent = 100.0 * lost_packets / total_packets;                    iperf_err(test,
                }                            "iperf_print_intermediate error: interval_results is NULL");
                else {                    return;
                    lost_percent = 0.0;                }
                }                bytes += irp->bytes_transferred;
                if (test->json_output)                if (test->protocol->id == Ptcp) {
                    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", (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));                    if (test->sender_has_retransmits == 1) {
                else                        retransmits += irp->interval_retrans;
                    iprintf(test, report_sum_bw_udp_format, start_time, end_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, total_packets, lost_percent, test->omitting?report_omitted:"");                    }
            }                } else {
        }                    total_packets += irp->interval_packet_count;
        }                    lost_packets += irp->interval_cnt_error;
                     avg_jitter += irp->jitter;
                 }
             }
         }
 
         /* next build string with sum of all streams */
         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 */
             /* Only do this of course if there was a first stream */
             if (sp) {
             irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);    /* use 1st stream for timing info */
 
             unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A');
             bandwidth = (double) bytes / (double) irp->interval_duration;
             unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
 
             iperf_time_diff(&sp->result->start_time,&irp->interval_start_time, &temp_time);
             start_time = iperf_time_in_secs(&temp_time);
             iperf_time_diff(&sp->result->start_time,&irp->interval_end_time, &temp_time);
             end_time = iperf_time_in_secs(&temp_time);
                 if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
                     if (test->sender_has_retransmits == 1 && stream_must_be_sender) {
                         /* Interval sum, TCP with retransmits. */
                         if (test->json_output)
                             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
                             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 {
                         /* Interval sum, TCP without retransmits. */
                         if (test->json_output)
                             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
                             iperf_printf(test, report_sum_bw_format, mbuf, start_time, end_time, ubuf, nbuf, test->omitting?report_omitted:"");
                     }
                 } else {
                     /* Interval sum, UDP. */
                     if (stream_must_be_sender) {
                         if (test->json_output)
                             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
                             iperf_printf(test, report_sum_bw_udp_sender_format, mbuf, start_time, end_time, ubuf, nbuf, zbuf, total_packets, test->omitting?report_omitted:"");
                     } else {
                         avg_jitter /= test->num_streams;
                         if (total_packets > 0) {
                             lost_percent = 100.0 * lost_packets / total_packets;
                         }
                         else {
                             lost_percent = 0.0;
                         }
                         if (test->json_output)
                             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
                             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 2313  iperf_print_results(struct iperf_test *test) Line 3586  iperf_print_results(struct iperf_test *test)
 {  {
   
     cJSON *json_summary_streams = NULL;      cJSON *json_summary_streams = NULL;
     cJSON *json_summary_stream = NULL;  
     int total_retransmits = 0;  
     int total_packets = 0, lost_packets = 0;  
     char ubuf[UNIT_LEN];  
     char nbuf[UNIT_LEN];  
     struct stat sb;  
     char sbuf[UNIT_LEN];  
     struct iperf_stream *sp = NULL;  
     iperf_size_t bytes_sent, total_sent = 0;  
     iperf_size_t bytes_received, total_received = 0;  
     double start_time, end_time, avg_jitter = 0.0, lost_percent;  
     double bandwidth;  
   
       int lower_mode, upper_mode;
       int current_mode;
   
       char *sum_sent_name, *sum_received_name, *sum_name;
   
       int tmp_sender_has_retransmits = test->sender_has_retransmits;
   
     /* print final summary for all intervals */      /* print final summary for all intervals */
   
     if (test->json_output) {      if (test->json_output) {
Line 2334  iperf_print_results(struct iperf_test *test) Line 3602  iperf_print_results(struct iperf_test *test)
             return;              return;
         cJSON_AddItemToObject(test->json_end, "streams", json_summary_streams);          cJSON_AddItemToObject(test->json_end, "streams", json_summary_streams);
     } else {      } else {
        iprintf(test, "%s", report_bw_separator);        iperf_printf(test, "%s", report_bw_separator);
         if (test->verbose)          if (test->verbose)
            iprintf(test, "%s", report_summary);            iperf_printf(test, "%s", report_summary);
         if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {          if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
            if (test->sender_has_retransmits)            if (test->sender_has_retransmits || test->other_side_has_retransmits) {
                iprintf(test, "%s", report_bw_retrans_header);                if (test->bidirectional)
                     iperf_printf(test, "%s", report_bw_retrans_header_bidir);
                 else
                     iperf_printf(test, "%s", report_bw_retrans_header);
             }
             else {
                 if (test->bidirectional)
                     iperf_printf(test, "%s", report_bw_header_bidir);
                 else
                     iperf_printf(test, "%s", report_bw_header);
             }
         } else {
             if (test->bidirectional)
                 iperf_printf(test, "%s", report_bw_udp_header_bidir);
             else              else
                iprintf(test, "%s", report_bw_header);                iperf_printf(test, "%s", report_bw_udp_header);
        } else        }
            iprintf(test, "%s", report_bw_udp_header); 
     }      }
   
    start_time = 0.;    /*
    sp = SLIST_FIRST(&test->streams);     * We must to sum streams separately.
    /*      * For bidirectional mode we must to display
     * If there is at least one stream, then figure out the length of time     * information about sender and receiver streams.
     * we were running the tests and print out some statistics about     * For client side we must handle sender streams
     * the streams.  It's possible to not have any streams at all     * firstly and receiver streams for server side.
     * if the client got interrupted before it got to do anything.     * The following design allows us to do this.
      */       */
     if (sp) {  
     end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time);  
     SLIST_FOREACH(sp, &test->streams, streams) {  
         if (test->json_output) {  
             json_summary_stream = cJSON_CreateObject();  
             if (json_summary_stream == NULL)  
                 return;  
             cJSON_AddItemToArray(json_summary_streams, json_summary_stream);  
         }  
   
        bytes_sent = sp->result->bytes_sent - sp->result->bytes_sent_omit;    if (test->mode == BIDIRECTIONAL) {
        bytes_received = sp->result->bytes_received;        if (test->role == 'c') {
        total_sent += bytes_sent;            lower_mode = -1;
        total_received += bytes_received;            upper_mode = 0;
         } else {
             lower_mode = 0;
             upper_mode = 1;
         }
     } else {
         lower_mode = test->mode;
         upper_mode = lower_mode;
     }
   
        if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
            if (test->sender_has_retransmits) {    for (current_mode = lower_mode; current_mode <= upper_mode; ++current_mode) {
                total_retransmits += sp->result->stream_retrans;        cJSON *json_summary_stream = NULL;
            }        int64_t total_retransmits = 0;
        } else {        int64_t total_packets = 0, lost_packets = 0;
            total_packets += (sp->packet_count - sp->omitted_packet_count);        int64_t sender_packet_count = 0, receiver_packet_count = 0; /* for this stream, this interval */
            lost_packets += (sp->cnt_error - sp->omitted_cnt_error);        int64_t sender_omitted_packet_count = 0, receiver_omitted_packet_count = 0; /* for this stream, this interval */
            avg_jitter += sp->jitter;        int64_t sender_total_packets = 0, receiver_total_packets = 0; /* running total */
         char ubuf[UNIT_LEN];
         char nbuf[UNIT_LEN];
         struct stat sb;
         char sbuf[UNIT_LEN];
         struct iperf_stream *sp = NULL;
         iperf_size_t bytes_sent, total_sent = 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 sender_time = 0.0, receiver_time = 0.0;
         struct iperf_time temp_time;
         double bandwidth;
 
         char mbuf[UNIT_LEN];
         int stream_must_be_sender = current_mode * current_mode;
 
 
         /*  Print stream role just for bidirectional mode. */
 
         if (test->mode == BIDIRECTIONAL) {
             sprintf(mbuf, "[%s-%s]", stream_must_be_sender?"TX":"RX", test->role == 'c'?"C":"S");
         } else {
             mbuf[0] = '\0';
         }          }
   
        unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A');        /* Get sender_has_retransmits for each sender side (client and server) */
        bandwidth = (double) bytes_sent / (double) end_time;        if (test->mode == BIDIRECTIONAL && stream_must_be_sender)
        unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);            test->sender_has_retransmits = tmp_sender_has_retransmits;
        if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {        else if (test->mode == BIDIRECTIONAL && !stream_must_be_sender)
            if (test->sender_has_retransmits) {            test->sender_has_retransmits = test->other_side_has_retransmits;
                /* Summary, TCP with retransmits. */ 
                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", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_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))); 
                else 
                    iprintf(test, report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->result->stream_retrans, report_sender); 
            } else { 
                /* Summary, TCP without retransmits. */ 
                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", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8)); 
                else 
                    iprintf(test, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, report_sender); 
            } 
        } else { 
            /* Summary, UDP. */ 
            if (sp->packet_count - sp->omitted_packet_count > 0) { 
              lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (sp->packet_count - sp->omitted_packet_count); 
            } 
            else { 
                lost_percent = 0.0; 
            } 
            if (test->json_output) 
              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", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (sp->packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets))); 
            else { 
              iprintf(test, report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (sp->packet_count - sp->omitted_packet_count), lost_percent, ""); 
                if (test->role == 'c') 
                    iprintf(test, report_datagrams, sp->socket, (sp->packet_count - sp->omitted_packet_count)); 
                if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0) 
                  iprintf(test, report_sum_outoforder, start_time, end_time, (sp->outoforder_packets - sp->omitted_outoforder_packets)); 
            } 
        } 
   
        if (sp->diskfile_fd >= 0) {        start_time = 0.;
            if (fstat(sp->diskfile_fd, &sb) == 0) {        sp = SLIST_FIRST(&test->streams);
                int percent = (int) ( ( (double) bytes_sent / (double) sb.st_size ) * 100.0 ); 
                unit_snprintf(sbuf, UNIT_LEN, (double) sb.st_size, 'A'); 
                if (test->json_output) 
                    cJSON_AddItemToObject(json_summary_stream, "diskfile", iperf_json_printf("sent: %d  size: %d  percent: %d  filename: %s", (int64_t) bytes_sent, (int64_t) sb.st_size, (int64_t) percent, test->diskfile_name)); 
                else 
                    iprintf(test, report_diskfile, ubuf, sbuf, percent, test->diskfile_name); 
            } 
        } 
   
        unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');        /*
        bandwidth = (double) bytes_received / (double) end_time;         * If there is at least one stream, then figure out the length of time
        unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);         * we were running the tests and print out some statistics about
        if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {         * the streams.  It's possible to not have any streams at all
            if (test->json_output)         * if the client got interrupted before it got to do anything.
                cJSON_AddItemToObject(json_summary_stream, "receiver", iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8));         *
            else         * Also note that we try to keep separate values for the sender
                iprintf(test, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, report_receiver);         * and receiver ending times.  Earlier iperf (3.1 and earlier)
        }         * 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
    }         * basically emulating what iperf 3.1 did.
          */
   
    if (test->num_streams > 1 || test->json_output) {        if (sp) {
        unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');        iperf_time_diff(&sp->result->start_time, &sp->result->end_time, &temp_time);
        /* If no tests were run, arbitrariliy set bandwidth to 0. */        end_time = iperf_time_in_secs(&temp_time);
        if (end_time > 0.0) {        if (sp->sender) {
            bandwidth = (double) total_sent / (double) end_time;            sp->result->sender_time = end_time;
        }            if (sp->result->receiver_time == 0.0) {
        else {                sp->result->receiver_time = sp->result->sender_time;
            bandwidth = 0.0;            }
        }        }
        unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);        else {
        if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {            sp->result->receiver_time = end_time;
            if (test->sender_has_retransmits) {            if (sp->result->sender_time == 0.0) {
                /* Summary sum, TCP with retransmits. */                sp->result->sender_time = sp->result->receiver_time;
                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", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8, (int64_t) total_retransmits));        }
                else        sender_time = sp->result->sender_time;
                    iprintf(test, report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, total_retransmits, report_sender);        receiver_time = sp->result->receiver_time;
            } else {        SLIST_FOREACH(sp, &test->streams, streams) {
                /* Summary sum, TCP without retransmits. */            if (sp->sender == stream_must_be_sender) {
                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", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8));                    json_summary_stream = cJSON_CreateObject();
                else                    if (json_summary_stream == NULL)
                    iprintf(test, report_sum_bw_format, start_time, end_time, ubuf, nbuf, report_sender);                        return;
            }                    cJSON_AddItemToArray(json_summary_streams, json_summary_stream);
            unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');                }
            /* If no tests were run, set received bandwidth to 0 */
            if (end_time > 0.0) {                bytes_sent = sp->result->bytes_sent - sp->result->bytes_sent_omit;
                bandwidth = (double) total_received / (double) end_time;                bytes_received = sp->result->bytes_received;
            }                total_sent += bytes_sent;
            else {                total_received += bytes_received;
                bandwidth = 0.0;
            }                if (sp->sender) {
                     sender_packet_count = sp->packet_count;
                     sender_omitted_packet_count = sp->omitted_packet_count;
                     receiver_packet_count = sp->peer_packet_count;
                     receiver_omitted_packet_count = sp->peer_omitted_packet_count;
                 }
                 else {
                     sender_packet_count = sp->peer_packet_count;
                     sender_omitted_packet_count = sp->peer_omitted_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->sender_has_retransmits) {
                         total_retransmits += sp->result->stream_retrans;
                     }
                 } else {
                     /*
                      * Running total of the total number of packets.  Use the sender packet count if we
                      * have it, otherwise use the receiver packet count.
                      */
                     int64_t packet_count = sender_packet_count ? sender_packet_count : receiver_packet_count;
                     total_packets += (packet_count - sp->omitted_packet_count);
                     sender_total_packets += (sender_packet_count - sender_omitted_packet_count);
                     receiver_total_packets += (receiver_packet_count - receiver_omitted_packet_count);
                     lost_packets += sp->cnt_error;
                     if (sp->omitted_cnt_error > -1)
                          lost_packets -= sp->omitted_cnt_error;
                     avg_jitter += sp->jitter;
                 }
 
                 unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A');
                 if (sender_time > 0.0) {
                     bandwidth = (double) bytes_sent / (double) sender_time;
                 }
                 else {
                     bandwidth = 0.0;
                 }
                 unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
                 if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
                     if (test->sender_has_retransmits) {
                         /* Sender summary, TCP and SCTP with retransmits. */
                         if (test->json_output)
                             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
                             if (test->role == 's' && !sp->sender) {
                                 if (test->verbose)
                                     iperf_printf(test, report_sender_not_available_format, sp->socket);
                             }
                             else {
                                 iperf_printf(test, report_bw_retrans_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, sp->result->stream_retrans, report_sender);
                             }
                     } else {
                         /* Sender summary, TCP and SCTP without retransmits. */
                         if (test->json_output)
                             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
                             if (test->role == 's' && !sp->sender) {
                                 if (test->verbose)
                                     iperf_printf(test, report_sender_not_available_format, sp->socket);
                             }
                             else {
                                 iperf_printf(test, report_bw_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, report_sender);
                             }
                     }
                 } else {
                     /* Sender summary, UDP. */
                     if (sender_packet_count - sender_omitted_packet_count > 0) {
                         lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (sender_packet_count - sender_omitted_packet_count);
                     }
                     else {
                         lost_percent = 0.0;
                     }
                     if (test->json_output) {
                         /*
                          * For historical reasons, we only emit one JSON
                          * object for the UDP summary, and it contains
                          * information for both the sender and receiver
                          * side.
                          *
                          * The JSON format as currently defined only includes one
                          * value for the number of packets.  We usually want that
                          * to be the sender's value (how many packets were sent
                          * by the sender).  However this value might not be
                          * available on the receiver in certain circumstances
                          * specifically on the server side for a normal test or
                          * the client side for a reverse-mode test.  If this
                          * is the case, then use the receiver's count of packets
                          * instead.
                          */
                         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));
                     }
                     else {
                         /*
                          * Due to ordering of messages on the control channel,
                          * the server cannot report on client-side summary
                          * statistics.  If we're the server, omit one set of
                          * summary statistics to avoid giving meaningless
                          * results.
                          */
                         if (test->role == 's' && !sp->sender) {
                             if (test->verbose)
                                 iperf_printf(test, report_sender_not_available_format, sp->socket);
                         }
                         else {
                             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)
                           iperf_printf(test, report_sum_outoforder, mbuf, start_time, sender_time, (sp->outoforder_packets - sp->omitted_outoforder_packets));
                     }
                 }
 
                 if (sp->diskfile_fd >= 0) {
                     if (fstat(sp->diskfile_fd, &sb) == 0) {
                         /* In the odd case that it's a zero-sized file, say it was all transferred. */
                         int percent_sent = 100, percent_received = 100;
                         if (sb.st_size > 0) {
                             percent_sent = (int) ( ( (double) bytes_sent / (double) sb.st_size ) * 100.0 );
                             percent_received = (int) ( ( (double) bytes_received / (double) sb.st_size ) * 100.0 );
                         }
                         unit_snprintf(sbuf, UNIT_LEN, (double) sb.st_size, 'A');
                         if (test->json_output)
                             cJSON_AddItemToObject(json_summary_stream, "diskfile", iperf_json_printf("sent: %d  received: %d  size: %d  percent_sent: %d  percent_received: %d  filename: %s", (int64_t) bytes_sent, (int64_t) bytes_received, (int64_t) sb.st_size, (int64_t) percent_sent, (int64_t) percent_received, test->diskfile_name));
                         else
                             if (stream_must_be_sender) {
                                 iperf_printf(test, report_diskfile, ubuf, sbuf, percent_sent, test->diskfile_name);
                             }
                             else {
                                 unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
                                 iperf_printf(test, report_diskfile, ubuf, sbuf, percent_received, test->diskfile_name);
                             }
                     }
                 }
 
                 unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
                 if (receiver_time > 0) {
                     bandwidth = (double) bytes_received / (double) receiver_time;
                 }
                 else {
                     bandwidth = 0.0;
                 }
                 unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
                 if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
                     /* Receiver summary, TCP and SCTP */
                     if (test->json_output)
                         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
                         if (test->role == 's' && sp->sender) {
                             if (test->verbose)
                                 iperf_printf(test, report_receiver_not_available_format, sp->socket);
                         }
                         else {
                             iperf_printf(test, report_bw_format, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver);
                         }
                 }
                 else {
                     /*
                      * Receiver summary, UDP.  Note that JSON was emitted with
                      * the sender summary, so we only deal with human-readable
                      * data here.
                      */
                     if (! test->json_output) {
                         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 - receiver_omitted_packet_count);
                         }
                         else {
                             lost_percent = 0.0;
                         }
 
                         if (test->role == 's' && sp->sender) {
                             if (test->verbose)
                                 iperf_printf(test, report_receiver_not_available_format, sp->socket);
                         }
                         else {
                             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);
                             }
                         }
                     }
                 }
             }
         }
         }
 
         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');
             /* If no tests were run, arbitrarily set bandwidth to 0. */
             if (sender_time > 0.0) {
                 bandwidth = (double) total_sent / (double) sender_time;
             }
             else {
                 bandwidth = 0.0;
             }
             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->protocol->id == Ptcp || test->protocol->id == Psctp) {
                cJSON_AddItemToObject(test->json_end, "sum_received", iperf_json_printf("start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_received, bandwidth * 8));                if (test->sender_has_retransmits) {
            else                    /* Summary sum, TCP with retransmits. */
                iprintf(test, report_sum_bw_format, start_time, end_time, ubuf, nbuf, report_receiver);                    if (test->json_output)
        } else {                        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));
            /* Summary sum, UDP. */                    else
            avg_jitter /= test->num_streams;                        if (test->role == 's' && !stream_must_be_sender) {
            /* If no packets were sent, arbitrarily set loss percentage to 0. */                            if (test->verbose)
            if (total_packets > 0) {                                iperf_printf(test, report_sender_not_available_summary_format, "SUM");
                lost_percent = 100.0 * lost_packets / total_packets;                        }
            }                        else {
            else {                          iperf_printf(test, report_sum_bw_retrans_format, mbuf, start_time, sender_time, ubuf, nbuf, total_retransmits, report_sender);
                lost_percent = 0.0;                        }
            }                } else {
            if (test->json_output)                    /* Summary sum, TCP without retransmits. */
                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", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent));                    if (test->json_output)
            else                        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));
                iprintf(test, report_sum_bw_udp_format, start_time, end_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, total_packets, lost_percent, "");                    else
                         if (test->role == 's' && !stream_must_be_sender) {
                             if (test->verbose)
                                 iperf_printf(test, report_sender_not_available_summary_format, "SUM");
                         }
                         else {
                             iperf_printf(test, report_sum_bw_format, mbuf, start_time, sender_time, ubuf, nbuf, report_sender);
                         }
                 }
                 unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
                 /* If no tests were run, set received bandwidth to 0 */
                 if (receiver_time > 0.0) {
                     bandwidth = (double) total_received / (double) receiver_time;
                 }
                 else {
                     bandwidth = 0.0;
                 }
                 unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
                 if (test->json_output)
                     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
                     if (test->role == 's' && stream_must_be_sender) {
                         if (test->verbose)
                             iperf_printf(test, report_receiver_not_available_summary_format, "SUM");
                     }
                     else {
                         iperf_printf(test, report_sum_bw_format, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver);
                     }
             } else {
                 /* Summary sum, UDP. */
                 avg_jitter /= test->num_streams;
                 /* If no packets were sent, arbitrarily set loss percentage to 0. */
                 if (total_packets > 0) {
                     lost_percent = 100.0 * lost_packets / total_packets;
                 }
                 else {
                     lost_percent = 0.0;
                 }
                 if (test->json_output) {
                     /*
                      * 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
                      * stats.  On the server we have only the side that was on the
                      * server.  Output whatever we have.
                      */
                     if (! (test->role == 's' && !stream_must_be_sender) ) {
                         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, (int64_t) 0, sender_total_packets, 0.0, report_sender);
                     }
                     if (! (test->role == 's' && stream_must_be_sender) ) {
 
                         unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
                         /* Compute received bandwidth. */
                         if (end_time > 0.0) {
                             bandwidth = (double) total_received / (double) receiver_time;
                         }
                         else {
                             bandwidth = 0.0;
                         }
                         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, report_receiver);
                     }
                 }
             }
         }          }
     }  
   
    if (test->json_output)        if (test->json_output && current_mode == upper_mode) {
        cJSON_AddItemToObject(test->json_end, "cpu_utilization_percent", iperf_json_printf("host_total: %f  host_user: %f  host_system: %f  remote_total: %f  remote_user: %f  remote_system: %f", (double) test->cpu_util[0], (double) test->cpu_util[1], (double) test->cpu_util[2], (double) test->remote_cpu_util[0], (double) test->remote_cpu_util[1], (double) test->remote_cpu_util[2]));            cJSON_AddItemToObject(test->json_end, "cpu_utilization_percent", iperf_json_printf("host_total: %f  host_user: %f  host_system: %f  remote_total: %f  remote_user: %f  remote_system: %f", (double) test->cpu_util[0], (double) test->cpu_util[1], (double) test->cpu_util[2], (double) test->remote_cpu_util[0], (double) test->remote_cpu_util[1], (double) test->remote_cpu_util[2]));
    else {            if (test->protocol->id == Ptcp) {
        if (test->verbose) {                char *snd_congestion = NULL, *rcv_congestion = NULL;
            iprintf(test, report_cpu, report_local, test->sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, test->sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);                if (stream_must_be_sender) {
        }                    snd_congestion = test->congestion_used;
                     rcv_congestion = test->remote_congestion_used;
                 }
                 else {
                     snd_congestion = test->remote_congestion_used;
                     rcv_congestion = test->congestion_used;
                 }
                 if (snd_congestion) {
                     cJSON_AddStringToObject(test->json_end, "sender_tcp_congestion", snd_congestion);
                 }
                 if (rcv_congestion) {
                     cJSON_AddStringToObject(test->json_end, "receiver_tcp_congestion", rcv_congestion);
                 }
             }
         }
         else {
             if (test->verbose) {
                 if (stream_must_be_sender) {
                     if (test->bidirectional) {
                         iperf_printf(test, report_cpu, report_local, stream_must_be_sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, stream_must_be_sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
                         iperf_printf(test, report_cpu, report_local, !stream_must_be_sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, !stream_must_be_sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
                     } else
                         iperf_printf(test, report_cpu, report_local, stream_must_be_sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, stream_must_be_sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
                 }
                 if (test->protocol->id == Ptcp) {
                     char *snd_congestion = NULL, *rcv_congestion = NULL;
                     if (stream_must_be_sender) {
                         snd_congestion = test->congestion_used;
                         rcv_congestion = test->remote_congestion_used;
                     }
                     else {
                         snd_congestion = test->remote_congestion_used;
                         rcv_congestion = test->congestion_used;
                     }
                     if (snd_congestion) {
                         iperf_printf(test, "snd_tcp_congestion %s\n", snd_congestion);
                     }
                     if (rcv_congestion) {
                         iperf_printf(test, "rcv_tcp_congestion %s\n", rcv_congestion);
                     }
                 }
             }
   
        /* Print server output if we're on the client and it was requested/provided */            /* Print server output if we're on the client and it was requested/provided */
        if (test->role == 'c' && iperf_get_test_get_server_output(test)) {            if (test->role == 'c' && iperf_get_test_get_server_output(test) && !test->json_output) {
            if (test->json_server_output) {                if (test->json_server_output) {
                iprintf(test, "\nServer JSON output:\n%s\n", cJSON_Print(test->json_server_output));                    char *str = cJSON_Print(test->json_server_output);
                cJSON_Delete(test->json_server_output);                    iperf_printf(test, "\nServer JSON output:\n%s\n", str);
                test->json_server_output = NULL;                    cJSON_free(str);
            }                    cJSON_Delete(test->json_server_output);
            if (test->server_output_text) {                    test->json_server_output = NULL;
                iprintf(test, "\nServer output:\n%s\n", test->server_output_text);                }
                test->server_output_text = NULL;                if (test->server_output_text) {
            }                    iperf_printf(test, "\nServer output:\n%s\n", test->server_output_text);
        }                    test->server_output_text = NULL;
                 }
             }
         }
     }      }
   
       /* Set real sender_has_retransmits for current side */
       if (test->mode == BIDIRECTIONAL)
           test->sender_has_retransmits = tmp_sender_has_retransmits;
 }  }
   
 /**************************************************************************/  /**************************************************************************/
   
 /**  /**
  * 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 2536  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 2551  print_interval_results(struct iperf_test *test, struct Line 4155  print_interval_results(struct iperf_test *test, struct
     char ubuf[UNIT_LEN];      char ubuf[UNIT_LEN];
     char nbuf[UNIT_LEN];      char nbuf[UNIT_LEN];
     char cbuf[UNIT_LEN];      char cbuf[UNIT_LEN];
       char mbuf[UNIT_LEN];
       char zbuf[] = "          ";
     double st = 0., et = 0.;      double st = 0., et = 0.;
       struct iperf_time temp_time;
     struct iperf_interval_results *irp = NULL;      struct iperf_interval_results *irp = NULL;
     double bandwidth, lost_percent;      double bandwidth, lost_percent;
   
       if (test->mode == BIDIRECTIONAL) {
           sprintf(mbuf, "[%s-%s]", sp->sender?"TX":"RX", test->role == 'c'?"C":"S");
       } else {
           mbuf[0] = '\0';
           zbuf[0] = '\0';
       }
   
     irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* get last entry in linked list */      irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* get last entry in linked list */
     if (irp == NULL) {      if (irp == NULL) {
         iperf_err(test, "print_interval_results error: interval_results is NULL");          iperf_err(test, "print_interval_results error: interval_results is NULL");
Line 2567  print_interval_results(struct iperf_test *test, struct Line 4181  print_interval_results(struct iperf_test *test, struct
             ** else if there's more than one stream, print the separator;              ** else if there's more than one stream, print the separator;
             ** else nothing.              ** else nothing.
             */              */
            if (timeval_equals(&sp->result->start_time, &irp->interval_start_time)) {            if (iperf_time_compare(&sp->result->start_time, &irp->interval_start_time) == 0) {
                 if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {                  if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
                    if (test->sender && test->sender_has_retransmits)                    if (test->sender_has_retransmits == 1) {
                        iprintf(test, "%s", report_bw_retrans_cwnd_header);                        if (test->bidirectional)
                    else                            iperf_printf(test, "%s", report_bw_retrans_cwnd_header_bidir);
                        iprintf(test, "%s", report_bw_header);                        else
                             iperf_printf(test, "%s", report_bw_retrans_cwnd_header);
                     }
                     else {
                         if (test->bidirectional)
                             iperf_printf(test, "%s", report_bw_header_bidir);
                         else
                             iperf_printf(test, "%s", report_bw_header);
                     }
                 } else {                  } else {
                    if (test->sender)                    if (test->mode == SENDER) {
                        iprintf(test, "%s", report_bw_udp_sender_header);                        iperf_printf(test, "%s", report_bw_udp_sender_header);
                    else                    } else if (test->mode == RECEIVER){
                        iprintf(test, "%s", report_bw_udp_header);                        iperf_printf(test, "%s", report_bw_udp_header);
                     } else {
                         /* BIDIRECTIONAL */
                         iperf_printf(test, "%s", report_bw_udp_header_bidir);
                     }
                 }                  }
             } else if (test->num_streams > 1)              } else if (test->num_streams > 1)
                iprintf(test, "%s", report_bw_separator);                iperf_printf(test, "%s", report_bw_separator);
         }          }
     }      }
   
     unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A');      unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A');
    bandwidth = (double) irp->bytes_transferred / (double) irp->interval_duration;    if (irp->interval_duration > 0.0) {
         bandwidth = (double) irp->bytes_transferred / (double) irp->interval_duration;
     }
     else {
         bandwidth = 0.0;
     }
     unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);      unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
    
    st = timeval_diff(&sp->result->start_time, &irp->interval_start_time);    iperf_time_diff(&sp->result->start_time, &irp->interval_start_time, &temp_time);
    et = timeval_diff(&sp->result->start_time, &irp->interval_end_time);    st = iperf_time_in_secs(&temp_time);
        iperf_time_diff(&sp->result->start_time, &irp->interval_end_time, &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 && test->sender_has_retransmits) {        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  omitted: %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, irp->omitted));                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');
                iprintf(test, report_bw_retrans_cwnd_format, sp->socket, 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:"");
             }              }
         } else {          } else {
             /* Interval, TCP without retransmits. */              /* Interval, TCP without 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  omitted: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, irp->omitted));                cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, irp->omitted, sp->sender));
             else              else
                iprintf(test, report_bw_format, sp->socket, st, et, ubuf, nbuf, irp->omitted?report_omitted:"");                iperf_printf(test, report_bw_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->omitted?report_omitted:"");
         }          }
     } else {      } else {
         /* Interval, UDP. */          /* Interval, UDP. */
        if (test->sender) {        if (sp->sender) {
             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  packets: %d  omitted: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_packet_count, irp->omitted));                cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d  start: %f  end: %f  seconds: %f  bytes: %d  bits_per_second: %f  packets: %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_packet_count, irp->omitted, sp->sender));
             else              else
                iprintf(test, report_bw_udp_sender_format, sp->socket, st, et, ubuf, nbuf, irp->interval_packet_count, irp->omitted?report_omitted:"");                iperf_printf(test, report_bw_udp_sender_format, sp->socket, mbuf, st, et, ubuf, nbuf, zbuf, irp->interval_packet_count, irp->omitted?report_omitted:"");
         } else {          } else {
             if (irp->interval_packet_count > 0) {              if (irp->interval_packet_count > 0) {
                 lost_percent = 100.0 * irp->interval_cnt_error / irp->interval_packet_count;                  lost_percent = 100.0 * irp->interval_cnt_error / irp->interval_packet_count;
Line 2622  print_interval_results(struct iperf_test *test, struct Line 4255  print_interval_results(struct iperf_test *test, struct
                 lost_percent = 0.0;                  lost_percent = 0.0;
             }              }
             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  jitter_ms: %f  lost_packets: %d  packets: %d  lost_percent: %f  omitted: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (double) irp->jitter * 1000.0, (int64_t) irp->interval_cnt_error, (int64_t) irp->interval_packet_count, (double) lost_percent, irp->omitted));                cJSON_AddItemToArray(json_interval_streams, 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  omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (double) irp->jitter * 1000.0, (int64_t) irp->interval_cnt_error, (int64_t) irp->interval_packet_count, (double) lost_percent, irp->omitted, sp->sender));
             else              else
                iprintf(test, report_bw_udp_format, sp->socket, st, et, ubuf, nbuf, irp->jitter * 1000.0, irp->interval_cnt_error, irp->interval_packet_count, lost_percent, irp->omitted?report_omitted:"");                iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->jitter * 1000.0, irp->interval_cnt_error, irp->interval_packet_count, lost_percent, irp->omitted?report_omitted:"");
         }          }
     }      }
   
    if (test->logfile)    if (test->logfile || test->forceflush)
         iflush(test);          iflush(test);
 }  }
   
Line 2655  iperf_free_stream(struct iperf_stream *sp) Line 4288  iperf_free_stream(struct iperf_stream *sp)
   
 /**************************************************************************/  /**************************************************************************/
 struct iperf_stream *  struct iperf_stream *
iperf_new_stream(struct iperf_test *test, int s)iperf_new_stream(struct iperf_test *test, int s, int sender)
 {  {
     int i;  
     struct iperf_stream *sp;      struct iperf_stream *sp;
        int ret = 0;
 
     char template[1024];      char template[1024];
     if (test->tmp_template) {      if (test->tmp_template) {
         snprintf(template, sizeof(template) / sizeof(char), "%s", test->tmp_template);          snprintf(template, sizeof(template) / sizeof(char), "%s", test->tmp_template);
     } else {      } else {
        char buf[] = "/tmp/iperf3.XXXXXX";        //find the system temporary dir *unix, windows, cygwin support
        snprintf(template, sizeof(template) / sizeof(char), "%s", buf);        char* tempdir = getenv("TMPDIR");
         if (tempdir == 0){
             tempdir = getenv("TEMP");
         }
         if (tempdir == 0){
             tempdir = getenv("TMP");
         }
         if (tempdir == 0){
 #if defined(__ANDROID__)
             tempdir = "/data/local/tmp";
 #else
             tempdir = "/tmp";
 #endif
         }
         snprintf(template, sizeof(template) / sizeof(char), "%s/iperf3.XXXXXX", tempdir);
     }      }
   
     h_errno = 0;  
   
     sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream));      sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream));
     if (!sp) {      if (!sp) {
         i_errno = IECREATESTREAM;          i_errno = IECREATESTREAM;
Line 2678  iperf_new_stream(struct iperf_test *test, int s) Line 4323  iperf_new_stream(struct iperf_test *test, int s)
   
     memset(sp, 0, sizeof(struct iperf_stream));      memset(sp, 0, sizeof(struct iperf_stream));
   
       sp->sender = sender;
     sp->test = test;      sp->test = test;
     sp->settings = test->settings;      sp->settings = test->settings;
     sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result));      sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result));
Line 2689  iperf_new_stream(struct iperf_test *test, int s) Line 4335  iperf_new_stream(struct iperf_test *test, 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 2717  iperf_new_stream(struct iperf_test *test, int s) Line 4363  iperf_new_stream(struct iperf_test *test, int s)
         free(sp);          free(sp);
         return NULL;          return NULL;
     }      }
    srandom(time(NULL));    sp->pending_size = 0;
    for (i = 0; i < test->settings->blksize; ++i) 
        sp->buffer[i] = random(); 
   
     /* Set socket */      /* Set socket */
     sp->socket = s;      sp->socket = s;
Line 2728  iperf_new_stream(struct iperf_test *test, int s) Line 4372  iperf_new_stream(struct iperf_test *test, int s)
     sp->rcv = test->protocol->recv;      sp->rcv = test->protocol->recv;
   
     if (test->diskfile_name != (char*) 0) {      if (test->diskfile_name != (char*) 0) {
        sp->diskfile_fd = open(test->diskfile_name, test->sender ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), S_IRUSR|S_IWUSR);        sp->diskfile_fd = open(test->diskfile_name, sender ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), S_IRUSR|S_IWUSR);
         if (sp->diskfile_fd == -1) {          if (sp->diskfile_fd == -1) {
             i_errno = IEFILE;              i_errno = IEFILE;
             munmap(sp->buffer, sp->test->settings->blksize);              munmap(sp->buffer, sp->test->settings->blksize);
Line 2744  iperf_new_stream(struct iperf_test *test, int s) Line 4388  iperf_new_stream(struct iperf_test *test, int s)
         sp->diskfile_fd = -1;          sp->diskfile_fd = -1;
   
     /* Initialize stream */      /* Initialize stream */
    if (iperf_init_stream(sp, test) < 0) {    if (test->repeating_payload)
         fill_with_repeating_pattern(sp->buffer, test->settings->blksize);
     else
         ret = readentropy(sp->buffer, test->settings->blksize);
 
     if ((ret < 0) || (iperf_init_stream(sp, test) < 0)) {
         close(sp->buffer_fd);          close(sp->buffer_fd);
         munmap(sp->buffer, sp->test->settings->blksize);          munmap(sp->buffer, sp->test->settings->blksize);
         free(sp->result);          free(sp->result);
Line 2758  iperf_new_stream(struct iperf_test *test, int s) Line 4407  iperf_new_stream(struct iperf_test *test, 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 2809  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 2831  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;
   
    r = read(sp->diskfile_fd, sp->buffer, sp->test->settings->blksize);    /* if needed, read enough data from the disk to fill up the buffer */
    if (r == 0)    if (sp->diskfile_left < sp->test->settings->blksize && !sp->test->done) {
         r = read(sp->diskfile_fd, sp->buffer, sp->test->settings->blksize -
                  sp->diskfile_left);
         buffer_left += r;
         rtot += r;
         if (sp->test->debug) {
             printf("read %d bytes from file, %d total\n", r, rtot);
         }
 
         // If the buffer doesn't contain a full buffer at this point,
         // adjust the size of the data to send.
         if (buffer_left != sp->test->settings->blksize) {
             if (sp->test->debug)
                 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;          sp->test->done = 1;
    else        return 0;
        r = sp->snd2(sp);    }
 
     r = sp->snd2(sp);
     if (r < 0) {
         return r;
     }
     /*
      * Compute how much data is in the buffer but didn't get sent.
      * If there are bytes that got left behind, slide them to the
      * front of the buffer so they can hopefully go out on the next
      * pass.
      */
     sp->diskfile_left = buffer_left - r;
     if (sp->diskfile_left && sp->diskfile_left < sp->test->settings->blksize) {
         memcpy(sp->buffer,
                sp->buffer + (sp->test->settings->blksize - sp->diskfile_left),
                sp->diskfile_left);
         if (sp->test->debug)
             printf("Shifting %d bytes by %d\n", sp->diskfile_left, (sp->test->settings->blksize - sp->diskfile_left));
     }
     return r;      return r;
 }  }
   
Line 2847  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 2857  diskfile_recv(struct iperf_stream *sp) Line 4623  diskfile_recv(struct iperf_stream *sp)
 void  void
 iperf_catch_sigend(void (*handler)(int))  iperf_catch_sigend(void (*handler)(int))
 {  {
   #ifdef SIGINT
     signal(SIGINT, handler);      signal(SIGINT, handler);
   #endif
   #ifdef SIGTERM
     signal(SIGTERM, handler);      signal(SIGTERM, handler);
   #endif
   #ifdef SIGHUP
     signal(SIGHUP, handler);      signal(SIGHUP, handler);
   #endif
 }  }
   
 /**  /**
Line 2902  iperf_create_pidfile(struct iperf_test *test) Line 4674  iperf_create_pidfile(struct iperf_test *test)
     if (test->pidfile) {      if (test->pidfile) {
         int fd;          int fd;
         char buf[8];          char buf[8];
   
           /* See if the file already exists and we can read it. */
           fd = open(test->pidfile, O_RDONLY, 0);
           if (fd >= 0) {
               if (read(fd, buf, sizeof(buf) - 1) >= 0) {
   
                   /* We read some bytes, see if they correspond to a valid PID */
                   pid_t pid;
                   pid = atoi(buf);
                   if (pid > 0) {
   
                       /* See if the process exists. */
                       if (kill(pid, 0) == 0) {
                           /*
                            * Make sure not to try to delete existing PID file by
                            * scribbling over the pathname we'd use to refer to it.
                            * Then exit with an error.
                            */
                           free(test->pidfile);
                           test->pidfile = NULL;
                           iperf_errexit(test, "Another instance of iperf3 appears to be running");
                       }
                   }
               }
           }
   
           /*
            * File didn't exist, we couldn't read it, or it didn't correspond to
            * 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 2957  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) {
    /* Include server output */            cJSON_AddStringToObject(test->json_top, "title", test->title);
    if (test->json_server_output) {        }
        cJSON_AddItemToObject(test->json_top, "server_output_json", test->json_server_output);        if (test->extra_data) {
             cJSON_AddStringToObject(test->json_top, "extra_data", test->extra_data);
         }
         /* 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_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;
 }  }
   
   
/* CPU affinity stuff - Linux and FreeBSD only. *//* CPU affinity stuff - Linux, FreeBSD, and Windows only. */
   
 int  int
 iperf_setaffinity(struct iperf_test *test, int affinity)  iperf_setaffinity(struct iperf_test *test, int affinity)
Line 3010  iperf_setaffinity(struct iperf_test *test, int affinit Line 4829  iperf_setaffinity(struct iperf_test *test, int affinit
         return -1;          return -1;
     }      }
     return 0;      return 0;
#else /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY */#elif defined(HAVE_SETPROCESSAFFINITYMASK)
         HANDLE process = GetCurrentProcess();
         DWORD_PTR processAffinityMask = 1 << affinity;
 
         if (SetProcessAffinityMask(process, processAffinityMask) == 0) {
                 i_errno = IEAFFINITY;
                 return -1;
         }
         return 0;
 #else /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
     i_errno = IEAFFINITY;      i_errno = IEAFFINITY;
     return -1;      return -1;
#endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY */#endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
 }  }
   
 int  int
Line 3038  iperf_clearaffinity(struct iperf_test *test) Line 4866  iperf_clearaffinity(struct iperf_test *test)
         return -1;          return -1;
     }      }
     return 0;      return 0;
#else /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY */#elif defined(HAVE_SETPROCESSAFFINITYMASK)
         HANDLE process = GetCurrentProcess();
         DWORD_PTR processAffinityMask;
         DWORD_PTR lpSystemAffinityMask;
 
         if (GetProcessAffinityMask(process, &processAffinityMask, &lpSystemAffinityMask) == 0
                         || SetProcessAffinityMask(process, lpSystemAffinityMask) == 0) {
                 i_errno = IEAFFINITY;
                 return -1;
         }
         return 0;
 #else /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
     i_errno = IEAFFINITY;      i_errno = IEAFFINITY;
     return -1;      return -1;
#endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY */#endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
 }  }
   
   static char iperf_timestr[100];
   static char linebuffer[1024];
   
 int  int
iprintf(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;
     struct tm *ltm = NULL;
     char *ct = NULL;
   
       /* Timestamp if requested */
       if (iperf_get_test_timestamps(test)) {
           time(&now);
           ltm = localtime(&now);
           strftime(iperf_timestr, sizeof(iperf_timestr), iperf_get_test_timestamp_format(test), ltm);
           ct = iperf_timestr;
       }
   
     /*      /*
      * There are roughly two use cases here.  If we're the client,       * There are roughly two use cases here.  If we're the client,
      * want to print stuff directly to the output stream.       * want to print stuff directly to the output stream.
Line 3063  iprintf(struct iperf_test *test, const char* format, . Line 4916  iprintf(struct iperf_test *test, const char* format, .
      * to be buffered up anyway.       * to be buffered up anyway.
      */       */
     if (test->role == 'c') {      if (test->role == 'c') {
        if (test->title)        if (ct) {
            fprintf(test->outfile, "%s:  ", test->title);            r0 = fprintf(test->outfile, "%s", ct);
             if (r0 < 0)
                 return r0;
             r += r0;
         }
         if (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];        if (ct) {
        va_start(argp, format);            r0 = snprintf(linebuffer, sizeof(linebuffer), "%s", ct);
        r = vsnprintf(linebuffer, sizeof(linebuffer), format, argp);            if (r0 < 0)
        va_end(argp);                return r0;
             r += r0;
         }
         /* Should always be true as long as sizeof(ct) < sizeof(linebuffer) */
         if (r < sizeof(linebuffer)) {
             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.1  
changed lines
  Added in v.1.1.1.3


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