Diff for /embedaddon/iperf/src/iperf_client_api.c between versions 1.1 and 1.1.1.3

version 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, 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 32 Line 32
 #include <unistd.h>  #include <unistd.h>
 #include <signal.h>  #include <signal.h>
 #include <sys/types.h>  #include <sys/types.h>
   #include <netinet/in.h>
 #include <sys/select.h>  #include <sys/select.h>
 #include <sys/uio.h>  #include <sys/uio.h>
 #include <arpa/inet.h>  #include <arpa/inet.h>
Line 40 Line 41
 #include "iperf_api.h"  #include "iperf_api.h"
 #include "iperf_util.h"  #include "iperf_util.h"
 #include "iperf_locale.h"  #include "iperf_locale.h"
   #include "iperf_time.h"
 #include "net.h"  #include "net.h"
 #include "timer.h"  #include "timer.h"
   
   #if defined(HAVE_TCP_CONGESTION)
   #if !defined(TCP_CA_NAME_MAX)
   #define TCP_CA_NAME_MAX 16
   #endif /* TCP_CA_NAME_MAX */
   #endif /* HAVE_TCP_CONGESTION */
   
 int  int
iperf_create_streams(struct iperf_test *test)iperf_create_streams(struct iperf_test *test, int sender)
 {  {
       if (NULL == test)
       {
           iperf_err(NULL, "No test\n");
           return -1;
       }
     int i, s;      int i, s;
   #if defined(HAVE_TCP_CONGESTION)
       int saved_errno;
   #endif /* HAVE_TCP_CONGESTION */
     struct iperf_stream *sp;      struct iperf_stream *sp;
   
     int orig_bind_port = test->bind_port;      int orig_bind_port = test->bind_port;
     for (i = 0; i < test->num_streams; ++i) {      for (i = 0; i < test->num_streams; ++i) {
   
         test->bind_port = orig_bind_port;          test->bind_port = orig_bind_port;
        if (orig_bind_port)        if (orig_bind_port) {
             test->bind_port += i;              test->bind_port += i;
        if ((s = test->protocol->connect(test)) < 0)            // If Bidir make sure send and receive ports are different
             if (!sender && test->mode == BIDIRECTIONAL)
                 test->bind_port += test->num_streams;
         }
         s = test->protocol->connect(test);
         test->bind_port = orig_bind_port;
         if (s < 0)
             return -1;              return -1;
   
        if (test->sender)#if defined(HAVE_TCP_CONGESTION)
         if (test->protocol->id == Ptcp) {
             if (test->congestion) {
                 if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
                     saved_errno = errno;
                     close(s);
                     errno = saved_errno;
                     i_errno = IESETCONGESTION;
                     return -1;
                 }
             }
             {
                 socklen_t len = TCP_CA_NAME_MAX;
                 char ca[TCP_CA_NAME_MAX + 1];
                 int rc;
                 rc = getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len);
                 if (rc < 0 && test->congestion) {
                     saved_errno = errno;
                     close(s);
                     errno = saved_errno;
                     i_errno = IESETCONGESTION;
                     return -1;
                 }
                 // Set actual used congestion alg, or set to unknown if could not get it
                 if (rc < 0)
                     test->congestion_used = strdup("unknown");
                 else
                     test->congestion_used = strdup(ca);
                 if (test->debug) {
                     printf("Congestion algorithm is %s\n", test->congestion_used);
                 }
             }
         }
 #endif /* HAVE_TCP_CONGESTION */
 
         if (sender)
             FD_SET(s, &test->write_set);              FD_SET(s, &test->write_set);
         else          else
             FD_SET(s, &test->read_set);              FD_SET(s, &test->read_set);
         if (s > test->max_fd) test->max_fd = s;          if (s > test->max_fd) test->max_fd = s;
   
        sp = iperf_new_stream(test, s);        sp = iperf_new_stream(test, s, sender);
         if (!sp)          if (!sp)
             return -1;              return -1;
   
Line 78  iperf_create_streams(struct iperf_test *test) Line 134  iperf_create_streams(struct iperf_test *test)
 }  }
   
 static void  static void
test_timer_proc(TimerClientData client_data, struct timeval *nowP)test_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
 {  {
     struct iperf_test *test = client_data.p;      struct iperf_test *test = client_data.p;
   
Line 87  test_timer_proc(TimerClientData client_data, struct ti Line 143  test_timer_proc(TimerClientData client_data, struct ti
 }  }
   
 static void  static void
client_stats_timer_proc(TimerClientData client_data, struct timeval *nowP)client_stats_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
 {  {
     struct iperf_test *test = client_data.p;      struct iperf_test *test = client_data.p;
   
Line 98  client_stats_timer_proc(TimerClientData client_data, s Line 154  client_stats_timer_proc(TimerClientData client_data, s
 }  }
   
 static void  static void
client_reporter_timer_proc(TimerClientData client_data, struct timeval *nowP)client_reporter_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
 {  {
     struct iperf_test *test = client_data.p;      struct iperf_test *test = client_data.p;
   
Line 111  client_reporter_timer_proc(TimerClientData client_data Line 167  client_reporter_timer_proc(TimerClientData client_data
 static int  static int
 create_client_timers(struct iperf_test * test)  create_client_timers(struct iperf_test * test)
 {  {
    struct timeval now;    struct iperf_time now;
     TimerClientData cd;      TimerClientData cd;
       if (NULL == test)
       {
           iperf_err(NULL, "No test\n");
           i_errno = IEINITTEST;
           return -1;
       }
   
    if (gettimeofday(&now, NULL) < 0) {    if (iperf_time_now(&now) < 0) {
         i_errno = IEINITTEST;          i_errno = IEINITTEST;
         return -1;          return -1;
     }      }
Line 127  create_client_timers(struct iperf_test * test) Line 189  create_client_timers(struct iperf_test * test)
             i_errno = IEINITTEST;              i_errno = IEINITTEST;
             return -1;              return -1;
         }          }
    }     }
     if (test->stats_interval != 0) {      if (test->stats_interval != 0) {
         test->stats_timer = tmr_create(&now, client_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);          test->stats_timer = tmr_create(&now, client_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
         if (test->stats_timer == NULL) {          if (test->stats_timer == NULL) {
Line 146  create_client_timers(struct iperf_test * test) Line 208  create_client_timers(struct iperf_test * test)
 }  }
   
 static void  static void
client_omit_timer_proc(TimerClientData client_data, struct timeval *nowP)client_omit_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
 {  {
     struct iperf_test *test = client_data.p;      struct iperf_test *test = client_data.p;
   
Line 154  client_omit_timer_proc(TimerClientData client_data, st Line 216  client_omit_timer_proc(TimerClientData client_data, st
     test->omitting = 0;      test->omitting = 0;
     iperf_reset_stats(test);      iperf_reset_stats(test);
     if (test->verbose && !test->json_output && test->reporter_interval == 0)      if (test->verbose && !test->json_output && test->reporter_interval == 0)
        iprintf(test, "%s", report_omit_done);        iperf_printf(test, "%s", report_omit_done);
   
     /* Reset the timers. */      /* Reset the timers. */
     if (test->stats_timer != NULL)      if (test->stats_timer != NULL)
Line 166  client_omit_timer_proc(TimerClientData client_data, st Line 228  client_omit_timer_proc(TimerClientData client_data, st
 static int  static int
 create_client_omit_timer(struct iperf_test * test)  create_client_omit_timer(struct iperf_test * test)
 {  {
    struct timeval now;    struct iperf_time now;
     TimerClientData cd;      TimerClientData cd;
       if (NULL == test)
       {
           iperf_err(NULL, "No test\n");
           return -1;
       }
   
     if (test->omit == 0) {      if (test->omit == 0) {
         test->omit_timer = NULL;          test->omit_timer = NULL;
         test->omitting = 0;          test->omitting = 0;
     } else {      } else {
        if (gettimeofday(&now, NULL) < 0) {        if (iperf_time_now(&now) < 0) {
             i_errno = IEINITTEST;              i_errno = IEINITTEST;
             return -1;              return -1;
         }          }
Line 194  iperf_handle_message_client(struct iperf_test *test) Line 261  iperf_handle_message_client(struct iperf_test *test)
     int rval;      int rval;
     int32_t err;      int32_t err;
   
       if (NULL == test)
       {
           iperf_err(NULL, "No test\n");
           i_errno = IEINITTEST;
           return -1;
       }
     /*!!! Why is this read() and not Nread()? */      /*!!! Why is this read() and not Nread()? */
     if ((rval = read(test->ctrl_sck, (char*) &test->state, sizeof(signed char))) <= 0) {      if ((rval = read(test->ctrl_sck, (char*) &test->state, sizeof(signed char))) <= 0) {
         if (rval == 0) {          if (rval == 0) {
Line 213  iperf_handle_message_client(struct iperf_test *test) Line 286  iperf_handle_message_client(struct iperf_test *test)
                 test->on_connect(test);                  test->on_connect(test);
             break;              break;
         case CREATE_STREAMS:          case CREATE_STREAMS:
            if (iperf_create_streams(test) < 0)            if (test->mode == BIDIRECTIONAL)
             {
                 if (iperf_create_streams(test, 1) < 0)
                     return -1;
                 if (iperf_create_streams(test, 0) < 0)
                     return -1;
             }
             else if (iperf_create_streams(test, test->mode) < 0)
                 return -1;                  return -1;
             break;              break;
         case TEST_START:          case TEST_START:
Line 223  iperf_handle_message_client(struct iperf_test *test) Line 303  iperf_handle_message_client(struct iperf_test *test)
                 return -1;                  return -1;
             if (create_client_omit_timer(test) < 0)              if (create_client_omit_timer(test) < 0)
                 return -1;                  return -1;
            if (!test->reverse)            if (test->mode)
                 if (iperf_create_send_timers(test) < 0)                  if (iperf_create_send_timers(test) < 0)
                     return -1;                      return -1;
             break;              break;
Line 282  iperf_handle_message_client(struct iperf_test *test) Line 362  iperf_handle_message_client(struct iperf_test *test)
 int  int
 iperf_connect(struct iperf_test *test)  iperf_connect(struct iperf_test *test)
 {  {
       int opt;
       socklen_t len;
   
       if (NULL == test)
       {
           iperf_err(NULL, "No test\n");
           return -1;
       }
     FD_ZERO(&test->read_set);      FD_ZERO(&test->read_set);
     FD_ZERO(&test->write_set);      FD_ZERO(&test->write_set);
   
Line 290  iperf_connect(struct iperf_test *test) Line 378  iperf_connect(struct iperf_test *test)
     /* Create and connect the control channel */      /* Create and connect the control channel */
     if (test->ctrl_sck < 0)      if (test->ctrl_sck < 0)
         // Create the control channel using an ephemeral port          // Create the control channel using an ephemeral port
        test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, 0, test->server_hostname, test->server_port);        test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, 0, test->server_hostname, test->server_port, test->settings->connect_timeout);
     if (test->ctrl_sck < 0) {      if (test->ctrl_sck < 0) {
         i_errno = IECONNECT;          i_errno = IECONNECT;
         return -1;          return -1;
     }      }
   
       // set TCP_NODELAY for lower latency on control messages
       int flag = 1;
       if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int))) {
           i_errno = IESETNODELAY;
           return -1;
       }
   
   #if defined(HAVE_TCP_USER_TIMEOUT)
       if ((opt = test->settings->snd_timeout)) {
           if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
           i_errno = IESETUSERTIMEOUT;
           return -1;
           }
       }
   #endif /* HAVE_TCP_USER_TIMEOUT */
   
     if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {      if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
         i_errno = IESENDCOOKIE;          i_errno = IESENDCOOKIE;
         return -1;          return -1;
Line 304  iperf_connect(struct iperf_test *test) Line 408  iperf_connect(struct iperf_test *test)
     FD_SET(test->ctrl_sck, &test->read_set);      FD_SET(test->ctrl_sck, &test->read_set);
     if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;      if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;
   
       len = sizeof(opt);
       if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) {
           test->ctrl_sck_mss = 0;
       }
       else {
           if (opt > 0 && opt <= MAX_UDP_BLOCKSIZE) {
               test->ctrl_sck_mss = opt;
           }
           else {
               char str[WARN_STR_LEN];
               snprintf(str, sizeof(str),
                        "Ignoring nonsense TCP MSS %d", opt);
               warning(str);
   
               test->ctrl_sck_mss = 0;
           }
       }
   
       if (test->verbose) {
           printf("Control connection MSS %d\n", test->ctrl_sck_mss);
       }
   
       /*
        * If we're doing a UDP test and the block size wasn't explicitly
        * set, then use the known MSS of the control connection to pick
        * an appropriate default.  If we weren't able to get the
        * MSS for some reason, then default to something that should
        * work on non-jumbo-frame Ethernet networks.  The goal is to
        * pick a reasonable default that is large but should get from
        * sender to receiver without any IP fragmentation.
        *
        * We assume that the control connection is routed the same as the
        * data packets (thus has the same PMTU).  Also in the case of
        * --reverse tests, we assume that the MTU is the same in both
        * directions.  Note that even if the algorithm guesses wrong,
        * the user always has the option to override.
        */
       if (test->protocol->id == Pudp) {
           if (test->settings->blksize == 0) {
               if (test->ctrl_sck_mss) {
                   test->settings->blksize = test->ctrl_sck_mss;
               }
               else {
                   test->settings->blksize = DEFAULT_UDP_BLKSIZE;
               }
               if (test->verbose) {
                   printf("Setting UDP block size to %d\n", test->settings->blksize);
               }
           }
   
           /*
            * Regardless of whether explicitly or implicitly set, if the
            * block size is larger than the MSS, print a warning.
            */
           if (test->ctrl_sck_mss > 0 &&
               test->settings->blksize > test->ctrl_sck_mss) {
               char str[WARN_STR_LEN];
               snprintf(str, sizeof(str),
                        "UDP block size %d exceeds TCP MSS %d, may result in fragmentation / drops", test->settings->blksize, test->ctrl_sck_mss);
               warning(str);
           }
       }
   
     return 0;      return 0;
 }  }
   
Line 311  iperf_connect(struct iperf_test *test) Line 478  iperf_connect(struct iperf_test *test)
 int  int
 iperf_client_end(struct iperf_test *test)  iperf_client_end(struct iperf_test *test)
 {  {
       if (NULL == test)
       {
           iperf_err(NULL, "No test\n");
           return -1;
       }
     struct iperf_stream *sp;      struct iperf_stream *sp;
   
     /* Close all stream sockets */      /* Close all stream sockets */
Line 321  iperf_client_end(struct iperf_test *test) Line 493  iperf_client_end(struct iperf_test *test)
     /* show final summary */      /* show final summary */
     test->reporter_callback(test);      test->reporter_callback(test);
   
    if (iperf_set_send_state(test, IPERF_DONE) != 0)    /* Send response only if no error in server */
        return -1;    if (test->state > 0) {
         if (iperf_set_send_state(test, IPERF_DONE) != 0)
             return -1;
     }
   
       /* Close control socket */
       if (test->ctrl_sck >= 0)
           close(test->ctrl_sck);
   
     return 0;      return 0;
 }  }
   
Line 334  iperf_run_client(struct iperf_test * test) Line 513  iperf_run_client(struct iperf_test * test)
     int startup;      int startup;
     int result = 0;      int result = 0;
     fd_set read_set, write_set;      fd_set read_set, write_set;
    struct timeval now;    struct iperf_time now;
     struct timeval* timeout = NULL;      struct timeval* timeout = NULL;
     struct iperf_stream *sp;      struct iperf_stream *sp;
       struct iperf_time last_receive_time;
       struct iperf_time diff_time;
       struct timeval used_timeout;
       int64_t t_usecs;
       int64_t timeout_us;
       int64_t rcv_timeout_us;
   
       if (NULL == test)
       {
           iperf_err(NULL, "No test\n");
           return -1;
       }
   
       if (test->logfile)
           if (iperf_open_logfile(test) < 0)
               return -1;
   
     if (test->affinity != -1)      if (test->affinity != -1)
         if (iperf_setaffinity(test, test->affinity) != 0)          if (iperf_setaffinity(test, test->affinity) != 0)
             return -1;              return -1;
Line 350  iperf_run_client(struct iperf_test * test) Line 545  iperf_run_client(struct iperf_test * test)
         cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));          cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
         cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));          cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
     } else if (test->verbose) {      } else if (test->verbose) {
        iprintf(test, "%s\n", version);        iperf_printf(test, "%s\n", version);
        iprintf(test, "%s", "");        iperf_printf(test, "%s", "");
        iprintf(test, "%s\n", get_system_info());        iperf_printf(test, "%s\n", get_system_info());
         iflush(test);          iflush(test);
     }      }
   
     /* Start the client and connect to the server */      /* Start the client and connect to the server */
     if (iperf_connect(test) < 0)      if (iperf_connect(test) < 0)
        return -1;        goto cleanup_and_fail;
   
     /* Begin calculating CPU utilization */      /* Begin calculating CPU utilization */
     cpu_util(NULL);      cpu_util(NULL);
       if (test->mode != SENDER)
           rcv_timeout_us = (test->settings->rcv_timeout.secs * SEC_TO_US) + test->settings->rcv_timeout.usecs;
       else
           rcv_timeout_us = 0;
   
     startup = 1;      startup = 1;
     while (test->state != IPERF_DONE) {      while (test->state != IPERF_DONE) {
         memcpy(&read_set, &test->read_set, sizeof(fd_set));          memcpy(&read_set, &test->read_set, sizeof(fd_set));
         memcpy(&write_set, &test->write_set, sizeof(fd_set));          memcpy(&write_set, &test->write_set, sizeof(fd_set));
        (void) gettimeofday(&now, NULL);        iperf_time_now(&now);
         timeout = tmr_timeout(&now);          timeout = tmr_timeout(&now);
   
           // In reverse active mode client ensures data is received
           if (test->state == TEST_RUNNING && rcv_timeout_us > 0) {
               timeout_us = -1;
               if (timeout != NULL) {
                   used_timeout.tv_sec = timeout->tv_sec;
                   used_timeout.tv_usec = timeout->tv_usec;
                   timeout_us = (timeout->tv_sec * SEC_TO_US) + timeout->tv_usec;
               }
               if (timeout_us < 0 || timeout_us > rcv_timeout_us) {
                   used_timeout.tv_sec = test->settings->rcv_timeout.secs;
                   used_timeout.tv_usec = test->settings->rcv_timeout.usecs;
               }
               timeout = &used_timeout;
           }
   
         result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);          result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
         if (result < 0 && errno != EINTR) {          if (result < 0 && errno != EINTR) {
             i_errno = IESELECT;              i_errno = IESELECT;
            return -1;            goto cleanup_and_fail;
        }        } else if (result == 0 && test->state == TEST_RUNNING && rcv_timeout_us > 0) {
             // If nothing was received in non-reverse running state then probably something got stack -
             // either client, server or network, and test should be terminated.
             iperf_time_now(&now);
             if (iperf_time_diff(&now, &last_receive_time, &diff_time) == 0) {
                 t_usecs = iperf_time_in_usecs(&diff_time);
                 if (t_usecs > rcv_timeout_us) {
                     i_errno = IENOMSG;
                     goto cleanup_and_fail;
                 }
 
             }
         }
 
         if (result > 0) {          if (result > 0) {
               if (rcv_timeout_us > 0) {
                   iperf_time_now(&last_receive_time);
               }
             if (FD_ISSET(test->ctrl_sck, &read_set)) {              if (FD_ISSET(test->ctrl_sck, &read_set)) {
                 if (iperf_handle_message_client(test) < 0) {                  if (iperf_handle_message_client(test) < 0) {
                    return -1;                    goto cleanup_and_fail;
                 }                  }
                 FD_CLR(test->ctrl_sck, &read_set);                  FD_CLR(test->ctrl_sck, &read_set);
             }              }
Line 397  iperf_run_client(struct iperf_test * test) Line 628  iperf_run_client(struct iperf_test * test)
                 }                  }
             }              }
   
            if (test->reverse) {
                // Reverse mode. Client receives.            if (test->mode == BIDIRECTIONAL)
                if (iperf_recv(test, &read_set) < 0)            {
                    return -1;                if (iperf_send(test, &write_set) < 0)
                     goto cleanup_and_fail;
                 if (iperf_recv(test, &read_set) < 0)
                     goto cleanup_and_fail;
             } else if (test->mode == SENDER) {
                 // Regular mode. Client sends.
                 if (iperf_send(test, &write_set) < 0)
                     goto cleanup_and_fail;
             } else {              } else {
                // Regular mode. Client sends.                // Reverse mode. Client receives.
                if (iperf_send(test, &write_set) < 0)                if (iperf_recv(test, &read_set) < 0)
                    return -1;                    goto cleanup_and_fail;
             }              }
   
   
             /* Run the timers. */              /* Run the timers. */
            (void) gettimeofday(&now, NULL);            iperf_time_now(&now);
             tmr_run(&now);              tmr_run(&now);
   
            /* Is the test done yet? */            /*
              * Is the test done yet?  We have to be out of omitting
              * mode, and then we have to have fulfilled one of the
              * ending criteria, either by times, bytes, or blocks.
              * The bytes and blocks tests needs to handle both the
              * cases of the client being the sender and the client
              * being the receiver.
              */
             if ((!test->omitting) &&              if ((!test->omitting) &&
                ((test->duration != 0 && test->done) ||                (test->done ||
                 (test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes) ||                 (test->settings->bytes != 0 && (test->bytes_sent >= test->settings->bytes ||
                 (test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks))) {                                                 test->bytes_received >= test->settings->bytes)) ||
                  (test->settings->blocks != 0 && (test->blocks_sent >= test->settings->blocks ||
                                                   test->blocks_received >= test->settings->blocks)))) {
   
                 // Unset non-blocking for non-UDP tests                  // Unset non-blocking for non-UDP tests
                 if (test->protocol->id != Pudp) {                  if (test->protocol->id != Pudp) {
Line 429  iperf_run_client(struct iperf_test * test) Line 677  iperf_run_client(struct iperf_test * test)
                 cpu_util(test->cpu_util);                  cpu_util(test->cpu_util);
                 test->stats_callback(test);                  test->stats_callback(test);
                 if (iperf_set_send_state(test, TEST_END) != 0)                  if (iperf_set_send_state(test, TEST_END) != 0)
                    return -1;                    goto cleanup_and_fail;
             }              }
         }          }
         // If we're in reverse mode, continue draining the data          // If we're in reverse mode, continue draining the data
Line 437  iperf_run_client(struct iperf_test * test) Line 685  iperf_run_client(struct iperf_test * test)
         // deadlock where the server side fills up its pipe(s)          // deadlock where the server side fills up its pipe(s)
         // and gets blocked, so it can't receive state changes          // and gets blocked, so it can't receive state changes
         // from the client side.          // from the client side.
        else if (test->reverse && test->state == TEST_END) {        else if (test->mode == RECEIVER && test->state == TEST_END) {
             if (iperf_recv(test, &read_set) < 0)              if (iperf_recv(test, &read_set) < 0)
                return -1;                goto cleanup_and_fail;
         }          }
     }      }
   
Line 447  iperf_run_client(struct iperf_test * test) Line 695  iperf_run_client(struct iperf_test * test)
         if (iperf_json_finish(test) < 0)          if (iperf_json_finish(test) < 0)
             return -1;              return -1;
     } else {      } else {
        iprintf(test, "\n");        iperf_printf(test, "\n");
        iprintf(test, "%s", report_done);        iperf_printf(test, "%s", report_done);
     }      }
   
     iflush(test);      iflush(test);
   
     return 0;      return 0;
   
     cleanup_and_fail:
       iperf_client_end(test);
       if (test->json_output) {
           cJSON_AddStringToObject(test->json_top, "error", iperf_strerror(i_errno));
           iperf_json_finish(test);
       }
       iflush(test);
       return -1;
 }  }

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


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