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

1.1       misho       1: /*
1.1.1.2 ! misho       2:  * iperf, Copyright (c) 2014-2019, The Regents of the University of
1.1       misho       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>
1.1.1.2 ! misho      32: #include <arpa/inet.h>
1.1       misho      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>
1.1.1.2 ! misho      40: #include <fcntl.h>
        !            41: #include <limits.h>
1.1       misho      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: 
1.1.1.2 ! misho      60: #ifdef HAVE_POLL_H
        !            61: #include <poll.h>
        !            62: #endif /* HAVE_POLL_H */
        !            63: 
1.1       misho      64: #include "iperf_util.h"
                     65: #include "net.h"
                     66: #include "timer.h"
                     67: 
1.1.1.2 ! misho      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: 
1.1       misho     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
1.1.1.2 ! misho     124: netdial(int domain, int proto, const char *local, int local_port, const char *server, int port, int timeout)
1.1       misho     125: {
                    126:     struct addrinfo hints, *local_res, *server_res;
1.1.1.2 ! misho     127:     int s, saved_errno;
1.1       misho     128: 
                    129:     if (local) {
                    130:         memset(&hints, 0, sizeof(hints));
                    131:         hints.ai_family = domain;
                    132:         hints.ai_socktype = proto;
1.1.1.2 ! misho     133:         if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0)
1.1       misho     134:             return -1;
                    135:     }
                    136: 
                    137:     memset(&hints, 0, sizeof(hints));
                    138:     hints.ai_family = domain;
                    139:     hints.ai_socktype = proto;
1.1.1.2 ! misho     140:     if ((gerror = getaddrinfo(server, NULL, &hints, &server_res)) != 0)
1.1       misho     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: 
1.1.1.2 ! misho     151:     /* Bind the local address if given a name (with or without --cport) */
1.1       misho     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) {
1.1.1.2 ! misho     160:            saved_errno = errno;
1.1       misho     161:            close(s);
                    162:            freeaddrinfo(local_res);
                    163:            freeaddrinfo(server_res);
1.1.1.2 ! misho     164:            errno = saved_errno;
1.1       misho     165:             return -1;
                    166:        }
                    167:         freeaddrinfo(local_res);
                    168:     }
1.1.1.2 ! misho     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:     }
1.1       misho     204: 
                    205:     ((struct sockaddr_in *) server_res->ai_addr)->sin_port = htons(port);
1.1.1.2 ! misho     206:     if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) {
        !           207:        saved_errno = errno;
1.1       misho     208:        close(s);
                    209:        freeaddrinfo(server_res);
1.1.1.2 ! misho     210:        errno = saved_errno;
1.1       misho     211:         return -1;
                    212:     }
                    213: 
                    214:     freeaddrinfo(server_res);
                    215:     return s;
                    216: }
                    217: 
                    218: /***************************************************************/
                    219: 
                    220: int
1.1.1.2 ! misho     221: netannounce(int domain, int proto, const char *local, int port)
1.1       misho     222: {
                    223:     struct addrinfo hints, *res;
                    224:     char portstr[6];
1.1.1.2 ! misho     225:     int s, opt, saved_errno;
1.1       misho     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;
1.1.1.2 ! misho     249:     if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0)
1.1       misho     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) {
1.1.1.2 ! misho     261:        saved_errno = errno;
1.1       misho     262:        close(s);
                    263:        freeaddrinfo(res);
1.1.1.2 ! misho     264:        errno = saved_errno;
1.1       misho     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) {
1.1.1.2 ! misho     283:            saved_errno = errno;
1.1       misho     284:            close(s);
                    285:            freeaddrinfo(res);
1.1.1.2 ! misho     286:            errno = saved_errno;
1.1       misho     287:            return -1;
                    288:        }
                    289:     }
                    290: #endif /* IPV6_V6ONLY */
                    291: 
                    292:     if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
1.1.1.2 ! misho     293:         saved_errno = errno;
1.1       misho     294:         close(s);
                    295:        freeaddrinfo(res);
1.1.1.2 ! misho     296:         errno = saved_errno;
1.1       misho     297:         return -1;
                    298:     }
                    299: 
                    300:     freeaddrinfo(res);
                    301:     
                    302:     if (proto == SOCK_STREAM) {
1.1.1.2 ! misho     303:         if (listen(s, INT_MAX) < 0) {
        !           304:            saved_errno = errno;
1.1       misho     305:            close(s);
1.1.1.2 ! misho     306:            errno = saved_errno;
1.1       misho     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>