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

version 1.1.1.2, 2021/03/17 00:36:46 version 1.1.1.3, 2023/09/27 11:14:54
Line 1 Line 1
 /*  /*
 * iperf, Copyright (c) 2014-2020, The Regents of the University of * iperf, Copyright (c) 2014-2022, The Regents of the University of
  * California, through Lawrence Berkeley National Laboratory (subject   * California, through Lawrence Berkeley National Laboratory (subject
  * to receipt of any required approvals from the U.S. Dept. of   * to receipt of any required approvals from the U.S. Dept. of
  * Energy).  All rights reserved.   * Energy).  All rights reserved.
Line 54 Line 54
 int  int
 iperf_create_streams(struct iperf_test *test, int sender)  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)  #if defined(HAVE_TCP_CONGESTION)
     int saved_errno;      int saved_errno;
Line 64  iperf_create_streams(struct iperf_test *test, int send Line 69  iperf_create_streams(struct iperf_test *test, int send
     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 defined(HAVE_TCP_CONGESTION)  #if defined(HAVE_TCP_CONGESTION)
Line 78  iperf_create_streams(struct iperf_test *test, int send Line 89  iperf_create_streams(struct iperf_test *test, int send
                     errno = saved_errno;                      errno = saved_errno;
                     i_errno = IESETCONGESTION;                      i_errno = IESETCONGESTION;
                     return -1;                      return -1;
                }                 }
             }              }
             {              {
                 socklen_t len = TCP_CA_NAME_MAX;                  socklen_t len = TCP_CA_NAME_MAX;
                 char ca[TCP_CA_NAME_MAX + 1];                  char ca[TCP_CA_NAME_MAX + 1];
                if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) {                int rc;
                 rc = getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len);
                 if (rc < 0 && test->congestion) {
                     saved_errno = errno;                      saved_errno = errno;
                     close(s);                      close(s);
                     errno = saved_errno;                      errno = saved_errno;
                     i_errno = IESETCONGESTION;                      i_errno = IESETCONGESTION;
                     return -1;                      return -1;
                 }                  }
                test->congestion_used = strdup(ca);                // 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) {                  if (test->debug) {
                     printf("Congestion algorithm is %s\n", test->congestion_used);                      printf("Congestion algorithm is %s\n", test->congestion_used);
                 }                  }
Line 152  create_client_timers(struct iperf_test * test) Line 169  create_client_timers(struct iperf_test * test)
 {  {
     struct iperf_time now;      struct iperf_time now;
     TimerClientData cd;      TimerClientData cd;
       if (NULL == test)
       {
           iperf_err(NULL, "No test\n");
           i_errno = IEINITTEST;
           return -1;
       }
   
     if (iperf_time_now(&now) < 0) {      if (iperf_time_now(&now) < 0) {
         i_errno = IEINITTEST;          i_errno = IEINITTEST;
Line 166  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 207  create_client_omit_timer(struct iperf_test * test) Line 230  create_client_omit_timer(struct iperf_test * test)
 {  {
     struct iperf_time 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;
Line 233  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 328  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 336  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->settings->connect_timeout);        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 350  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;
   
     int opt;  
     socklen_t len;  
   
     len = sizeof(opt);      len = sizeof(opt);
     if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) {      if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) {
         test->ctrl_sck_mss = 0;          test->ctrl_sck_mss = 0;
Line 362  iperf_connect(struct iperf_test *test) Line 417  iperf_connect(struct iperf_test *test)
             test->ctrl_sck_mss = opt;              test->ctrl_sck_mss = opt;
         }          }
         else {          else {
            char str[128];            char str[WARN_STR_LEN];
             snprintf(str, sizeof(str),              snprintf(str, sizeof(str),
                      "Ignoring nonsense TCP MSS %d", opt);                       "Ignoring nonsense TCP MSS %d", opt);
             warning(str);              warning(str);
Line 409  iperf_connect(struct iperf_test *test) Line 464  iperf_connect(struct iperf_test *test)
          */           */
         if (test->ctrl_sck_mss > 0 &&          if (test->ctrl_sck_mss > 0 &&
             test->settings->blksize > test->ctrl_sck_mss) {              test->settings->blksize > test->ctrl_sck_mss) {
            char str[128];            char str[WARN_STR_LEN];
             snprintf(str, sizeof(str),              snprintf(str, sizeof(str),
                      "UDP block size %d exceeds TCP MSS %d, may result in fragmentation / drops", test->settings->blksize, test->ctrl_sck_mss);                       "UDP block size %d exceeds TCP MSS %d, may result in fragmentation / drops", test->settings->blksize, test->ctrl_sck_mss);
             warning(str);              warning(str);
Line 423  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 433  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 */      /* Close control socket */
    if (test->ctrl_sck)    if (test->ctrl_sck >= 0)
         close(test->ctrl_sck);          close(test->ctrl_sck);
   
     return 0;      return 0;
Line 453  iperf_run_client(struct iperf_test * test) Line 516  iperf_run_client(struct iperf_test * test)
     struct iperf_time 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 (test->logfile)
         if (iperf_open_logfile(test) < 0)          if (iperf_open_logfile(test) < 0)
             return -1;              return -1;
Line 482  iperf_run_client(struct iperf_test * test) Line 557  iperf_run_client(struct iperf_test * test)
   
     /* 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) {
Line 489  iperf_run_client(struct iperf_test * test) Line 568  iperf_run_client(struct iperf_test * test)
         memcpy(&write_set, &test->write_set, sizeof(fd_set));          memcpy(&write_set, &test->write_set, sizeof(fd_set));
         iperf_time_now(&now);          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;
             goto cleanup_and_fail;              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) {
                     goto cleanup_and_fail;                      goto cleanup_and_fail;
Line 539  iperf_run_client(struct iperf_test * test) Line 650  iperf_run_client(struct iperf_test * test)
             iperf_time_now(&now);              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 585  iperf_run_client(struct iperf_test * test) Line 705  iperf_run_client(struct iperf_test * test)
   
   cleanup_and_fail:    cleanup_and_fail:
     iperf_client_end(test);      iperf_client_end(test);
    if (test->json_output)    if (test->json_output) {
        iperf_json_finish(test);        cJSON_AddStringToObject(test->json_top, "error", iperf_strerror(i_errno));
         iperf_json_finish(test);
     }
     iflush(test);      iflush(test);
     return -1;      return -1;
 }  }

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


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