File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iperf / src / net.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:36:46 2021 UTC (3 years, 3 months ago) by misho
Branches: iperf, MAIN
CVS tags: v3_3_9, HEAD
iperf 3.3.9

    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 <netinet/tcp.h>
   37: #include <assert.h>
   38: #include <netdb.h>
   39: #include <string.h>
   40: #include <fcntl.h>
   41: #include <limits.h>
   42: 
   43: #ifdef HAVE_SENDFILE
   44: #ifdef linux
   45: #include <sys/sendfile.h>
   46: #else
   47: #ifdef __FreeBSD__
   48: #include <sys/uio.h>
   49: #else
   50: #if defined(__APPLE__) && defined(__MACH__)	/* OS X */
   51: #include <AvailabilityMacros.h>
   52: #if defined(MAC_OS_X_VERSION_10_6)
   53: #include <sys/uio.h>
   54: #endif
   55: #endif
   56: #endif
   57: #endif
   58: #endif /* HAVE_SENDFILE */
   59: 
   60: #ifdef HAVE_POLL_H
   61: #include <poll.h>
   62: #endif /* HAVE_POLL_H */
   63: 
   64: #include "iperf_util.h"
   65: #include "net.h"
   66: #include "timer.h"
   67: 
   68: /*
   69:  * Declaration of gerror in iperf_error.c.  Most other files in iperf3 can get this
   70:  * by including "iperf.h", but net.c lives "below" this layer.  Clearly the
   71:  * presence of this declaration is a sign we need to revisit this layering.
   72:  */
   73: extern int gerror;
   74: 
   75: /*
   76:  * timeout_connect adapted from netcat, via OpenBSD and FreeBSD
   77:  * Copyright (c) 2001 Eric Jackson <ericj@monkey.org>
   78:  */
   79: int
   80: timeout_connect(int s, const struct sockaddr *name, socklen_t namelen,
   81:     int timeout)
   82: {
   83: 	struct pollfd pfd;
   84: 	socklen_t optlen;
   85: 	int flags, optval;
   86: 	int ret;
   87: 
   88: 	flags = 0;
   89: 	if (timeout != -1) {
   90: 		flags = fcntl(s, F_GETFL, 0);
   91: 		if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
   92: 			return -1;
   93: 	}
   94: 
   95: 	if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
   96: 		pfd.fd = s;
   97: 		pfd.events = POLLOUT;
   98: 		if ((ret = poll(&pfd, 1, timeout)) == 1) {
   99: 			optlen = sizeof(optval);
  100: 			if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
  101: 			    &optval, &optlen)) == 0) {
  102: 				errno = optval;
  103: 				ret = optval == 0 ? 0 : -1;
  104: 			}
  105: 		} else if (ret == 0) {
  106: 			errno = ETIMEDOUT;
  107: 			ret = -1;
  108: 		} else
  109: 			ret = -1;
  110: 	}
  111: 
  112: 	if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
  113: 		ret = -1;
  114: 
  115: 	return (ret);
  116: }
  117: 
  118: /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/
  119:  * Copyright: http://swtch.com/libtask/COPYRIGHT
  120: */
  121: 
  122: /* make connection to server */
  123: int
  124: netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout)
  125: {
  126:     struct addrinfo hints, *local_res, *server_res;
  127:     int s, saved_errno;
  128: 
  129:     if (local) {
  130:         memset(&hints, 0, sizeof(hints));
  131:         hints.ai_family = domain;
  132:         hints.ai_socktype = proto;
  133:         if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0)
  134:             return -1;
  135:     }
  136: 
  137:     memset(&hints, 0, sizeof(hints));
  138:     hints.ai_family = domain;
  139:     hints.ai_socktype = proto;
  140:     if ((gerror = getaddrinfo(server, NULL, &hints, &server_res)) != 0)
  141:         return -1;
  142: 
  143:     s = socket(server_res->ai_family, proto, 0);
  144:     if (s < 0) {
  145: 	if (local)
  146: 	    freeaddrinfo(local_res);
  147: 	freeaddrinfo(server_res);
  148:         return -1;
  149:     }
  150: 
  151:     /* Bind the local address if given a name (with or without --cport) */
  152:     if (local) {
  153:         if (local_port) {
  154:             struct sockaddr_in *lcladdr;
  155:             lcladdr = (struct sockaddr_in *)local_res->ai_addr;
  156:             lcladdr->sin_port = htons(local_port);
  157:         }
  158: 
  159:         if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
  160: 	    saved_errno = errno;
  161: 	    close(s);
  162: 	    freeaddrinfo(local_res);
  163: 	    freeaddrinfo(server_res);
  164: 	    errno = saved_errno;
  165:             return -1;
  166: 	}
  167:         freeaddrinfo(local_res);
  168:     }
  169:     /* No local name, but --cport given */
  170:     else if (local_port) {
  171: 	size_t addrlen;
  172: 	struct sockaddr_storage lcl;
  173: 
  174: 	/* IPv4 */
  175: 	if (server_res->ai_family == AF_INET) {
  176: 	    struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl;
  177: 	    lcladdr->sin_family = AF_INET;
  178: 	    lcladdr->sin_port = htons(local_port);
  179: 	    lcladdr->sin_addr.s_addr = INADDR_ANY;
  180: 	    addrlen = sizeof(struct sockaddr_in);
  181: 	}
  182: 	/* IPv6 */
  183: 	else if (server_res->ai_family == AF_INET6) {
  184: 	    struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl;
  185: 	    lcladdr->sin6_family = AF_INET6;
  186: 	    lcladdr->sin6_port = htons(local_port);
  187: 	    lcladdr->sin6_addr = in6addr_any;
  188: 	    addrlen = sizeof(struct sockaddr_in6);
  189: 	}
  190: 	/* Unknown protocol */
  191: 	else {
  192: 	    errno = EAFNOSUPPORT;
  193:             return -1;
  194: 	}
  195: 
  196:         if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) {
  197: 	    saved_errno = errno;
  198: 	    close(s);
  199: 	    freeaddrinfo(server_res);
  200: 	    errno = saved_errno;
  201:             return -1;
  202:         }
  203:     }
  204: 
  205:     ((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port);
  206:     if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) {
  207: 	saved_errno = errno;
  208: 	close(s);
  209: 	freeaddrinfo(server_res);
  210: 	errno = saved_errno;
  211:         return -1;
  212:     }
  213: 
  214:     freeaddrinfo(server_res);
  215:     return s;
  216: }
  217: 
  218: /***************************************************************/
  219: 
  220: int
  221: netannounce(int domain, int proto, const char *local, int port)
  222: {
  223:     struct addrinfo hints, *res;
  224:     char portstr[6];
  225:     int s, opt, saved_errno;
  226: 
  227:     snprintf(portstr, 6, "%d", port);
  228:     memset(&hints, 0, sizeof(hints));
  229:     /* 
  230:      * If binding to the wildcard address with no explicit address
  231:      * family specified, then force us to get an AF_INET6 socket.  On
  232:      * CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family,
  233:      * and ai_flags containing AI_PASSIVE returns a result structure
  234:      * with ai_family set to AF_INET, with the result that we create
  235:      * and bind an IPv4 address wildcard address and by default, we
  236:      * can't accept IPv6 connections.
  237:      *
  238:      * On FreeBSD, under the above circumstances, ai_family in the
  239:      * result structure is set to AF_INET6.
  240:      */
  241:     if (domain == AF_UNSPEC && !local) {
  242: 	hints.ai_family = AF_INET6;
  243:     }
  244:     else {
  245: 	hints.ai_family = domain;
  246:     }
  247:     hints.ai_socktype = proto;
  248:     hints.ai_flags = AI_PASSIVE;
  249:     if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0)
  250:         return -1; 
  251: 
  252:     s = socket(res->ai_family, proto, 0);
  253:     if (s < 0) {
  254: 	freeaddrinfo(res);
  255:         return -1;
  256:     }
  257: 
  258:     opt = 1;
  259:     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 
  260: 		   (char *) &opt, sizeof(opt)) < 0) {
  261: 	saved_errno = errno;
  262: 	close(s);
  263: 	freeaddrinfo(res);
  264: 	errno = saved_errno;
  265: 	return -1;
  266:     }
  267:     /*
  268:      * If we got an IPv6 socket, figure out if it should accept IPv4
  269:      * connections as well.  We do that if and only if no address
  270:      * family was specified explicitly.  Note that we can only
  271:      * do this if the IPV6_V6ONLY socket option is supported.  Also,
  272:      * OpenBSD explicitly omits support for IPv4-mapped addresses,
  273:      * even though it implements IPV6_V6ONLY.
  274:      */
  275: #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
  276:     if (res->ai_family == AF_INET6 && (domain == AF_UNSPEC || domain == AF_INET6)) {
  277: 	if (domain == AF_UNSPEC)
  278: 	    opt = 0;
  279: 	else
  280: 	    opt = 1;
  281: 	if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 
  282: 		       (char *) &opt, sizeof(opt)) < 0) {
  283: 	    saved_errno = errno;
  284: 	    close(s);
  285: 	    freeaddrinfo(res);
  286: 	    errno = saved_errno;
  287: 	    return -1;
  288: 	}
  289:     }
  290: #endif /* IPV6_V6ONLY */
  291: 
  292:     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
  293:         saved_errno = errno;
  294:         close(s);
  295: 	freeaddrinfo(res);
  296:         errno = saved_errno;
  297:         return -1;
  298:     }
  299: 
  300:     freeaddrinfo(res);
  301:     
  302:     if (proto == SOCK_STREAM) {
  303:         if (listen(s, INT_MAX) < 0) {
  304: 	    saved_errno = errno;
  305: 	    close(s);
  306: 	    errno = saved_errno;
  307:             return -1;
  308:         }
  309:     }
  310: 
  311:     return s;
  312: }
  313: 
  314: 
  315: /*******************************************************************/
  316: /* reads 'count' bytes from a socket  */
  317: /********************************************************************/
  318: 
  319: int
  320: Nread(int fd, char *buf, size_t count, int prot)
  321: {
  322:     register ssize_t r;
  323:     register size_t nleft = count;
  324: 
  325:     while (nleft > 0) {
  326:         r = read(fd, buf, nleft);
  327:         if (r < 0) {
  328:             if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
  329:                 break;
  330:             else
  331:                 return NET_HARDERROR;
  332:         } else if (r == 0)
  333:             break;
  334: 
  335:         nleft -= r;
  336:         buf += r;
  337:     }
  338:     return count - nleft;
  339: }
  340: 
  341: 
  342: /*
  343:  *                      N W R I T E
  344:  */
  345: 
  346: int
  347: Nwrite(int fd, const char *buf, size_t count, int prot)
  348: {
  349:     register ssize_t r;
  350:     register size_t nleft = count;
  351: 
  352:     while (nleft > 0) {
  353: 	r = write(fd, buf, nleft);
  354: 	if (r < 0) {
  355: 	    switch (errno) {
  356: 		case EINTR:
  357: 		case EAGAIN:
  358: #if (EAGAIN != EWOULDBLOCK)
  359: 		case EWOULDBLOCK:
  360: #endif
  361: 		return count - nleft;
  362: 
  363: 		case ENOBUFS:
  364: 		return NET_SOFTERROR;
  365: 
  366: 		default:
  367: 		return NET_HARDERROR;
  368: 	    }
  369: 	} else if (r == 0)
  370: 	    return NET_SOFTERROR;
  371: 	nleft -= r;
  372: 	buf += r;
  373:     }
  374:     return count;
  375: }
  376: 
  377: 
  378: int
  379: has_sendfile(void)
  380: {
  381: #if defined(HAVE_SENDFILE)
  382:     return 1;
  383: #else /* HAVE_SENDFILE */
  384:     return 0;
  385: #endif /* HAVE_SENDFILE */
  386: 
  387: }
  388: 
  389: 
  390: /*
  391:  *                      N S E N D F I L E
  392:  */
  393: 
  394: int
  395: Nsendfile(int fromfd, int tofd, const char *buf, size_t count)
  396: {
  397:     off_t offset;
  398: #if defined(HAVE_SENDFILE)
  399: #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6))
  400:     off_t sent;
  401: #endif
  402:     register size_t nleft;
  403:     register ssize_t r;
  404: 
  405:     nleft = count;
  406:     while (nleft > 0) {
  407: 	offset = count - nleft;
  408: #ifdef linux
  409: 	r = sendfile(tofd, fromfd, &offset, nleft);
  410: 	if (r > 0)
  411: 	    nleft -= r;
  412: #elif defined(__FreeBSD__)
  413: 	r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0);
  414: 	nleft -= sent;
  415: #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6)	/* OS X */
  416: 	sent = nleft;
  417: 	r = sendfile(fromfd, tofd, offset, &sent, NULL, 0);
  418: 	nleft -= sent;
  419: #else
  420: 	/* Shouldn't happen. */
  421: 	r = -1;
  422: 	errno = ENOSYS;
  423: #endif
  424: 	if (r < 0) {
  425: 	    switch (errno) {
  426: 		case EINTR:
  427: 		case EAGAIN:
  428: #if (EAGAIN != EWOULDBLOCK)
  429: 		case EWOULDBLOCK:
  430: #endif
  431: 		if (count == nleft)
  432: 		    return NET_SOFTERROR;
  433: 		return count - nleft;
  434: 
  435: 		case ENOBUFS:
  436: 		case ENOMEM:
  437: 		return NET_SOFTERROR;
  438: 
  439: 		default:
  440: 		return NET_HARDERROR;
  441: 	    }
  442: 	}
  443: #ifdef linux
  444: 	else if (r == 0)
  445: 	    return NET_SOFTERROR;
  446: #endif
  447:     }
  448:     return count;
  449: #else /* HAVE_SENDFILE */
  450:     errno = ENOSYS;	/* error if somehow get called without HAVE_SENDFILE */
  451:     return NET_HARDERROR;
  452: #endif /* HAVE_SENDFILE */
  453: }
  454: 
  455: /*************************************************************************/
  456: 
  457: int
  458: setnonblocking(int fd, int nonblocking)
  459: {
  460:     int flags, newflags;
  461: 
  462:     flags = fcntl(fd, F_GETFL, 0);
  463:     if (flags < 0) {
  464:         perror("fcntl(F_GETFL)");
  465:         return -1;
  466:     }
  467:     if (nonblocking)
  468: 	newflags = flags | (int) O_NONBLOCK;
  469:     else
  470: 	newflags = flags & ~((int) O_NONBLOCK);
  471:     if (newflags != flags)
  472: 	if (fcntl(fd, F_SETFL, newflags) < 0) {
  473: 	    perror("fcntl(F_SETFL)");
  474: 	    return -1;
  475: 	}
  476:     return 0;
  477: }
  478: 
  479: /****************************************************************************/
  480: 
  481: int
  482: getsockdomain(int sock)
  483: {
  484:     struct sockaddr_storage sa;
  485:     socklen_t len = sizeof(sa);
  486: 
  487:     if (getsockname(sock, (struct sockaddr *)&sa, &len) < 0) {
  488:         return -1;
  489:     }
  490:     return ((struct sockaddr *) &sa)->sa_family;
  491: }

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