Diff for /embedaddon/iperf/src/net.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-2019, 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 29 Line 29
 #include <stdio.h>  #include <stdio.h>
 #include <unistd.h>  #include <unistd.h>
 #include <errno.h>  #include <errno.h>
   #include <arpa/inet.h>
 #include <sys/socket.h>  #include <sys/socket.h>
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/errno.h>  
 #include <netinet/in.h>  #include <netinet/in.h>
 #include <netinet/tcp.h>  
 #include <assert.h>  #include <assert.h>
 #include <netdb.h>  #include <netdb.h>
 #include <string.h>  #include <string.h>
#include <sys/fcntl.h>#include <fcntl.h>
 #include <limits.h>
   
 #ifdef HAVE_SENDFILE  #ifdef HAVE_SENDFILE
 #ifdef linux  #ifdef linux
Line 56 Line 56
 #endif  #endif
 #endif /* HAVE_SENDFILE */  #endif /* HAVE_SENDFILE */
   
   #ifdef HAVE_POLL_H
   #include <poll.h>
   #endif /* HAVE_POLL_H */
   
   #include "iperf.h"
 #include "iperf_util.h"  #include "iperf_util.h"
 #include "net.h"  #include "net.h"
 #include "timer.h"  #include "timer.h"
   
   static int nread_read_timeout = 10;
   static int nread_overall_timeout = 30;
   
   /*
    * Declaration of gerror in iperf_error.c.  Most other files in iperf3 can get this
    * by including "iperf.h", but net.c lives "below" this layer.  Clearly the
    * presence of this declaration is a sign we need to revisit this layering.
    */
   extern int gerror;
   
   /*
    * timeout_connect adapted from netcat, via OpenBSD and FreeBSD
    * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
    */
   int
   timeout_connect(int s, const struct sockaddr *name, socklen_t namelen,
       int timeout)
   {
           struct pollfd pfd;
           socklen_t optlen;
           int flags, optval;
           int ret;
   
           flags = 0;
           if (timeout != -1) {
                   flags = fcntl(s, F_GETFL, 0);
                   if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
                           return -1;
           }
   
           if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
                   pfd.fd = s;
                   pfd.events = POLLOUT;
                   if ((ret = poll(&pfd, 1, timeout)) == 1) {
                           optlen = sizeof(optval);
                           if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
                               &optval, &optlen)) == 0) {
                                   errno = optval;
                                   ret = optval == 0 ? 0 : -1;
                           }
                   } else if (ret == 0) {
                           errno = ETIMEDOUT;
                           ret = -1;
                   } else
                           ret = -1;
           }
   
           if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
                   ret = -1;
   
           return (ret);
   }
   
 /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/  /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/
  * Copyright: http://swtch.com/libtask/COPYRIGHT   * Copyright: http://swtch.com/libtask/COPYRIGHT
 */  */
   
/* make connection to server *//* create a socket */
 int  int
netdial(int domain, int proto, char *local, int local_port, char *server, int port)create_socket(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, struct addrinfo **server_res_out)
 {  {
    struct addrinfo hints, *local_res, *server_res;    struct addrinfo hints, *local_res = NULL, *server_res = NULL;
    int s;    int s, saved_errno;
     char portstr[6];
   
     if (local) {      if (local) {
         memset(&hints, 0, sizeof(hints));          memset(&hints, 0, sizeof(hints));
         hints.ai_family = domain;          hints.ai_family = domain;
         hints.ai_socktype = proto;          hints.ai_socktype = proto;
        if (getaddrinfo(local, NULL, &hints, &local_res) != 0)        if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0)
             return -1;              return -1;
     }      }
   
     memset(&hints, 0, sizeof(hints));      memset(&hints, 0, sizeof(hints));
     hints.ai_family = domain;      hints.ai_family = domain;
     hints.ai_socktype = proto;      hints.ai_socktype = proto;
    if (getaddrinfo(server, NULL, &hints, &server_res) != 0)    snprintf(portstr, sizeof(portstr), "%d", port);
     if ((gerror = getaddrinfo(server, portstr, &hints, &server_res)) != 0) {
         if (local)
             freeaddrinfo(local_res);
         return -1;          return -1;
       }
   
     s = socket(server_res->ai_family, proto, 0);      s = socket(server_res->ai_family, proto, 0);
     if (s < 0) {      if (s < 0) {
Line 93  netdial(int domain, int proto, char *local, int local_ Line 156  netdial(int domain, int proto, char *local, int local_
         return -1;          return -1;
     }      }
   
       if (bind_dev) {
   #if defined(HAVE_SO_BINDTODEVICE)
           if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
                          bind_dev, IFNAMSIZ) < 0)
   #endif // HAVE_SO_BINDTODEVICE
           {
               saved_errno = errno;
               close(s);
               freeaddrinfo(local_res);
               freeaddrinfo(server_res);
               errno = saved_errno;
               return -1;
           }
       }
   
       /* Bind the local address if given a name (with or without --cport) */
     if (local) {      if (local) {
         if (local_port) {          if (local_port) {
             struct sockaddr_in *lcladdr;              struct sockaddr_in *lcladdr;
             lcladdr = (struct sockaddr_in *)local_res->ai_addr;              lcladdr = (struct sockaddr_in *)local_res->ai_addr;
             lcladdr->sin_port = htons(local_port);              lcladdr->sin_port = htons(local_port);
             local_res->ai_addr = (struct sockaddr *)lcladdr;  
         }          }
   
         if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {          if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
               saved_errno = errno;
             close(s);              close(s);
             freeaddrinfo(local_res);              freeaddrinfo(local_res);
             freeaddrinfo(server_res);              freeaddrinfo(server_res);
               errno = saved_errno;
             return -1;              return -1;
         }          }
         freeaddrinfo(local_res);          freeaddrinfo(local_res);
     }      }
       /* No local name, but --cport given */
       else if (local_port) {
           size_t addrlen;
           struct sockaddr_storage lcl;
   
    ((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port);        /* IPv4 */
    if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {        if (server_res->ai_family == AF_INET) {
             struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl;
             lcladdr->sin_family = AF_INET;
             lcladdr->sin_port = htons(local_port);
             lcladdr->sin_addr.s_addr = INADDR_ANY;
             addrlen = sizeof(struct sockaddr_in);
         }
         /* IPv6 */
         else if (server_res->ai_family == AF_INET6) {
             struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl;
             lcladdr->sin6_family = AF_INET6;
             lcladdr->sin6_port = htons(local_port);
             lcladdr->sin6_addr = in6addr_any;
             addrlen = sizeof(struct sockaddr_in6);
         }
         /* Unknown protocol */
         else {
             close(s);
             freeaddrinfo(server_res);
             errno = EAFNOSUPPORT;
             return -1;
         }
 
         if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) {
             saved_errno = errno;
             close(s);
             freeaddrinfo(server_res);
             errno = saved_errno;
             return -1;
         }
     }
 
     *server_res_out = server_res;
     return s;
 }
 
 /* make connection to server */
 int
 netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout)
 {
     struct addrinfo *server_res = NULL;
     int s, saved_errno;
 
     s = create_socket(domain, proto, local, bind_dev, local_port, server, port, &server_res);
     if (s < 0) {
       return -1;
     }
 
     if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) {
         saved_errno = errno;
         close(s);          close(s);
         freeaddrinfo(server_res);          freeaddrinfo(server_res);
           errno = saved_errno;
         return -1;          return -1;
     }      }
   
Line 124  netdial(int domain, int proto, char *local, int local_ Line 258  netdial(int domain, int proto, char *local, int local_
 /***************************************************************/  /***************************************************************/
   
 int  int
netannounce(int domain, int proto, char *local, int port)netannounce(int domain, int proto, const char *local, const char *bind_dev, int port)
 {  {
     struct addrinfo hints, *res;      struct addrinfo hints, *res;
     char portstr[6];      char portstr[6];
    int s, opt;    int s, opt, saved_errno;
   
     snprintf(portstr, 6, "%d", port);      snprintf(portstr, 6, "%d", port);
     memset(&hints, 0, sizeof(hints));      memset(&hints, 0, sizeof(hints));
    /*     /*
      * If binding to the wildcard address with no explicit address       * If binding to the wildcard address with no explicit address
      * family specified, then force us to get an AF_INET6 socket.  On       * family specified, then force us to get an AF_INET6 socket.  On
      * CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family,       * CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family,
Line 152  netannounce(int domain, int proto, char *local, int po Line 286  netannounce(int domain, int proto, char *local, int po
     }      }
     hints.ai_socktype = proto;      hints.ai_socktype = proto;
     hints.ai_flags = AI_PASSIVE;      hints.ai_flags = AI_PASSIVE;
    if (getaddrinfo(local, portstr, &hints, &res) != 0)    if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0)
        return -1;         return -1;
   
     s = socket(res->ai_family, proto, 0);      s = socket(res->ai_family, proto, 0);
     if (s < 0) {      if (s < 0) {
Line 161  netannounce(int domain, int proto, char *local, int po Line 295  netannounce(int domain, int proto, char *local, int po
         return -1;          return -1;
     }      }
   
       if (bind_dev) {
   #if defined(HAVE_SO_BINDTODEVICE)
           if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
                          bind_dev, IFNAMSIZ) < 0)
   #endif // HAVE_SO_BINDTODEVICE
           {
               saved_errno = errno;
               close(s);
               freeaddrinfo(res);
               errno = saved_errno;
               return -1;
           }
       }
   
     opt = 1;      opt = 1;
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
                    (char *) &opt, sizeof(opt)) < 0) {                     (char *) &opt, sizeof(opt)) < 0) {
           saved_errno = errno;
         close(s);          close(s);
         freeaddrinfo(res);          freeaddrinfo(res);
           errno = saved_errno;
         return -1;          return -1;
     }      }
     /*      /*
Line 182  netannounce(int domain, int proto, char *local, int po Line 332  netannounce(int domain, int proto, char *local, int po
             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;
             close(s);              close(s);
             freeaddrinfo(res);              freeaddrinfo(res);
               errno = saved_errno;
             return -1;              return -1;
         }          }
     }      }
 #endif /* IPV6_V6ONLY */  #endif /* IPV6_V6ONLY */
   
     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {      if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
           saved_errno = errno;
         close(s);          close(s);
         freeaddrinfo(res);          freeaddrinfo(res);
           errno = saved_errno;
         return -1;          return -1;
     }      }
   
     freeaddrinfo(res);      freeaddrinfo(res);
    
     if (proto == SOCK_STREAM) {      if (proto == SOCK_STREAM) {
        if (listen(s, 5) < 0) {        if (listen(s, INT_MAX) < 0) {
             saved_errno = errno;
             close(s);              close(s);
               errno = saved_errno;
             return -1;              return -1;
         }          }
     }      }
Line 219  Nread(int fd, char *buf, size_t count, int prot) Line 375  Nread(int fd, char *buf, size_t count, int prot)
 {  {
     register ssize_t r;      register ssize_t r;
     register size_t nleft = count;      register size_t nleft = count;
       struct iperf_time ftimeout = { 0, 0 };
   
       fd_set rfdset;
       struct timeval timeout = { nread_read_timeout, 0 };
   
       /*
        * fd might not be ready for reading on entry. Check for this
        * (with timeout) first.
        *
        * This check could go inside the while() loop below, except we're
        * currently considering whether it might make sense to support a
        * codepath that bypassese this check, for situations where we
        * already know that fd has data on it (for example if we'd gotten
        * to here as the result of a select() call.
        */
       {
           FD_ZERO(&rfdset);
           FD_SET(fd, &rfdset);
           r = select(fd + 1, &rfdset, NULL, NULL, &timeout);
           if (r < 0) {
               return NET_HARDERROR;
           }
           if (r == 0) {
               return 0;
           }
       }
   
     while (nleft > 0) {      while (nleft > 0) {
         r = read(fd, buf, nleft);          r = read(fd, buf, nleft);
         if (r < 0) {          if (r < 0) {
Line 232  Nread(int fd, char *buf, size_t count, int prot) Line 414  Nread(int fd, char *buf, size_t count, int prot)
   
         nleft -= r;          nleft -= r;
         buf += r;          buf += r;
   
           /*
            * We need some more bytes but don't want to wait around
            * forever for them. In the case of partial results, we need
            * to be able to read some bytes every nread_timeout seconds.
            */
           if (nleft > 0) {
               struct iperf_time now;
   
               /*
                * Also, we have an approximate upper limit for the total time
                * that a Nread call is supposed to take. We trade off accuracy
                * of this timeout for a hopefully lower performance impact.
                */
               iperf_time_now(&now);
               if (ftimeout.secs == 0) {
                   ftimeout = now;
                   iperf_time_add_usecs(&ftimeout, nread_overall_timeout * 1000000L);
               }
               if (iperf_time_compare(&ftimeout, &now) < 0) {
                   break;
               }
   
               FD_ZERO(&rfdset);
               FD_SET(fd, &rfdset);
               r = select(fd + 1, &rfdset, NULL, NULL, &timeout);
               if (r < 0) {
                   return NET_HARDERROR;
               }
               if (r == 0) {
                   break;
               }
           }
     }      }
     return count - nleft;      return count - nleft;
 }  }
Line 292  has_sendfile(void) Line 507  has_sendfile(void)
 int  int
 Nsendfile(int fromfd, int tofd, const char *buf, size_t count)  Nsendfile(int fromfd, int tofd, const char *buf, size_t count)
 {  {
     off_t offset;  
 #if defined(HAVE_SENDFILE)  #if defined(HAVE_SENDFILE)
       off_t offset;
 #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6))  #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6))
     off_t sent;      off_t sent;
 #endif  #endif
Line 351  Nsendfile(int fromfd, int tofd, const char *buf, size_ Line 566  Nsendfile(int fromfd, int tofd, const char *buf, size_
 }  }
   
 /*************************************************************************/  /*************************************************************************/
   
 /**  
  * getsock_tcp_mss - Returns the MSS size for TCP  
  *  
  */  
   
 int  
 getsock_tcp_mss(int inSock)  
 {  
     int             mss = 0;  
   
     int             rc;  
     socklen_t       len;  
   
     assert(inSock >= 0); /* print error and exit if this is not true */  
   
     /* query for mss */  
     len = sizeof(mss);  
     rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len);  
     if (rc == -1) {  
         perror("getsockopt TCP_MAXSEG");  
         return -1;  
     }  
   
     return mss;  
 }  
   
   
   
 /*************************************************************/  
   
 /* sets TCP_NODELAY and TCP_MAXSEG if requested */  
 // XXX: This function is not being used.  
   
 int  
 set_tcp_options(int sock, int no_delay, int mss)  
 {  
     socklen_t len;  
     int rc;  
     int new_mss;  
   
     if (no_delay == 1) {  
         len = sizeof(no_delay);  
         rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&no_delay, len);  
         if (rc == -1) {  
             perror("setsockopt TCP_NODELAY");  
             return -1;  
         }  
     }  
 #ifdef TCP_MAXSEG  
     if (mss > 0) {  
         len = sizeof(new_mss);  
         assert(sock != -1);  
   
         /* set */  
         new_mss = mss;  
         len = sizeof(new_mss);  
         rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len);  
         if (rc == -1) {  
             perror("setsockopt TCP_MAXSEG");  
             return -1;  
         }  
         /* verify results */  
         rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len);  
         if (rc == -1) {  
             perror("getsockopt TCP_MAXSEG");  
             return -1;  
         }  
         if (new_mss != mss) {  
             perror("setsockopt value mismatch");  
             return -1;  
         }  
     }  
 #endif  
     return 0;  
 }  
   
 /****************************************************************************/  
   
 int  int
 setnonblocking(int fd, int nonblocking)  setnonblocking(int fd, int nonblocking)

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


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