Diff for /embedaddon/iperf/src/iperf_tcp.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, 2016, The Regents of the University of * iperf, Copyright (c) 2014-2022, The Regents of the University of
  * California, through Lawrence Berkeley National Laboratory (subject   * California, through Lawrence Berkeley National Laboratory (subject
  * to receipt of any required approvals from the U.S. Dept. of   * to receipt of any required approvals from the U.S. Dept. of
  * Energy).  All rights reserved.   * Energy).  All rights reserved.
Line 24 Line 24
  * This code is distributed under a BSD style license, see the LICENSE   * This code is distributed under a BSD style license, see the LICENSE
  * file for complete information.   * file for complete information.
  */   */
 #include "iperf_config.h"  
   
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
 #include <errno.h>  #include <errno.h>
 #include <unistd.h>  #include <unistd.h>
   #include <arpa/inet.h>
 #include <sys/socket.h>  #include <sys/socket.h>
 #include <sys/types.h>  #include <sys/types.h>
 #include <netinet/in.h>  #include <netinet/in.h>
 #include <netdb.h>  #include <netdb.h>
 #include <netinet/tcp.h>  
 #include <sys/time.h>  #include <sys/time.h>
 #include <sys/select.h>  #include <sys/select.h>
   #include <limits.h>
   
 #include "iperf.h"  #include "iperf.h"
 #include "iperf_api.h"  #include "iperf_api.h"
 #include "iperf_tcp.h"  #include "iperf_tcp.h"
 #include "net.h"  #include "net.h"
   #include "cjson.h"
   
 #if defined(HAVE_FLOWLABEL)  #if defined(HAVE_FLOWLABEL)
 #include "flowlabel.h"  #include "flowlabel.h"
Line 62  iperf_tcp_recv(struct iperf_stream *sp) Line 62  iperf_tcp_recv(struct iperf_stream *sp)
     if (r < 0)      if (r < 0)
         return r;          return r;
   
    sp->result->bytes_received += r;    /* Only count bytes received while we're in the correct state. */
    sp->result->bytes_received_this_interval += r;    if (sp->test->state == TEST_RUNNING) {
         sp->result->bytes_received += r;
         sp->result->bytes_received_this_interval += r;
     }
     else {
         if (sp->test->debug)
             printf("Late receive, state = %d\n", sp->test->state);
     }
   
     return r;      return r;
 }  }
   
   
/* iperf_tcp_send /* iperf_tcp_send
  *   *
  * sends the data for TCP   * sends the data for TCP
  */   */
Line 78  iperf_tcp_send(struct iperf_stream *sp) Line 85  iperf_tcp_send(struct iperf_stream *sp)
 {  {
     int r;      int r;
   
       if (!sp->pending_size)
           sp->pending_size = sp->settings->blksize;
   
     if (sp->test->zerocopy)      if (sp->test->zerocopy)
        r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->settings->blksize);        r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->pending_size);
     else      else
        r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);        r = Nwrite(sp->socket, sp->buffer, sp->pending_size, Ptcp);
   
     if (r < 0)      if (r < 0)
         return r;          return r;
   
       sp->pending_size -= r;
     sp->result->bytes_sent += r;      sp->result->bytes_sent += r;
     sp->result->bytes_sent_this_interval += r;      sp->result->bytes_sent_this_interval += r;
   
       if (sp->test->debug_level >=  DEBUG_LEVEL_DEBUG)
           printf("sent %d bytes of %d, pending %d, total %" PRIu64 "\n",
               r, sp->settings->blksize, sp->pending_size, sp->result->bytes_sent);
   
     return r;      return r;
 }  }
   
Line 119  iperf_tcp_accept(struct iperf_test * test) Line 134  iperf_tcp_accept(struct iperf_test * test)
   
     if (strcmp(test->cookie, cookie) != 0) {      if (strcmp(test->cookie, cookie) != 0) {
         if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {          if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
            i_errno = IESENDMESSAGE;            iperf_err(test, "failed to send access denied from busy server to new connecting client, errno = %d\n", errno);
            return -1; 
         }          }
         close(s);          close(s);
     }      }
Line 136  iperf_tcp_accept(struct iperf_test * test) Line 150  iperf_tcp_accept(struct iperf_test * test)
 int  int
 iperf_tcp_listen(struct iperf_test *test)  iperf_tcp_listen(struct iperf_test *test)
 {  {
     struct addrinfo hints, *res;  
     char portstr[6];  
     int s, opt;      int s, opt;
       socklen_t optlen;
     int saved_errno;      int saved_errno;
       int rcvbuf_actual, sndbuf_actual;
   
     s = test->listener;      s = test->listener;
   
Line 153  iperf_tcp_listen(struct iperf_test *test) Line 167  iperf_tcp_listen(struct iperf_test *test)
      * It's not clear whether this is a requirement or a convenience.       * It's not clear whether this is a requirement or a convenience.
      */       */
     if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {      if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
           struct addrinfo hints, *res;
           char portstr[6];
   
         FD_CLR(s, &test->read_set);          FD_CLR(s, &test->read_set);
         close(s);          close(s);
   
Line 172  iperf_tcp_listen(struct iperf_test *test) Line 189  iperf_tcp_listen(struct iperf_test *test)
         }          }
         hints.ai_socktype = SOCK_STREAM;          hints.ai_socktype = SOCK_STREAM;
         hints.ai_flags = AI_PASSIVE;          hints.ai_flags = AI_PASSIVE;
        if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) {        if ((gerror = getaddrinfo(test->bind_address, portstr, &hints, &res)) != 0) {
             i_errno = IESTREAMLISTEN;              i_errno = IESTREAMLISTEN;
             return -1;              return -1;
         }          }
Line 223  iperf_tcp_listen(struct iperf_test *test) Line 240  iperf_tcp_listen(struct iperf_test *test)
                 return -1;                  return -1;
             }              }
         }          }
         if (test->debug) {  
             socklen_t optlen = sizeof(opt);  
             if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) {  
                 saved_errno = errno;  
                 close(s);  
                 freeaddrinfo(res);  
                 errno = saved_errno;  
                 i_errno = IESETBUF;  
                 return -1;  
             }  
             printf("SO_SNDBUF is %u\n", opt);  
         }  
 #if defined(HAVE_TCP_CONGESTION)  
         if (test->congestion) {  
             if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {  
                 close(s);  
                 freeaddrinfo(res);  
                 i_errno = IESETCONGESTION;  
                 return -1;  
             }   
         }  
 #endif /* HAVE_TCP_CONGESTION */  
 #if defined(HAVE_SO_MAX_PACING_RATE)  #if defined(HAVE_SO_MAX_PACING_RATE)
    /* If socket pacing is available and not disabled, try it. */    /* If fq socket pacing is specified, enable it. */
    if (! test->no_fq_socket_pacing) {    if (test->settings->fqrate) {
         /* Convert bits per second to bytes per second */          /* Convert bits per second to bytes per second */
        unsigned int rate = test->settings->rate / 8;        unsigned int fqrate = test->settings->fqrate / 8;
        if (rate > 0) {        if (fqrate > 0) {
             if (test->debug) {              if (test->debug) {
                printf("Setting fair-queue socket pacing to %u\n", rate);                printf("Setting fair-queue socket pacing to %u\n", fqrate);
             }              }
            if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) {            if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
                warning("Unable to set socket pacing, using application pacing instead");                warning("Unable to set socket pacing");
                test->no_fq_socket_pacing = 1; 
             }              }
         }          }
     }      }
 #endif /* HAVE_SO_MAX_PACING_RATE */  #endif /* HAVE_SO_MAX_PACING_RATE */
       {
           unsigned int rate = test->settings->rate / 8;
           if (rate > 0) {
               if (test->debug) {
                   printf("Setting application pacing to %u\n", rate);
               }
           }
       }
         opt = 1;          opt = 1;
         if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {          if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
             saved_errno = errno;              saved_errno = errno;
Line 272  iperf_tcp_listen(struct iperf_test *test) Line 274  iperf_tcp_listen(struct iperf_test *test)
         }          }
   
         /*          /*
         * If we got an IPv6 socket, figure out if it shoudl accept IPv4         * If we got an IPv6 socket, figure out if it should accept IPv4
          * connections as well.  See documentation in netannounce() for           * connections as well.  See documentation in netannounce() for
          * more details.           * more details.
          */           */
Line 280  iperf_tcp_listen(struct iperf_test *test) Line 282  iperf_tcp_listen(struct iperf_test *test)
         if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET)) {          if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET)) {
             if (test->settings->domain == AF_UNSPEC)              if (test->settings->domain == AF_UNSPEC)
                 opt = 0;                  opt = 0;
            else             else
                 opt = 1;                  opt = 1;
            if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,             if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
                            (char *) &opt, sizeof(opt)) < 0) {                             (char *) &opt, sizeof(opt)) < 0) {
                 saved_errno = errno;                  saved_errno = errno;
                 close(s);                  close(s);
Line 305  iperf_tcp_listen(struct iperf_test *test) Line 307  iperf_tcp_listen(struct iperf_test *test)
   
         freeaddrinfo(res);          freeaddrinfo(res);
   
        if (listen(s, 5) < 0) {        if (listen(s, INT_MAX) < 0) {
             i_errno = IESTREAMLISTEN;              i_errno = IESTREAMLISTEN;
             return -1;              return -1;
         }          }
   
         test->listener = s;          test->listener = s;
     }      }
    
     /* Read back and verify the sender socket buffer size */
     optlen = sizeof(sndbuf_actual);
     if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) {
         saved_errno = errno;
         close(s);
         errno = saved_errno;
         i_errno = IESETBUF;
         return -1;
     }
     if (test->debug) {
         printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize);
     }
     if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) {
         i_errno = IESETBUF2;
         return -1;
     }
 
     /* Read back and verify the receiver socket buffer size */
     optlen = sizeof(rcvbuf_actual);
     if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) {
         saved_errno = errno;
         close(s);
         errno = saved_errno;
         i_errno = IESETBUF;
         return -1;
     }
     if (test->debug) {
         printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize);
     }
     if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) {
         i_errno = IESETBUF2;
         return -1;
     }
 
     if (test->json_output) {
         cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize);
         cJSON_AddNumberToObject(test->json_start, "sndbuf_actual", sndbuf_actual);
         cJSON_AddNumberToObject(test->json_start, "rcvbuf_actual", rcvbuf_actual);
     }
 
     return s;      return s;
 }  }
   
Line 320  iperf_tcp_listen(struct iperf_test *test) Line 362  iperf_tcp_listen(struct iperf_test *test)
 /* iperf_tcp_connect  /* iperf_tcp_connect
  *   *
  * connect to a TCP stream listener   * connect to a TCP stream listener
    * This function is roughly similar to netdial(), and may indeed have
    * been derived from it at some point, but it sets many TCP-specific
    * options between socket creation and connection.
  */   */
 int  int
 iperf_tcp_connect(struct iperf_test *test)  iperf_tcp_connect(struct iperf_test *test)
 {  {
    struct addrinfo hints, *local_res, *server_res;    struct addrinfo *server_res;
    char portstr[6]; 
     int s, opt;      int s, opt;
       socklen_t optlen;
     int saved_errno;      int saved_errno;
       int rcvbuf_actual, sndbuf_actual;
   
    if (test->bind_address) {    s = create_socket(test->settings->domain, SOCK_STREAM, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, &server_res);
        memset(&hints, 0, sizeof(hints));    if (s < 0) {
        hints.ai_family = test->settings->domain;        i_errno = IESTREAMCONNECT;
        hints.ai_socktype = SOCK_STREAM;        return -1;
        if (getaddrinfo(test->bind_address, NULL, &hints, &local_res) != 0) { 
            i_errno = IESTREAMCONNECT; 
            return -1; 
        } 
     }      }
   
     memset(&hints, 0, sizeof(hints));  
     hints.ai_family = test->settings->domain;  
     hints.ai_socktype = SOCK_STREAM;  
     snprintf(portstr, sizeof(portstr), "%d", test->server_port);  
     if (getaddrinfo(test->server_hostname, portstr, &hints, &server_res) != 0) {  
         if (test->bind_address)  
             freeaddrinfo(local_res);  
         i_errno = IESTREAMCONNECT;  
         return -1;  
     }  
   
     if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) {  
         if (test->bind_address)  
             freeaddrinfo(local_res);  
         freeaddrinfo(server_res);  
         i_errno = IESTREAMCONNECT;  
         return -1;  
     }  
   
     if (test->bind_address) {  
         struct sockaddr_in *lcladdr;  
         lcladdr = (struct sockaddr_in *)local_res->ai_addr;  
         lcladdr->sin_port = htons(test->bind_port);  
         local_res->ai_addr = (struct sockaddr *)lcladdr;  
   
         if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {  
             saved_errno = errno;  
             close(s);  
             freeaddrinfo(local_res);  
             freeaddrinfo(server_res);  
             errno = saved_errno;  
             i_errno = IESTREAMCONNECT;  
             return -1;  
         }  
         freeaddrinfo(local_res);  
     }  
   
     /* Set socket options */      /* Set socket options */
     if (test->no_delay) {      if (test->no_delay) {
         opt = 1;          opt = 1;
Line 416  iperf_tcp_connect(struct iperf_test *test) Line 421  iperf_tcp_connect(struct iperf_test *test)
             return -1;              return -1;
         }          }
     }      }
    if (test->debug) {#if defined(HAVE_TCP_USER_TIMEOUT)
        socklen_t optlen = sizeof(opt);    if ((opt = test->settings->snd_timeout)) {
        if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) {        if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
             saved_errno = errno;              saved_errno = errno;
             close(s);              close(s);
             freeaddrinfo(server_res);              freeaddrinfo(server_res);
             errno = saved_errno;              errno = saved_errno;
            i_errno = IESETBUF;            i_errno = IESETUSERTIMEOUT;
            return -1;            return -1;
        }        }
        printf("SO_SNDBUF is %u\n", opt); 
     }      }
   #endif /* HAVE_TCP_USER_TIMEOUT */
   
       /* Read back and verify the sender socket buffer size */
       optlen = sizeof(sndbuf_actual);
       if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) {
           saved_errno = errno;
           close(s);
           freeaddrinfo(server_res);
           errno = saved_errno;
           i_errno = IESETBUF;
           return -1;
       }
       if (test->debug) {
           printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize);
       }
       if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) {
           i_errno = IESETBUF2;
           return -1;
       }
   
       /* Read back and verify the receiver socket buffer size */
       optlen = sizeof(rcvbuf_actual);
       if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) {
           saved_errno = errno;
           close(s);
           freeaddrinfo(server_res);
           errno = saved_errno;
           i_errno = IESETBUF;
           return -1;
       }
       if (test->debug) {
           printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize);
       }
       if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) {
           i_errno = IESETBUF2;
           return -1;
       }
   
       if (test->json_output) {
       cJSON *sock_bufsize_item = cJSON_GetObjectItem(test->json_start, "sock_bufsize");
       if (sock_bufsize_item == NULL) {
       cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize);
       }
   
       cJSON *sndbuf_actual_item = cJSON_GetObjectItem(test->json_start, "sndbuf_actual");
       if (sndbuf_actual_item == NULL) {
           cJSON_AddNumberToObject(test->json_start, "sndbuf_actual", sndbuf_actual);
       }
           
       cJSON *rcvbuf_actual_item = cJSON_GetObjectItem(test->json_start, "rcvbuf_actual");
       if (rcvbuf_actual_item == NULL) {
           cJSON_AddNumberToObject(test->json_start, "rcvbuf_actual", rcvbuf_actual);
       }
       }
   
 #if defined(HAVE_FLOWLABEL)  #if defined(HAVE_FLOWLABEL)
     if (test->settings->flowlabel) {      if (test->settings->flowlabel) {
         if (server_res->ai_addr->sa_family != AF_INET6) {          if (server_res->ai_addr->sa_family != AF_INET6) {
Line 447  iperf_tcp_connect(struct iperf_test *test) Line 506  iperf_tcp_connect(struct iperf_test *test)
             freq->flr_label = htonl(test->settings->flowlabel & IPV6_FLOWINFO_FLOWLABEL);              freq->flr_label = htonl(test->settings->flowlabel & IPV6_FLOWINFO_FLOWLABEL);
             freq->flr_action = IPV6_FL_A_GET;              freq->flr_action = IPV6_FL_A_GET;
             freq->flr_flags = IPV6_FL_F_CREATE;              freq->flr_flags = IPV6_FL_F_CREATE;
            freq->flr_share = IPV6_FL_F_CREATE | IPV6_FL_S_EXCL;            freq->flr_share = IPV6_FL_S_ANY;
             memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16);              memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16);
   
             if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) {              if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) {
Line 468  iperf_tcp_connect(struct iperf_test *test) Line 527  iperf_tcp_connect(struct iperf_test *test)
                 errno = saved_errno;                  errno = saved_errno;
                 i_errno = IESETFLOW;                  i_errno = IESETFLOW;
                 return -1;                  return -1;
            }             }
         }          }
     }      }
 #endif /* HAVE_FLOWLABEL */  #endif /* HAVE_FLOWLABEL */
   
 #if defined(HAVE_TCP_CONGESTION)  
     if (test->congestion) {  
         if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {  
             close(s);  
             freeaddrinfo(server_res);  
             i_errno = IESETCONGESTION;  
             return -1;  
         }  
     }  
 #endif /* HAVE_TCP_CONGESTION */  
   
 #if defined(HAVE_SO_MAX_PACING_RATE)  #if defined(HAVE_SO_MAX_PACING_RATE)
    /* If socket pacing is available and not disabled, try it. */    /* If socket pacing is specified try to enable it. */
    if (! test->no_fq_socket_pacing) {    if (test->settings->fqrate) {
         /* Convert bits per second to bytes per second */          /* Convert bits per second to bytes per second */
        unsigned int rate = test->settings->rate / 8;        unsigned int fqrate = test->settings->fqrate / 8;
        if (rate > 0) {        if (fqrate > 0) {
             if (test->debug) {              if (test->debug) {
                printf("Socket pacing set to %u\n", rate);                printf("Setting fair-queue socket pacing to %u\n", fqrate);
             }              }
            if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) {            if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
                warning("Unable to set socket pacing, using application pacing instead");                warning("Unable to set socket pacing");
                test->no_fq_socket_pacing = 1; 
             }              }
         }          }
     }      }
 #endif /* HAVE_SO_MAX_PACING_RATE */  #endif /* HAVE_SO_MAX_PACING_RATE */
       {
           unsigned int rate = test->settings->rate / 8;
           if (rate > 0) {
               if (test->debug) {
                   printf("Setting application pacing to %u\n", rate);
               }
           }
       }
   
       /* Set common socket options */
       iperf_common_sockopts(test, s);
   
     if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {      if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
         saved_errno = errno;          saved_errno = errno;

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


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