File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iperf / src / net.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:14:54 2023 UTC (18 months, 2 weeks ago) by misho
Branches: iperf, MAIN
CVS tags: v3_15, HEAD
Version 3.15

    1: /*
    2:  * iperf, Copyright (c) 2014-2019, The Regents of the University of
    3:  * California, through Lawrence Berkeley National Laboratory (subject
    4:  * to receipt of any required approvals from the U.S. Dept. of
    5:  * Energy).  All rights reserved.
    6:  *
    7:  * If you have questions about your rights to use or distribute this
    8:  * software, please contact Berkeley Lab's Technology Transfer
    9:  * Department at TTD@lbl.gov.
   10:  *
   11:  * NOTICE.  This software is owned by the U.S. Department of Energy.
   12:  * As such, the U.S. Government has been granted for itself and others
   13:  * acting on its behalf a paid-up, nonexclusive, irrevocable,
   14:  * worldwide license in the Software to reproduce, prepare derivative
   15:  * works, and perform publicly and display publicly.  Beginning five
   16:  * (5) years after the date permission to assert copyright is obtained
   17:  * from the U.S. Department of Energy, and subject to any subsequent
   18:  * five (5) year renewals, the U.S. Government is granted for itself
   19:  * and others acting on its behalf a paid-up, nonexclusive,
   20:  * irrevocable, worldwide license in the Software to reproduce,
   21:  * prepare derivative works, distribute copies to the public, perform
   22:  * publicly and display publicly, and to permit others to do so.
   23:  *
   24:  * This code is distributed under a BSD style license, see the LICENSE
   25:  * file for complete information.
   26:  */
   27: #include "iperf_config.h"
   28: 
   29: #include <stdio.h>
   30: #include <unistd.h>
   31: #include <errno.h>
   32: #include <arpa/inet.h>
   33: #include <sys/socket.h>
   34: #include <sys/types.h>
   35: #include <netinet/in.h>
   36: #include <assert.h>
   37: #include <netdb.h>
   38: #include <string.h>
   39: #include <fcntl.h>
   40: #include <limits.h>
   41: 
   42: #ifdef HAVE_SENDFILE
   43: #ifdef linux
   44: #include <sys/sendfile.h>
   45: #else
   46: #ifdef __FreeBSD__
   47: #include <sys/uio.h>
   48: #else
   49: #if defined(__APPLE__) && defined(__MACH__)	/* OS X */
   50: #include <AvailabilityMacros.h>
   51: #if defined(MAC_OS_X_VERSION_10_6)
   52: #include <sys/uio.h>
   53: #endif
   54: #endif
   55: #endif
   56: #endif
   57: #endif /* HAVE_SENDFILE */
   58: 
   59: #ifdef HAVE_POLL_H
   60: #include <poll.h>
   61: #endif /* HAVE_POLL_H */
   62: 
   63: #include "iperf.h"
   64: #include "iperf_util.h"
   65: #include "net.h"
   66: #include "timer.h"
   67: 
   68: static int nread_read_timeout = 10;
   69: static int nread_overall_timeout = 30;
   70: 
   71: /*
   72:  * Declaration of gerror in iperf_error.c.  Most other files in iperf3 can get this
   73:  * by including "iperf.h", but net.c lives "below" this layer.  Clearly the
   74:  * presence of this declaration is a sign we need to revisit this layering.
   75:  */
   76: extern int gerror;
   77: 
   78: /*
   79:  * timeout_connect adapted from netcat, via OpenBSD and FreeBSD
   80:  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
   81:  */
   82: int
   83: timeout_connect(int s, const struct sockaddr *name, socklen_t namelen,
   84:     int timeout)
   85: {
   86: 	struct pollfd pfd;
   87: 	socklen_t optlen;
   88: 	int flags, optval;
   89: 	int ret;
   90: 
   91: 	flags = 0;
   92: 	if (timeout != -1) {
   93: 		flags = fcntl(s, F_GETFL, 0);
   94: 		if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
   95: 			return -1;
   96: 	}
   97: 
   98: 	if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
   99: 		pfd.fd = s;
  100: 		pfd.events = POLLOUT;
  101: 		if ((ret = poll(&pfd, 1, timeout)) == 1) {
  102: 			optlen = sizeof(optval);
  103: 			if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
  104: 			    &optval, &optlen)) == 0) {
  105: 				errno = optval;
  106: 				ret = optval == 0 ? 0 : -1;
  107: 			}
  108: 		} else if (ret == 0) {
  109: 			errno = ETIMEDOUT;
  110: 			ret = -1;
  111: 		} else
  112: 			ret = -1;
  113: 	}
  114: 
  115: 	if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
  116: 		ret = -1;
  117: 
  118: 	return (ret);
  119: }
  120: 
  121: /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/
  122:  * Copyright: http://swtch.com/libtask/COPYRIGHT
  123: */
  124: 
  125: /* create a socket */
  126: int
  127: 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)
  128: {
  129:     struct addrinfo hints, *local_res = NULL, *server_res = NULL;
  130:     int s, saved_errno;
  131:     char portstr[6];
  132: 
  133:     if (local) {
  134:         memset(&hints, 0, sizeof(hints));
  135:         hints.ai_family = domain;
  136:         hints.ai_socktype = proto;
  137:         if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0)
  138:             return -1;
  139:     }
  140: 
  141:     memset(&hints, 0, sizeof(hints));
  142:     hints.ai_family = domain;
  143:     hints.ai_socktype = proto;
  144:     snprintf(portstr, sizeof(portstr), "%d", port);
  145:     if ((gerror = getaddrinfo(server, portstr, &hints, &server_res)) != 0) {
  146: 	if (local)
  147: 	    freeaddrinfo(local_res);
  148:         return -1;
  149:     }
  150: 
  151:     s = socket(server_res->ai_family, proto, 0);
  152:     if (s < 0) {
  153: 	if (local)
  154: 	    freeaddrinfo(local_res);
  155: 	freeaddrinfo(server_res);
  156:         return -1;
  157:     }
  158: 
  159:     if (bind_dev) {
  160: #if defined(HAVE_SO_BINDTODEVICE)
  161:         if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
  162:                        bind_dev, IFNAMSIZ) < 0)
  163: #endif // HAVE_SO_BINDTODEVICE
  164:         {
  165:             saved_errno = errno;
  166:             close(s);
  167:             freeaddrinfo(local_res);
  168:             freeaddrinfo(server_res);
  169:             errno = saved_errno;
  170:             return -1;
  171:         }
  172:     }
  173: 
  174:     /* Bind the local address if given a name (with or without --cport) */
  175:     if (local) {
  176:         if (local_port) {
  177:             struct sockaddr_in *lcladdr;
  178:             lcladdr = (struct sockaddr_in *)local_res->ai_addr;
  179:             lcladdr->sin_port = htons(local_port);
  180:         }
  181: 
  182:         if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
  183: 	    saved_errno = errno;
  184: 	    close(s);
  185: 	    freeaddrinfo(local_res);
  186: 	    freeaddrinfo(server_res);
  187: 	    errno = saved_errno;
  188:             return -1;
  189: 	}
  190:         freeaddrinfo(local_res);
  191:     }
  192:     /* No local name, but --cport given */
  193:     else if (local_port) {
  194: 	size_t addrlen;
  195: 	struct sockaddr_storage lcl;
  196: 
  197: 	/* IPv4 */
  198: 	if (server_res->ai_family == AF_INET) {
  199: 	    struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl;
  200: 	    lcladdr->sin_family = AF_INET;
  201: 	    lcladdr->sin_port = htons(local_port);
  202: 	    lcladdr->sin_addr.s_addr = INADDR_ANY;
  203: 	    addrlen = sizeof(struct sockaddr_in);
  204: 	}
  205: 	/* IPv6 */
  206: 	else if (server_res->ai_family == AF_INET6) {
  207: 	    struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl;
  208: 	    lcladdr->sin6_family = AF_INET6;
  209: 	    lcladdr->sin6_port = htons(local_port);
  210: 	    lcladdr->sin6_addr = in6addr_any;
  211: 	    addrlen = sizeof(struct sockaddr_in6);
  212: 	}
  213: 	/* Unknown protocol */
  214: 	else {
  215: 	    close(s);
  216: 	    freeaddrinfo(server_res);
  217: 	    errno = EAFNOSUPPORT;
  218:             return -1;
  219: 	}
  220: 
  221:         if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) {
  222: 	    saved_errno = errno;
  223: 	    close(s);
  224: 	    freeaddrinfo(server_res);
  225: 	    errno = saved_errno;
  226:             return -1;
  227:         }
  228:     }
  229: 
  230:     *server_res_out = server_res;
  231:     return s;
  232: }
  233: 
  234: /* make connection to server */
  235: int
  236: netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout)
  237: {
  238:     struct addrinfo *server_res = NULL;
  239:     int s, saved_errno;
  240: 
  241:     s = create_socket(domain, proto, local, bind_dev, local_port, server, port, &server_res);
  242:     if (s < 0) {
  243:       return -1;
  244:     }
  245: 
  246:     if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) {
  247: 	saved_errno = errno;
  248: 	close(s);
  249: 	freeaddrinfo(server_res);
  250: 	errno = saved_errno;
  251:         return -1;
  252:     }
  253: 
  254:     freeaddrinfo(server_res);
  255:     return s;
  256: }
  257: 
  258: /***************************************************************/
  259: 
  260: int
  261: netannounce(int domain, int proto, const char *local, const char *bind_dev, int port)
  262: {
  263:     struct addrinfo hints, *res;
  264:     char portstr[6];
  265:     int s, opt, saved_errno;
  266: 
  267:     snprintf(portstr, 6, "%d", port);
  268:     memset(&hints, 0, sizeof(hints));
  269:     /*
  270:      * If binding to the wildcard address with no explicit address
  271:      * family specified, then force us to get an AF_INET6 socket.  On
  272:      * CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family,
  273:      * and ai_flags containing AI_PASSIVE returns a result structure
  274:      * with ai_family set to AF_INET, with the result that we create
  275:      * and bind an IPv4 address wildcard address and by default, we
  276:      * can't accept IPv6 connections.
  277:      *
  278:      * On FreeBSD, under the above circumstances, ai_family in the
  279:      * result structure is set to AF_INET6.
  280:      */
  281:     if (domain == AF_UNSPEC && !local) {
  282: 	hints.ai_family = AF_INET6;
  283:     }
  284:     else {
  285: 	hints.ai_family = domain;
  286:     }
  287:     hints.ai_socktype = proto;
  288:     hints.ai_flags = AI_PASSIVE;
  289:     if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0)
  290:         return -1;
  291: 
  292:     s = socket(res->ai_family, proto, 0);
  293:     if (s < 0) {
  294: 	freeaddrinfo(res);
  295:         return -1;
  296:     }
  297: 
  298:     if (bind_dev) {
  299: #if defined(HAVE_SO_BINDTODEVICE)
  300:         if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
  301:                        bind_dev, IFNAMSIZ) < 0)
  302: #endif // HAVE_SO_BINDTODEVICE
  303:         {
  304:             saved_errno = errno;
  305:             close(s);
  306:             freeaddrinfo(res);
  307:             errno = saved_errno;
  308:             return -1;
  309:         }
  310:     }
  311: 
  312:     opt = 1;
  313:     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  314: 		   (char *) &opt, sizeof(opt)) < 0) {
  315: 	saved_errno = errno;
  316: 	close(s);
  317: 	freeaddrinfo(res);
  318: 	errno = saved_errno;
  319: 	return -1;
  320:     }
  321:     /*
  322:      * If we got an IPv6 socket, figure out if it should accept IPv4
  323:      * connections as well.  We do that if and only if no address
  324:      * family was specified explicitly.  Note that we can only
  325:      * do this if the IPV6_V6ONLY socket option is supported.  Also,
  326:      * OpenBSD explicitly omits support for IPv4-mapped addresses,
  327:      * even though it implements IPV6_V6ONLY.
  328:      */
  329: #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
  330:     if (res->ai_family == AF_INET6 && (domain == AF_UNSPEC || domain == AF_INET6)) {
  331: 	if (domain == AF_UNSPEC)
  332: 	    opt = 0;
  333: 	else
  334: 	    opt = 1;
  335: 	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
  336: 		       (char *) &opt, sizeof(opt)) < 0) {
  337: 	    saved_errno = errno;
  338: 	    close(s);
  339: 	    freeaddrinfo(res);
  340: 	    errno = saved_errno;
  341: 	    return -1;
  342: 	}
  343:     }
  344: #endif /* IPV6_V6ONLY */
  345: 
  346:     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
  347:         saved_errno = errno;
  348:         close(s);
  349: 	freeaddrinfo(res);
  350:         errno = saved_errno;
  351:         return -1;
  352:     }
  353: 
  354:     freeaddrinfo(res);
  355: 
  356:     if (proto == SOCK_STREAM) {
  357:         if (listen(s, INT_MAX) < 0) {
  358: 	    saved_errno = errno;
  359: 	    close(s);
  360: 	    errno = saved_errno;
  361:             return -1;
  362:         }
  363:     }
  364: 
  365:     return s;
  366: }
  367: 
  368: 
  369: /*******************************************************************/
  370: /* reads 'count' bytes from a socket  */
  371: /********************************************************************/
  372: 
  373: int
  374: Nread(int fd, char *buf, size_t count, int prot)
  375: {
  376:     register ssize_t r;
  377:     register size_t nleft = count;
  378:     struct iperf_time ftimeout = { 0, 0 };
  379: 
  380:     fd_set rfdset;
  381:     struct timeval timeout = { nread_read_timeout, 0 };
  382: 
  383:     /*
  384:      * fd might not be ready for reading on entry. Check for this
  385:      * (with timeout) first.
  386:      *
  387:      * This check could go inside the while() loop below, except we're
  388:      * currently considering whether it might make sense to support a
  389:      * codepath that bypassese this check, for situations where we
  390:      * already know that fd has data on it (for example if we'd gotten
  391:      * to here as the result of a select() call.
  392:      */
  393:     {
  394:         FD_ZERO(&rfdset);
  395:         FD_SET(fd, &rfdset);
  396:         r = select(fd + 1, &rfdset, NULL, NULL, &timeout);
  397:         if (r < 0) {
  398:             return NET_HARDERROR;
  399:         }
  400:         if (r == 0) {
  401:             return 0;
  402:         }
  403:     }
  404: 
  405:     while (nleft > 0) {
  406:         r = read(fd, buf, nleft);
  407:         if (r < 0) {
  408:             if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
  409:                 break;
  410:             else
  411:                 return NET_HARDERROR;
  412:         } else if (r == 0)
  413:             break;
  414: 
  415:         nleft -= r;
  416:         buf += r;
  417: 
  418:         /*
  419:          * We need some more bytes but don't want to wait around
  420:          * forever for them. In the case of partial results, we need
  421:          * to be able to read some bytes every nread_timeout seconds.
  422:          */
  423:         if (nleft > 0) {
  424:             struct iperf_time now;
  425: 
  426:             /*
  427:              * Also, we have an approximate upper limit for the total time
  428:              * that a Nread call is supposed to take. We trade off accuracy
  429:              * of this timeout for a hopefully lower performance impact.
  430:              */
  431:             iperf_time_now(&now);
  432:             if (ftimeout.secs == 0) {
  433:                 ftimeout = now;
  434:                 iperf_time_add_usecs(&ftimeout, nread_overall_timeout * 1000000L);
  435:             }
  436:             if (iperf_time_compare(&ftimeout, &now) < 0) {
  437:                 break;
  438:             }
  439: 
  440:             FD_ZERO(&rfdset);
  441:             FD_SET(fd, &rfdset);
  442:             r = select(fd + 1, &rfdset, NULL, NULL, &timeout);
  443:             if (r < 0) {
  444:                 return NET_HARDERROR;
  445:             }
  446:             if (r == 0) {
  447:                 break;
  448:             }
  449:         }
  450:     }
  451:     return count - nleft;
  452: }
  453: 
  454: 
  455: /*
  456:  *                      N W R I T E
  457:  */
  458: 
  459: int
  460: Nwrite(int fd, const char *buf, size_t count, int prot)
  461: {
  462:     register ssize_t r;
  463:     register size_t nleft = count;
  464: 
  465:     while (nleft > 0) {
  466: 	r = write(fd, buf, nleft);
  467: 	if (r < 0) {
  468: 	    switch (errno) {
  469: 		case EINTR:
  470: 		case EAGAIN:
  471: #if (EAGAIN != EWOULDBLOCK)
  472: 		case EWOULDBLOCK:
  473: #endif
  474: 		return count - nleft;
  475: 
  476: 		case ENOBUFS:
  477: 		return NET_SOFTERROR;
  478: 
  479: 		default:
  480: 		return NET_HARDERROR;
  481: 	    }
  482: 	} else if (r == 0)
  483: 	    return NET_SOFTERROR;
  484: 	nleft -= r;
  485: 	buf += r;
  486:     }
  487:     return count;
  488: }
  489: 
  490: 
  491: int
  492: has_sendfile(void)
  493: {
  494: #if defined(HAVE_SENDFILE)
  495:     return 1;
  496: #else /* HAVE_SENDFILE */
  497:     return 0;
  498: #endif /* HAVE_SENDFILE */
  499: 
  500: }
  501: 
  502: 
  503: /*
  504:  *                      N S E N D F I L E
  505:  */
  506: 
  507: int
  508: Nsendfile(int fromfd, int tofd, const char *buf, size_t count)
  509: {
  510: #if defined(HAVE_SENDFILE)
  511:     off_t offset;
  512: #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6))
  513:     off_t sent;
  514: #endif
  515:     register size_t nleft;
  516:     register ssize_t r;
  517: 
  518:     nleft = count;
  519:     while (nleft > 0) {
  520: 	offset = count - nleft;
  521: #ifdef linux
  522: 	r = sendfile(tofd, fromfd, &offset, nleft);
  523: 	if (r > 0)
  524: 	    nleft -= r;
  525: #elif defined(__FreeBSD__)
  526: 	r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0);
  527: 	nleft -= sent;
  528: #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)	/* OS X */
  529: 	sent = nleft;
  530: 	r = sendfile(fromfd, tofd, offset, &sent, NULL, 0);
  531: 	nleft -= sent;
  532: #else
  533: 	/* Shouldn't happen. */
  534: 	r = -1;
  535: 	errno = ENOSYS;
  536: #endif
  537: 	if (r < 0) {
  538: 	    switch (errno) {
  539: 		case EINTR:
  540: 		case EAGAIN:
  541: #if (EAGAIN != EWOULDBLOCK)
  542: 		case EWOULDBLOCK:
  543: #endif
  544: 		if (count == nleft)
  545: 		    return NET_SOFTERROR;
  546: 		return count - nleft;
  547: 
  548: 		case ENOBUFS:
  549: 		case ENOMEM:
  550: 		return NET_SOFTERROR;
  551: 
  552: 		default:
  553: 		return NET_HARDERROR;
  554: 	    }
  555: 	}
  556: #ifdef linux
  557: 	else if (r == 0)
  558: 	    return NET_SOFTERROR;
  559: #endif
  560:     }
  561:     return count;
  562: #else /* HAVE_SENDFILE */
  563:     errno = ENOSYS;	/* error if somehow get called without HAVE_SENDFILE */
  564:     return NET_HARDERROR;
  565: #endif /* HAVE_SENDFILE */
  566: }
  567: 
  568: /*************************************************************************/
  569: 
  570: int
  571: setnonblocking(int fd, int nonblocking)
  572: {
  573:     int flags, newflags;
  574: 
  575:     flags = fcntl(fd, F_GETFL, 0);
  576:     if (flags < 0) {
  577:         perror("fcntl(F_GETFL)");
  578:         return -1;
  579:     }
  580:     if (nonblocking)
  581: 	newflags = flags | (int) O_NONBLOCK;
  582:     else
  583: 	newflags = flags & ~((int) O_NONBLOCK);
  584:     if (newflags != flags)
  585: 	if (fcntl(fd, F_SETFL, newflags) < 0) {
  586: 	    perror("fcntl(F_SETFL)");
  587: 	    return -1;
  588: 	}
  589:     return 0;
  590: }
  591: 
  592: /****************************************************************************/
  593: 
  594: int
  595: getsockdomain(int sock)
  596: {
  597:     struct sockaddr_storage sa;
  598:     socklen_t len = sizeof(sa);
  599: 
  600:     if (getsockname(sock, (struct sockaddr *)&sa, &len) < 0) {
  601:         return -1;
  602:     }
  603:     return ((struct sockaddr *) &sa)->sa_family;
  604: }

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