Annotation of embedaddon/iperf/src/net.c, revision 1.1.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>