Diff for /embedaddon/iperf/src/iperf_server_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, 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 40 Line 40
 #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 <sched.h>  #include <sched.h>
Line 56 Line 54
 #include "iperf_tcp.h"  #include "iperf_tcp.h"
 #include "iperf_util.h"  #include "iperf_util.h"
 #include "timer.h"  #include "timer.h"
   #include "iperf_time.h"
 #include "net.h"  #include "net.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"
   
   #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_server_listen(struct iperf_test *test)  iperf_server_listen(struct iperf_test *test)
 {  {
     retry:      retry:
    if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {    if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) {
         if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) {          if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) {
             /* If we get "Address family not supported by protocol", that              /* If we get "Address family not supported by protocol", that
             ** probably means we were compiled with IPv6 but the running              ** probably means we were compiled with IPv6 but the running
Line 84  iperf_server_listen(struct iperf_test *test) Line 87  iperf_server_listen(struct iperf_test *test)
     }      }
   
     if (!test->json_output) {      if (!test->json_output) {
        iprintf(test, "-----------------------------------------------------------\n");        if (test->server_last_run_rc != 2)
        iprintf(test, "Server listening on %d\n", test->server_port);            test->server_test_number +=1;
    }        if (test->debug || test->server_last_run_rc != 2) {
            iperf_printf(test, "-----------------------------------------------------------\n");
    // This needs to be changed to reflect if client has different window size            iperf_printf(test, "Server listening on %d (test #%d)\n", test->server_port, test->server_test_number);
    // make sure we got what we asked for            iperf_printf(test, "-----------------------------------------------------------\n");
    /* XXX: This needs to be moved to the stream listener            if (test->forceflush)
    if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) {                iflush(test);
        // Needs to set some sort of error number/message 
        perror("SO_RCVBUF"); 
        return -1; 
    } 
    */ 
 
    // XXX: This code needs to be moved to after parameter exhange 
    /* 
    char ubuf[UNIT_LEN]; 
    int x; 
 
    if (test->protocol->id == Ptcp) { 
        if (test->settings->socket_bufsize > 0) { 
            unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A'); 
            if (!test->json_output)  
                iprintf(test, report_window, ubuf); 
        } else { 
            if (!test->json_output)  
                iprintf(test, "%s", report_autotune); 
         }          }
     }      }
     */  
     if (!test->json_output)  
         iprintf(test, "-----------------------------------------------------------\n");  
   
     FD_ZERO(&test->read_set);      FD_ZERO(&test->read_set);
     FD_ZERO(&test->write_set);      FD_ZERO(&test->write_set);
Line 142  iperf_accept(struct iperf_test *test) Line 123  iperf_accept(struct iperf_test *test)
     if (test->ctrl_sck == -1) {      if (test->ctrl_sck == -1) {
         /* Server free, accept new client */          /* Server free, accept new client */
         test->ctrl_sck = s;          test->ctrl_sck = s;
        if (Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {        // 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)
         int opt;
         if ((opt = test->settings->snd_timeout)) {
             if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
                 i_errno = IESETUSERTIMEOUT;
                 return -1;
             }
         }
 #endif /* HAVE_TCP_USER_TIMEOUT */
 
         if (Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) != COOKIE_SIZE) {
             /*
              * Note this error covers both the case of a system error
              * or the inability to read the correct amount of data
              * (i.e. timed out).
              */
             i_errno = IERECVCOOKIE;              i_errno = IERECVCOOKIE;
             return -1;              return -1;
         }          }
Line 153  iperf_accept(struct iperf_test *test) Line 156  iperf_accept(struct iperf_test *test)
             return -1;              return -1;
         if (iperf_exchange_parameters(test) < 0)          if (iperf_exchange_parameters(test) < 0)
             return -1;              return -1;
        if (test->server_affinity != -1)         if (test->server_affinity != -1)
             if (iperf_setaffinity(test, test->server_affinity) != 0)              if (iperf_setaffinity(test, test->server_affinity) != 0)
                 return -1;                  return -1;
         if (test->on_connect)          if (test->on_connect)
             test->on_connect(test);              test->on_connect(test);
     } else {      } else {
         /*          /*
         * Don't try to read from the socket.  It could block an ongoing test.          * Don't try to read from the socket.  It could block an ongoing test.
          * Just send ACCESS_DENIED.           * Just send ACCESS_DENIED.
            * Also, if sending failed, don't return an error, as the request is not related
            * to the ongoing test, and returning an error will terminate the test.
          */           */
         if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {          if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
            i_errno = IESENDMESSAGE;            if (test->debug)
            return -1;                printf("failed to send ACCESS_DENIED to an unsolicited connection request during active test\n");
         } else {
             if (test->debug)
                 printf("successfully sent ACCESS_DENIED to an unsolicited connection request during active test\n");
         }          }
         close(s);          close(s);
     }      }
Line 246  iperf_handle_message_server(struct iperf_test *test) Line 254  iperf_handle_message_server(struct iperf_test *test)
     return 0;      return 0;
 }  }
   
/* XXX: This function is not used anymore */static void
voidserver_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
iperf_test_reset(struct iperf_test *test) 
 {  {
       struct iperf_test *test = client_data.p;
     struct iperf_stream *sp;      struct iperf_stream *sp;
   
    close(test->ctrl_sck);    test->timer = NULL;
    if (test->done)
         return;
     test->done = 1;
     /* Free streams */      /* Free streams */
     while (!SLIST_EMPTY(&test->streams)) {      while (!SLIST_EMPTY(&test->streams)) {
         sp = SLIST_FIRST(&test->streams);          sp = SLIST_FIRST(&test->streams);
         SLIST_REMOVE_HEAD(&test->streams, streams);          SLIST_REMOVE_HEAD(&test->streams, streams);
           close(sp->socket);
         iperf_free_stream(sp);          iperf_free_stream(sp);
     }      }
    if (test->timer != NULL) {    close(test->ctrl_sck);
        tmr_cancel(test->timer); 
        test->timer = NULL; 
    } 
    if (test->stats_timer != NULL) { 
        tmr_cancel(test->stats_timer); 
        test->stats_timer = NULL; 
    } 
    if (test->reporter_timer != NULL) { 
        tmr_cancel(test->reporter_timer); 
        test->reporter_timer = NULL; 
    } 
    test->done = 0; 
 
    SLIST_INIT(&test->streams); 
 
    test->role = 's'; 
    set_protocol(test, Ptcp); 
    test->omit = OMIT; 
    test->duration = DURATION; 
    test->diskfile_name = (char*) 0; 
    test->affinity = -1; 
    test->server_affinity = -1; 
    test->title = NULL; 
    test->congestion = NULL; 
    test->state = 0; 
    test->server_hostname = NULL; 
 
     test->ctrl_sck = -1;      test->ctrl_sck = -1;
     test->prot_listener = -1;  
   
     test->bytes_sent = 0;  
   
     test->reverse = 0;  
     test->sender = 0;  
     test->sender_has_retransmits = 0;  
     test->no_delay = 0;  
   
     FD_ZERO(&test->read_set);  
     FD_ZERO(&test->write_set);  
     FD_SET(test->listener, &test->read_set);  
     test->max_fd = test->listener;  
       
     test->num_streams = 1;  
     test->settings->socket_bufsize = 0;  
     test->settings->blksize = DEFAULT_TCP_BLKSIZE;  
     test->settings->rate = 0;  
     test->settings->mss = 0;  
     memset(test->cookie, 0, COOKIE_SIZE);   
 }  }
   
 static void  static void
server_stats_timer_proc(TimerClientData client_data, struct timeval *nowP)server_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 323  server_stats_timer_proc(TimerClientData client_data, s Line 287  server_stats_timer_proc(TimerClientData client_data, s
 }  }
   
 static void  static void
server_reporter_timer_proc(TimerClientData client_data, struct timeval *nowP)server_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 336  server_reporter_timer_proc(TimerClientData client_data Line 300  server_reporter_timer_proc(TimerClientData client_data
 static int  static int
 create_server_timers(struct iperf_test * test)  create_server_timers(struct iperf_test * test)
 {  {
    struct timeval now;    struct iperf_time now;
     TimerClientData cd;      TimerClientData cd;
       int max_rtt = 4; /* seconds */
       int state_transitions = 10; /* number of state transitions in iperf3 */
       int grace_period = max_rtt * state_transitions;
   
    if (gettimeofday(&now, NULL) < 0) {    if (iperf_time_now(&now) < 0) {
         i_errno = IEINITTEST;          i_errno = IEINITTEST;
         return -1;          return -1;
     }      }
     cd.p = test;      cd.p = test;
       test->timer = test->stats_timer = test->reporter_timer = NULL;
       if (test->duration != 0 ) {
           test->done = 0;
           test->timer = tmr_create(&now, server_timer_proc, cd, (test->duration + test->omit + grace_period) * SEC_TO_US, 0);
           if (test->timer == NULL) {
               i_errno = IEINITTEST;
               return -1;
           }
       }
   
     test->stats_timer = test->reporter_timer = NULL;      test->stats_timer = test->reporter_timer = NULL;
     if (test->stats_interval != 0) {      if (test->stats_interval != 0) {
         test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);          test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
Line 363  create_server_timers(struct iperf_test * test) Line 340  create_server_timers(struct iperf_test * test)
 }  }
   
 static void  static void
server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP)server_omit_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
{   {
     struct iperf_test *test = client_data.p;      struct iperf_test *test = client_data.p;
   
     test->omit_timer = NULL;      test->omit_timer = NULL;
     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 383  server_omit_timer_proc(TimerClientData client_data, st Line 360  server_omit_timer_proc(TimerClientData client_data, st
 static int  static int
 create_server_omit_timer(struct iperf_test * test)  create_server_omit_timer(struct iperf_test * test)
 {  {
    struct timeval now;    struct iperf_time now;
    TimerClientData cd;     TimerClientData cd;
   
     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;
         }          }
         test->omitting = 1;          test->omitting = 1;
         cd.p = test;          cd.p = test;
        test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);         test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
         if (test->omit_timer == NULL) {          if (test->omit_timer == NULL) {
             i_errno = IEINITTEST;              i_errno = IEINITTEST;
             return -1;              return -1;
Line 409  create_server_omit_timer(struct iperf_test * test) Line 386  create_server_omit_timer(struct iperf_test * test)
 static void  static void
 cleanup_server(struct iperf_test *test)  cleanup_server(struct iperf_test *test)
 {  {
       struct iperf_stream *sp;
   
       /* Close open streams */
       SLIST_FOREACH(sp, &test->streams, streams) {
           if (sp->socket > -1) {
               FD_CLR(sp->socket, &test->read_set);
               FD_CLR(sp->socket, &test->write_set);
               close(sp->socket);
               sp->socket = -1;
           }
       }
   
     /* Close open test sockets */      /* Close open test sockets */
    close(test->ctrl_sck);    if (test->ctrl_sck > -1) {
    close(test->listener);        close(test->ctrl_sck);
         test->ctrl_sck = -1;
     }
     if (test->listener > -1) {
         close(test->listener);
         test->listener = -1;
     }
     if (test->prot_listener > -1) {     // May remain open if create socket failed
         close(test->prot_listener);
         test->prot_listener = -1;
     }
   
     /* Cancel any remaining timers. */      /* Cancel any remaining timers. */
     if (test->stats_timer != NULL) {      if (test->stats_timer != NULL) {
Line 426  cleanup_server(struct iperf_test *test) Line 425  cleanup_server(struct iperf_test *test)
         tmr_cancel(test->omit_timer);          tmr_cancel(test->omit_timer);
         test->omit_timer = NULL;          test->omit_timer = NULL;
     }      }
       if (test->congestion_used != NULL) {
           free(test->congestion_used);
           test->congestion_used = NULL;
       }
       if (test->timer != NULL) {
           tmr_cancel(test->timer);
           test->timer = NULL;
       }
 }  }
   
   
 int  int
 iperf_run_server(struct iperf_test *test)  iperf_run_server(struct iperf_test *test)
 {  {
    int result, s, streams_accepted;    int result, s;
     int send_streams_accepted, rec_streams_accepted;
     int streams_to_send = 0, streams_to_rec = 0;
 #if defined(HAVE_TCP_CONGESTION)
     int saved_errno;
 #endif /* HAVE_TCP_CONGESTION */
     fd_set read_set, write_set;      fd_set read_set, write_set;
     struct iperf_stream *sp;      struct iperf_stream *sp;
    struct timeval now;    struct iperf_time now;
     struct iperf_time last_receive_time;
     struct iperf_time diff_time;
     struct timeval* timeout;      struct timeval* timeout;
       struct timeval used_timeout;
       int flag;
       int64_t t_usecs;
       int64_t timeout_us;
       int64_t rcv_timeout_us;
   
    if (test->affinity != -1)     if (test->logfile)
        if (iperf_setaffinity(test, test->affinity) != 0)        if (iperf_open_logfile(test) < 0)
             return -2;
 
     if (test->affinity != -1)
         if (iperf_setaffinity(test, test->affinity) != 0) {
             cleanup_server(test);
             return -2;              return -2;
           }
   
     if (test->json_output)      if (test->json_output)
        if (iperf_json_start(test) < 0)        if (iperf_json_start(test) < 0) {
             cleanup_server(test);
             return -2;              return -2;
           }
   
     if (test->json_output) {      if (test->json_output) {
         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);
     }      }
   
     // Open socket and listen      // Open socket and listen
     if (iperf_server_listen(test) < 0) {      if (iperf_server_listen(test) < 0) {
           cleanup_server(test);
         return -2;          return -2;
     }      }
   
    // Begin calculating CPU utilization    iperf_time_now(&last_receive_time); // Initialize last time something was received
    cpu_util(NULL); 
   
     test->state = IPERF_START;      test->state = IPERF_START;
    streams_accepted = 0;    send_streams_accepted = 0;
     rec_streams_accepted = 0;
     rcv_timeout_us = (test->settings->rcv_timeout.secs * SEC_TO_US) + test->settings->rcv_timeout.usecs;
   
     while (test->state != IPERF_DONE) {      while (test->state != IPERF_DONE) {
   
           // Check if average transfer rate was exceeded (condition set in the callback routines)
           if (test->bitrate_limit_exceeded) {
               cleanup_server(test);
               i_errno = IETOTALRATE;
               return -1;
           }
   
         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);
   
           // Ensure select() will timeout to allow handling error cases that require server restart
           if (test->state == IPERF_START) {       // In idle mode server may need to restart
               if (timeout == NULL && test->settings->idle_timeout > 0) {
                   used_timeout.tv_sec = test->settings->idle_timeout;
                   used_timeout.tv_usec = 0;
                   timeout = &used_timeout;
               }
           } else if (test->mode != SENDER) {     // In non-reverse active mode server ensures data is received
               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) {
            cleanup_server(test);            cleanup_server(test);
             i_errno = IESELECT;              i_errno = IESELECT;
             return -1;              return -1;
           } else if (result == 0) {
               // If nothing was received during the specified time (per state)
               // then probably something got stack either at the client, server or network,
               // and Test should be forced to end.
               iperf_time_now(&now);
               t_usecs = 0;
               if (iperf_time_diff(&now, &last_receive_time, &diff_time) == 0) {
                   t_usecs = iperf_time_in_usecs(&diff_time);
                   if (test->state == IPERF_START) {
                       if (test->settings->idle_timeout > 0 && t_usecs >= test->settings->idle_timeout * SEC_TO_US) {
                           test->server_forced_idle_restarts_count += 1;
                           if (test->debug)
                               printf("Server restart (#%d) in idle state as no connection request was received for %d sec\n",
                                   test->server_forced_idle_restarts_count, test->settings->idle_timeout);
                           cleanup_server(test);
                           if ( iperf_get_test_one_off(test) ) {
                             if (test->debug)
                               printf("No connection request was received for %d sec in one-off mode; exiting.\n",
                                      test->settings->idle_timeout);
                             exit(0);
                           }
   
                           return 2;
                       }
                   }
                   else if (test->mode != SENDER && t_usecs > rcv_timeout_us) {
                       test->server_forced_no_msg_restarts_count += 1;
                       i_errno = IENOMSG;
                       if (iperf_get_verbose(test))
                           iperf_err(test, "Server restart (#%d) during active test due to idle timeout for receiving data",
                                     test->server_forced_no_msg_restarts_count);
                       cleanup_server(test);
                       return -1;
                   }
   
               }
         }          }
   
         if (result > 0) {          if (result > 0) {
               iperf_time_now(&last_receive_time);
             if (FD_ISSET(test->listener, &read_set)) {              if (FD_ISSET(test->listener, &read_set)) {
                 if (test->state != CREATE_STREAMS) {                  if (test->state != CREATE_STREAMS) {
                     if (iperf_accept(test) < 0) {                      if (iperf_accept(test) < 0) {
Line 488  iperf_run_server(struct iperf_test *test) Line 584  iperf_run_server(struct iperf_test *test)
                         return -1;                          return -1;
                     }                      }
                     FD_CLR(test->listener, &read_set);                      FD_CLR(test->listener, &read_set);
   
                       // Set streams number
                       if (test->mode == BIDIRECTIONAL) {
                           streams_to_send = test->num_streams;
                           streams_to_rec = test->num_streams;
                       } else if (test->mode == RECEIVER) {
                           streams_to_rec = test->num_streams;
                           streams_to_send = 0;
                       } else {
                           streams_to_send = test->num_streams;
                           streams_to_rec = 0;
                       }
                 }                  }
             }              }
             if (FD_ISSET(test->ctrl_sck, &read_set)) {              if (FD_ISSET(test->ctrl_sck, &read_set)) {
Line 495  iperf_run_server(struct iperf_test *test) Line 603  iperf_run_server(struct iperf_test *test)
                     cleanup_server(test);                      cleanup_server(test);
                     return -1;                      return -1;
                 }                  }
                FD_CLR(test->ctrl_sck, &read_set);                                FD_CLR(test->ctrl_sck, &read_set);
             }              }
   
             if (test->state == CREATE_STREAMS) {              if (test->state == CREATE_STREAMS) {
                 if (FD_ISSET(test->prot_listener, &read_set)) {                  if (FD_ISSET(test->prot_listener, &read_set)) {
    
                     if ((s = test->protocol->accept(test)) < 0) {                      if ((s = test->protocol->accept(test)) < 0) {
                         cleanup_server(test);                          cleanup_server(test);
                         return -1;                          return -1;
                     }                      }
   
                       /* apply other common socket options */
                       if (iperf_common_sockopts(test, s) < 0)
                       {
                           cleanup_server(test);
                           return -1;
                       }
   
                     if (!is_closed(s)) {                      if (!is_closed(s)) {
                         sp = iperf_new_stream(test, s);  
                         if (!sp) {  
                             cleanup_server(test);  
                             return -1;  
                         }  
   
                        if (test->sender)#if defined(HAVE_TCP_USER_TIMEOUT)
                            FD_SET(s, &test->write_set);                    if (test->protocol->id == Ptcp) {
                        else                        int opt;
                            FD_SET(s, &test->read_set);                        if ((opt = test->settings->snd_timeout)) {
                        if (s > test->max_fd) test->max_fd = s;                            if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
                                 saved_errno = errno;
                                 close(s);
                                 cleanup_server(test);
                                 errno = saved_errno;
                                 i_errno = IESETUSERTIMEOUT;
                                 return -1;
                             }
                         }
                     }
 #endif /* HAVE_TCP_USER_TIMEOUT */
   
                        /* #if defined(HAVE_TCP_CONGESTION)
                         * If the protocol isn't UDP, or even if it is but                    if (test->protocol->id == Ptcp) {
                         * we're the receiver, set nonblocking sockets.                        if (test->congestion) {
                         * We need this to allow a server receiver to                            if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
                         * maintain interactivity with the control channel.                                /*
                         */                                 * ENOENT means we tried to set the
                        if (test->protocol->id != Pudp ||                                 * congestion algorithm but the algorithm
                            !test->sender) {                                 * specified doesn't exist.  This can happen
                            setnonblocking(s, 1);                                 * if the client and server have different
                                  * congestion algorithms available.  In this
                                  * case, print a warning, but otherwise
                                  * continue.
                                  */
                                 if (errno == ENOENT) {
                                     warning("TCP congestion control algorithm not supported");
                                 }
                                 else {
                                     saved_errno = errno;
                                     close(s);
                                     cleanup_server(test);
                                     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);
                                   cleanup_server(test);
                                   errno = saved_errno;
                                   i_errno = IESETCONGESTION;
                                   return -1;
                               }
                               /*
                                * If not the first connection, discard prior
                                * congestion algorithm name so we don't leak
                                * duplicated strings.  We probably don't need
                                * the old string anyway.
                                */
                               if (test->congestion_used != NULL) {
                                   free(test->congestion_used);
                               }
                               // 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 */
   
                        streams_accepted++;                        if (rec_streams_accepted != streams_to_rec) {
                        if (test->on_new_stream)                            flag = 0;
                            test->on_new_stream(sp);                            ++rec_streams_accepted;
                         } else if (send_streams_accepted != streams_to_send) {
                             flag = 1;
                             ++send_streams_accepted;
                         }
 
                         if (flag != -1) {
                             sp = iperf_new_stream(test, s, flag);
                             if (!sp) {
                                 cleanup_server(test);
                                 return -1;
                             }
 
                             if (sp->sender)
                                 FD_SET(s, &test->write_set);
                             else
                                 FD_SET(s, &test->read_set);
 
                             if (s > test->max_fd) test->max_fd = s;
 
                             /*
                              * If the protocol isn't UDP, or even if it is but
                              * we're the receiver, set nonblocking sockets.
                              * We need this to allow a server receiver to
                              * maintain interactivity with the control channel.
                              */
                             if (test->protocol->id != Pudp ||
                                 !sp->sender) {
                                 setnonblocking(s, 1);
                             }
 
                             if (test->on_new_stream)
                                 test->on_new_stream(sp);
 
                             flag = -1;
                         }
                     }                      }
                     FD_CLR(test->prot_listener, &read_set);                      FD_CLR(test->prot_listener, &read_set);
                 }                  }
   
                if (streams_accepted == test->num_streams) {
                 if (rec_streams_accepted == streams_to_rec && send_streams_accepted == streams_to_send) {
                     if (test->protocol->id != Ptcp) {                      if (test->protocol->id != Ptcp) {
                         FD_CLR(test->prot_listener, &test->read_set);                          FD_CLR(test->prot_listener, &test->read_set);
                         close(test->prot_listener);                          close(test->prot_listener);
                    } else {                         test->prot_listener = -1;
                     } else {
                         if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {                          if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
                             FD_CLR(test->listener, &test->read_set);                              FD_CLR(test->listener, &test->read_set);
                             close(test->listener);                              close(test->listener);
                            if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {                            test->listener = -1;
                             if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) {
                                 cleanup_server(test);                                  cleanup_server(test);
                                 i_errno = IELISTEN;                                  i_errno = IELISTEN;
                                 return -1;                                  return -1;
Line 556  iperf_run_server(struct iperf_test *test) Line 763  iperf_run_server(struct iperf_test *test)
                         }                          }
                     }                      }
                     test->prot_listener = -1;                      test->prot_listener = -1;
   
                       /* Ensure that total requested data rate is not above limit */
                       iperf_size_t total_requested_rate = test->num_streams * test->settings->rate * (test->mode == BIDIRECTIONAL? 2 : 1);
                       if (test->settings->bitrate_limit > 0 && total_requested_rate > test->settings->bitrate_limit) {
                           if (iperf_get_verbose(test))
                               iperf_err(test, "Client total requested throughput rate of %" PRIu64 " bps exceeded %" PRIu64 " bps limit",
                                         total_requested_rate, test->settings->bitrate_limit);
                           cleanup_server(test);
                           i_errno = IETOTALRATE;
                           return -1;
                       }
   
                       // Begin calculating CPU utilization
                       cpu_util(NULL);
   
                     if (iperf_set_send_state(test, TEST_START) != 0) {                      if (iperf_set_send_state(test, TEST_START) != 0) {
                         cleanup_server(test);                          cleanup_server(test);
                         return -1;                          return -1;
Line 572  iperf_run_server(struct iperf_test *test) Line 794  iperf_run_server(struct iperf_test *test)
                         cleanup_server(test);                          cleanup_server(test);
                         return -1;                          return -1;
                     }                      }
                    if (test->reverse)                    if (test->mode != RECEIVER)
                         if (iperf_create_send_timers(test) < 0) {                          if (iperf_create_send_timers(test) < 0) {
                             cleanup_server(test);                              cleanup_server(test);
                             return -1;                              return -1;
Line 585  iperf_run_server(struct iperf_test *test) Line 807  iperf_run_server(struct iperf_test *test)
             }              }
   
             if (test->state == TEST_RUNNING) {              if (test->state == TEST_RUNNING) {
                if (test->reverse) {                if (test->mode == BIDIRECTIONAL) {
                     if (iperf_recv(test, &read_set) < 0) {
                         cleanup_server(test);
                         return -1;
                     }
                     if (iperf_send(test, &write_set) < 0) {
                         cleanup_server(test);
                         return -1;
                     }
                 } else if (test->mode == SENDER) {
                     // Reverse mode. Server sends.                      // Reverse mode. Server sends.
                     if (iperf_send(test, &write_set) < 0) {                      if (iperf_send(test, &write_set) < 0) {
                         cleanup_server(test);                          cleanup_server(test);
Line 598  iperf_run_server(struct iperf_test *test) Line 829  iperf_run_server(struct iperf_test *test)
                         return -1;                          return -1;
                     }                      }
                 }                  }
            }            }
         }          }
   
         if (result == 0 ||          if (result == 0 ||
             (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) {              (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) {
             /* Run the timers. */              /* Run the timers. */
            (void) gettimeofday(&now, NULL);            iperf_time_now(&now);
             tmr_run(&now);              tmr_run(&now);
         }          }
     }      }
   
     cleanup_server(test);  
   
     if (test->json_output) {      if (test->json_output) {
         if (iperf_json_finish(test) < 0)          if (iperf_json_finish(test) < 0)
             return -1;              return -1;
    }     }
   
     iflush(test);      iflush(test);
       cleanup_server(test);
   
    if (test->server_affinity != -1)     if (test->server_affinity != -1)
         if (iperf_clearaffinity(test) != 0)          if (iperf_clearaffinity(test) != 0)
             return -1;              return -1;
   

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


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