Annotation of embedaddon/iperf/src/net.c, revision 1.1

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

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