Diff for /embedaddon/iperf/src/iperf_server_api.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2016/10/18 13:28:18 version 1.1.1.2, 2021/03/17 00:36:46
Line 1 Line 1
 /*  /*
 * iperf, Copyright (c) 2014, 2015, The Regents of the University of * iperf, Copyright (c) 2014-2020 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)
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");        iperf_printf(test, "-----------------------------------------------------------\n");
        iprintf(test, "Server listening on %d\n", test->server_port);        iperf_printf(test, "Server listening on %d\n", test->server_port);
         iperf_printf(test, "-----------------------------------------------------------\n");
         if (test->forceflush)
             iflush(test);
     }      }
   
     // This needs to be changed to reflect if client has different window size  
     // make sure we got what we asked for  
     /* XXX: This needs to be moved to the stream listener  
     if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) {  
         // 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);
     FD_SET(test->listener, &test->read_set);      FD_SET(test->listener, &test->read_set);
Line 246  iperf_handle_message_server(struct iperf_test *test) Line 223  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->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 255  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 268  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 308  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;
   
Line 371  server_omit_timer_proc(TimerClientData client_data, st Line 316  server_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 383  server_omit_timer_proc(TimerClientData client_data, st Line 328  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; 
         }          }
Line 409  create_server_omit_timer(struct iperf_test * test) Line 354  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) {
           FD_CLR(sp->socket, &test->read_set);
           FD_CLR(sp->socket, &test->write_set);
           close(sp->socket);
       }
   
     /* Close open test sockets */      /* Close open test sockets */
    close(test->ctrl_sck);    if (test->ctrl_sck) {
    close(test->listener);        close(test->ctrl_sck);
     }
     if (test->listener) {
         close(test->listener);
     }
   
     /* 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 384  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 timeval* timeout;      struct timeval* timeout;
       int flag;
   
       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 -2;              return -2;
Line 450  iperf_run_server(struct iperf_test *test) Line 426  iperf_run_server(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);
     }      }
   
Line 465  iperf_run_server(struct iperf_test *test) Line 441  iperf_run_server(struct iperf_test *test)
     cpu_util(NULL);      cpu_util(NULL);
   
     test->state = IPERF_START;      test->state = IPERF_START;
    streams_accepted = 0;    send_streams_accepted = 0;
     rec_streams_accepted = 0;
   
     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);
         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;
Line 488  iperf_run_server(struct iperf_test *test) Line 473  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 506  iperf_run_server(struct iperf_test *test) Line 503  iperf_run_server(struct iperf_test *test)
                         return -1;                          return -1;
                     }                      }
   
                    if (!is_closed(s)) {#if defined(HAVE_TCP_CONGESTION)
                        sp = iperf_new_stream(test, s);                    if (test->protocol->id == Ptcp) {
                        if (!sp) {                        if (test->congestion) {
                            cleanup_server(test);                            if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
                            return -1;                                /*
                                  * ENOENT means we tried to set the
                                  * congestion algorithm but the algorithm
                                  * specified doesn't exist.  This can happen
                                  * 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];
                               if (getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len) < 0) {
                                   saved_errno = errno;
                                   close(s);
                                   cleanup_server(test);
                                   errno = saved_errno;
                                   i_errno = IESETCONGESTION;
                                   return -1;
                               }
                               test->congestion_used = strdup(ca);
                               if (test->debug) {
                                   printf("Congestion algorithm is %s\n", test->congestion_used);
                               }
                           }
                       }
   #endif /* HAVE_TCP_CONGESTION */
   
                        if (test->sender)                    if (!is_closed(s)) {
                            FD_SET(s, &test->write_set); 
                        else 
                            FD_SET(s, &test->read_set); 
                        if (s > test->max_fd) test->max_fd = s; 
   
                        /*                         if (rec_streams_accepted != streams_to_rec) {
                         * If the protocol isn't UDP, or even if it is but                            flag = 0;
                         * we're the receiver, set nonblocking sockets.                            ++rec_streams_accepted;
                         * We need this to allow a server receiver to                        } else if (send_streams_accepted != streams_to_send) {
                         * maintain interactivity with the control channel.                            flag = 1;
                         */                            ++send_streams_accepted;
                        if (test->protocol->id != Pudp ||                        }
                            !test->sender) { 
                            setnonblocking(s, 1); 
                        } 
   
                        streams_accepted++;                        if (flag != -1) {
                        if (test->on_new_stream)                            sp = iperf_new_stream(test, s, flag);
                            test->on_new_stream(sp);                            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);
Line 545  iperf_run_server(struct iperf_test *test) Line 601  iperf_run_server(struct iperf_test *test)
                         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);
                               test->listener = 0;
                             if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {                              if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
                                 cleanup_server(test);                                  cleanup_server(test);
                                 i_errno = IELISTEN;                                  i_errno = IELISTEN;
Line 556  iperf_run_server(struct iperf_test *test) Line 613  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) {
                           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;
                       }
   
                     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 640  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 653  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 675  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);
         }          }
     }      }

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


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