Annotation of embedaddon/iperf/src/iperf_tcp.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 <stdio.h>
                     28: #include <stdlib.h>
                     29: #include <string.h>
                     30: #include <errno.h>
                     31: #include <unistd.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 <netdb.h>
                     37: #include <sys/time.h>
                     38: #include <sys/select.h>
1.1.1.2 ! misho      39: #include <limits.h>
1.1       misho      40: 
                     41: #include "iperf.h"
                     42: #include "iperf_api.h"
                     43: #include "iperf_tcp.h"
                     44: #include "net.h"
1.1.1.2 ! misho      45: #include "cjson.h"
1.1       misho      46: 
                     47: #if defined(HAVE_FLOWLABEL)
                     48: #include "flowlabel.h"
                     49: #endif /* HAVE_FLOWLABEL */
                     50: 
                     51: /* iperf_tcp_recv
                     52:  *
                     53:  * receives the data for TCP
                     54:  */
                     55: int
                     56: iperf_tcp_recv(struct iperf_stream *sp)
                     57: {
                     58:     int r;
                     59: 
                     60:     r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);
                     61: 
                     62:     if (r < 0)
                     63:         return r;
                     64: 
1.1.1.2 ! misho      65:     /* Only count bytes received while we're in the correct state. */
        !            66:     if (sp->test->state == TEST_RUNNING) {
        !            67:        sp->result->bytes_received += r;
        !            68:        sp->result->bytes_received_this_interval += r;
        !            69:     }
        !            70:     else {
        !            71:        if (sp->test->debug)
        !            72:            printf("Late receive, state = %d\n", sp->test->state);
        !            73:     }
1.1       misho      74: 
                     75:     return r;
                     76: }
                     77: 
                     78: 
                     79: /* iperf_tcp_send 
                     80:  *
                     81:  * sends the data for TCP
                     82:  */
                     83: int
                     84: iperf_tcp_send(struct iperf_stream *sp)
                     85: {
                     86:     int r;
                     87: 
                     88:     if (sp->test->zerocopy)
                     89:        r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->settings->blksize);
                     90:     else
                     91:        r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);
                     92: 
                     93:     if (r < 0)
                     94:         return r;
                     95: 
                     96:     sp->result->bytes_sent += r;
                     97:     sp->result->bytes_sent_this_interval += r;
                     98: 
1.1.1.2 ! misho      99:     if (sp->test->debug)
        !           100:        printf("sent %d bytes of %d, total %" PRIu64 "\n", r, sp->settings->blksize, sp->result->bytes_sent);
        !           101: 
1.1       misho     102:     return r;
                    103: }
                    104: 
                    105: 
                    106: /* iperf_tcp_accept
                    107:  *
                    108:  * accept a new TCP stream connection
                    109:  */
                    110: int
                    111: iperf_tcp_accept(struct iperf_test * test)
                    112: {
                    113:     int     s;
                    114:     signed char rbuf = ACCESS_DENIED;
                    115:     char    cookie[COOKIE_SIZE];
                    116:     socklen_t len;
                    117:     struct sockaddr_storage addr;
                    118: 
                    119:     len = sizeof(addr);
                    120:     if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
                    121:         i_errno = IESTREAMCONNECT;
                    122:         return -1;
                    123:     }
                    124: 
                    125:     if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
                    126:         i_errno = IERECVCOOKIE;
                    127:         return -1;
                    128:     }
                    129: 
                    130:     if (strcmp(test->cookie, cookie) != 0) {
                    131:         if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
                    132:             i_errno = IESENDMESSAGE;
                    133:             return -1;
                    134:         }
                    135:         close(s);
                    136:     }
                    137: 
                    138:     return s;
                    139: }
                    140: 
                    141: 
                    142: /* iperf_tcp_listen
                    143:  *
                    144:  * start up a listener for TCP stream connections
                    145:  */
                    146: int
                    147: iperf_tcp_listen(struct iperf_test *test)
                    148: {
                    149:     int s, opt;
1.1.1.2 ! misho     150:     socklen_t optlen;
1.1       misho     151:     int saved_errno;
1.1.1.2 ! misho     152:     int rcvbuf_actual, sndbuf_actual;
1.1       misho     153: 
                    154:     s = test->listener;
                    155: 
                    156:     /*
                    157:      * If certain parameters are specified (such as socket buffer
                    158:      * size), then throw away the listening socket (the one for which
                    159:      * we just accepted the control connection) and recreate it with
                    160:      * those parameters.  That way, when new data connections are
                    161:      * set, they'll have all the correct parameters in place.
                    162:      *
                    163:      * It's not clear whether this is a requirement or a convenience.
                    164:      */
                    165:     if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
1.1.1.2 ! misho     166:        struct addrinfo hints, *res;
        !           167:        char portstr[6];
        !           168: 
1.1       misho     169:         FD_CLR(s, &test->read_set);
                    170:         close(s);
                    171: 
                    172:         snprintf(portstr, 6, "%d", test->server_port);
                    173:         memset(&hints, 0, sizeof(hints));
                    174: 
                    175:        /*
                    176:         * If binding to the wildcard address with no explicit address
                    177:         * family specified, then force us to get an AF_INET6 socket.
                    178:         * More details in the comments in netanounce().
                    179:         */
                    180:        if (test->settings->domain == AF_UNSPEC && !test->bind_address) {
                    181:            hints.ai_family = AF_INET6;
                    182:        }
                    183:        else {
                    184:            hints.ai_family = test->settings->domain;
                    185:        }
                    186:         hints.ai_socktype = SOCK_STREAM;
                    187:         hints.ai_flags = AI_PASSIVE;
1.1.1.2 ! misho     188:         if ((gerror = getaddrinfo(test->bind_address, portstr, &hints, &res)) != 0) {
1.1       misho     189:             i_errno = IESTREAMLISTEN;
                    190:             return -1;
                    191:         }
                    192: 
                    193:         if ((s = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
                    194:            freeaddrinfo(res);
                    195:             i_errno = IESTREAMLISTEN;
                    196:             return -1;
                    197:         }
                    198: 
                    199:         if (test->no_delay) {
                    200:             opt = 1;
                    201:             if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
                    202:                saved_errno = errno;
                    203:                close(s);
                    204:                freeaddrinfo(res);
                    205:                errno = saved_errno;
                    206:                 i_errno = IESETNODELAY;
                    207:                 return -1;
                    208:             }
                    209:         }
                    210:         // XXX: Setting MSS is very buggy!
                    211:         if ((opt = test->settings->mss)) {
                    212:             if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
                    213:                saved_errno = errno;
                    214:                close(s);
                    215:                freeaddrinfo(res);
                    216:                errno = saved_errno;
                    217:                 i_errno = IESETMSS;
                    218:                 return -1;
                    219:             }
                    220:         }
                    221:         if ((opt = test->settings->socket_bufsize)) {
                    222:             if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
                    223:                saved_errno = errno;
                    224:                close(s);
                    225:                freeaddrinfo(res);
                    226:                errno = saved_errno;
                    227:                 i_errno = IESETBUF;
                    228:                 return -1;
                    229:             }
                    230:             if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
                    231:                saved_errno = errno;
                    232:                close(s);
                    233:                freeaddrinfo(res);
                    234:                errno = saved_errno;
                    235:                 i_errno = IESETBUF;
                    236:                 return -1;
                    237:             }
                    238:         }
                    239: #if defined(HAVE_SO_MAX_PACING_RATE)
1.1.1.2 ! misho     240:     /* If fq socket pacing is specified, enable it. */
        !           241:     if (test->settings->fqrate) {
1.1       misho     242:        /* Convert bits per second to bytes per second */
1.1.1.2 ! misho     243:        unsigned int fqrate = test->settings->fqrate / 8;
        !           244:        if (fqrate > 0) {
1.1       misho     245:            if (test->debug) {
1.1.1.2 ! misho     246:                printf("Setting fair-queue socket pacing to %u\n", fqrate);
1.1       misho     247:            }
1.1.1.2 ! misho     248:            if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
        !           249:                warning("Unable to set socket pacing");
1.1       misho     250:            }
                    251:        }
                    252:     }
                    253: #endif /* HAVE_SO_MAX_PACING_RATE */
1.1.1.2 ! misho     254:     {
        !           255:        unsigned int rate = test->settings->rate / 8;
        !           256:        if (rate > 0) {
        !           257:            if (test->debug) {
        !           258:                printf("Setting application pacing to %u\n", rate);
        !           259:            }
        !           260:        }
        !           261:     }
1.1       misho     262:         opt = 1;
                    263:         if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
                    264:            saved_errno = errno;
                    265:             close(s);
                    266:            freeaddrinfo(res);
                    267:            errno = saved_errno;
                    268:             i_errno = IEREUSEADDR;
                    269:             return -1;
                    270:         }
                    271: 
                    272:        /*
                    273:         * If we got an IPv6 socket, figure out if it shoudl accept IPv4
                    274:         * connections as well.  See documentation in netannounce() for
                    275:         * more details.
                    276:         */
                    277: #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
                    278:        if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET)) {
                    279:            if (test->settings->domain == AF_UNSPEC)
                    280:                opt = 0;
                    281:            else 
                    282:                opt = 1;
                    283:            if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 
                    284:                           (char *) &opt, sizeof(opt)) < 0) {
                    285:                saved_errno = errno;
                    286:                close(s);
                    287:                freeaddrinfo(res);
                    288:                errno = saved_errno;
                    289:                i_errno = IEV6ONLY;
                    290:                return -1;
                    291:            }
                    292:        }
                    293: #endif /* IPV6_V6ONLY */
                    294: 
                    295:         if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
                    296:            saved_errno = errno;
                    297:             close(s);
                    298:            freeaddrinfo(res);
                    299:            errno = saved_errno;
                    300:             i_errno = IESTREAMLISTEN;
                    301:             return -1;
                    302:         }
                    303: 
                    304:         freeaddrinfo(res);
                    305: 
1.1.1.2 ! misho     306:         if (listen(s, INT_MAX) < 0) {
1.1       misho     307:             i_errno = IESTREAMLISTEN;
                    308:             return -1;
                    309:         }
                    310: 
                    311:         test->listener = s;
                    312:     }
                    313:     
1.1.1.2 ! misho     314:     /* Read back and verify the sender socket buffer size */
        !           315:     optlen = sizeof(sndbuf_actual);
        !           316:     if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) {
        !           317:        saved_errno = errno;
        !           318:        close(s);
        !           319:        errno = saved_errno;
        !           320:        i_errno = IESETBUF;
        !           321:        return -1;
        !           322:     }
        !           323:     if (test->debug) {
        !           324:        printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize);
        !           325:     }
        !           326:     if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) {
        !           327:        i_errno = IESETBUF2;
        !           328:        return -1;
        !           329:     }
        !           330: 
        !           331:     /* Read back and verify the receiver socket buffer size */
        !           332:     optlen = sizeof(rcvbuf_actual);
        !           333:     if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) {
        !           334:        saved_errno = errno;
        !           335:        close(s);
        !           336:        errno = saved_errno;
        !           337:        i_errno = IESETBUF;
        !           338:        return -1;
        !           339:     }
        !           340:     if (test->debug) {
        !           341:        printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize);
        !           342:     }
        !           343:     if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) {
        !           344:        i_errno = IESETBUF2;
        !           345:        return -1;
        !           346:     }
        !           347: 
        !           348:     if (test->json_output) {
        !           349:        cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize);
        !           350:        cJSON_AddNumberToObject(test->json_start, "sndbuf_actual", sndbuf_actual);
        !           351:        cJSON_AddNumberToObject(test->json_start, "rcvbuf_actual", rcvbuf_actual);
        !           352:     }
        !           353: 
1.1       misho     354:     return s;
                    355: }
                    356: 
                    357: 
                    358: /* iperf_tcp_connect
                    359:  *
                    360:  * connect to a TCP stream listener
1.1.1.2 ! misho     361:  * This function is roughly similar to netdial(), and may indeed have
        !           362:  * been derived from it at some point, but it sets many TCP-specific
        !           363:  * options between socket creation and connection.
1.1       misho     364:  */
                    365: int
                    366: iperf_tcp_connect(struct iperf_test *test)
                    367: {
                    368:     struct addrinfo hints, *local_res, *server_res;
                    369:     char portstr[6];
                    370:     int s, opt;
1.1.1.2 ! misho     371:     socklen_t optlen;
1.1       misho     372:     int saved_errno;
1.1.1.2 ! misho     373:     int rcvbuf_actual, sndbuf_actual;
1.1       misho     374: 
                    375:     if (test->bind_address) {
                    376:         memset(&hints, 0, sizeof(hints));
                    377:         hints.ai_family = test->settings->domain;
                    378:         hints.ai_socktype = SOCK_STREAM;
1.1.1.2 ! misho     379:         if ((gerror = getaddrinfo(test->bind_address, NULL, &hints, &local_res)) != 0) {
1.1       misho     380:             i_errno = IESTREAMCONNECT;
                    381:             return -1;
                    382:         }
                    383:     }
                    384: 
                    385:     memset(&hints, 0, sizeof(hints));
                    386:     hints.ai_family = test->settings->domain;
                    387:     hints.ai_socktype = SOCK_STREAM;
                    388:     snprintf(portstr, sizeof(portstr), "%d", test->server_port);
1.1.1.2 ! misho     389:     if ((gerror = getaddrinfo(test->server_hostname, portstr, &hints, &server_res)) != 0) {
1.1       misho     390:        if (test->bind_address)
                    391:            freeaddrinfo(local_res);
                    392:         i_errno = IESTREAMCONNECT;
                    393:         return -1;
                    394:     }
                    395: 
                    396:     if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) {
                    397:        if (test->bind_address)
                    398:            freeaddrinfo(local_res);
                    399:        freeaddrinfo(server_res);
                    400:         i_errno = IESTREAMCONNECT;
                    401:         return -1;
                    402:     }
                    403: 
1.1.1.2 ! misho     404:     /*
        !           405:      * Various ways to bind the local end of the connection.
        !           406:      * 1.  --bind (with or without --cport).
        !           407:      */
1.1       misho     408:     if (test->bind_address) {
                    409:         struct sockaddr_in *lcladdr;
                    410:         lcladdr = (struct sockaddr_in *)local_res->ai_addr;
                    411:         lcladdr->sin_port = htons(test->bind_port);
                    412: 
                    413:         if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
                    414:            saved_errno = errno;
                    415:            close(s);
                    416:            freeaddrinfo(local_res);
                    417:            freeaddrinfo(server_res);
                    418:            errno = saved_errno;
                    419:             i_errno = IESTREAMCONNECT;
                    420:             return -1;
                    421:         }
                    422:         freeaddrinfo(local_res);
                    423:     }
1.1.1.2 ! misho     424:     /* --cport, no --bind */
        !           425:     else if (test->bind_port) {
        !           426:        size_t addrlen;
        !           427:        struct sockaddr_storage lcl;
        !           428: 
        !           429:        /* IPv4 */
        !           430:        if (server_res->ai_family == AF_INET) {
        !           431:            struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl;
        !           432:            lcladdr->sin_family = AF_INET;
        !           433:            lcladdr->sin_port = htons(test->bind_port);
        !           434:            lcladdr->sin_addr.s_addr = INADDR_ANY;
        !           435:            addrlen = sizeof(struct sockaddr_in);
        !           436:        }
        !           437:        /* IPv6 */
        !           438:        else if (server_res->ai_family == AF_INET6) {
        !           439:            struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl;
        !           440:            lcladdr->sin6_family = AF_INET6;
        !           441:            lcladdr->sin6_port = htons(test->bind_port);
        !           442:            lcladdr->sin6_addr = in6addr_any;
        !           443:            addrlen = sizeof(struct sockaddr_in6);
        !           444:        }
        !           445:        /* Unknown protocol */
        !           446:        else {
        !           447:            saved_errno = errno;
        !           448:            close(s);
        !           449:            freeaddrinfo(server_res);
        !           450:            errno = saved_errno;
        !           451:             i_errno = IEPROTOCOL;
        !           452:             return -1;
        !           453:        }
        !           454: 
        !           455:         if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) {
        !           456:            saved_errno = errno;
        !           457:            close(s);
        !           458:            freeaddrinfo(server_res);
        !           459:            errno = saved_errno;
        !           460:             i_errno = IESTREAMCONNECT;
        !           461:             return -1;
        !           462:         }
        !           463:     }
1.1       misho     464: 
                    465:     /* Set socket options */
                    466:     if (test->no_delay) {
                    467:         opt = 1;
                    468:         if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
                    469:            saved_errno = errno;
                    470:            close(s);
                    471:            freeaddrinfo(server_res);
                    472:            errno = saved_errno;
                    473:             i_errno = IESETNODELAY;
                    474:             return -1;
                    475:         }
                    476:     }
                    477:     if ((opt = test->settings->mss)) {
                    478:         if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
                    479:            saved_errno = errno;
                    480:            close(s);
                    481:            freeaddrinfo(server_res);
                    482:            errno = saved_errno;
                    483:             i_errno = IESETMSS;
                    484:             return -1;
                    485:         }
                    486:     }
                    487:     if ((opt = test->settings->socket_bufsize)) {
                    488:         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
                    489:            saved_errno = errno;
                    490:            close(s);
                    491:            freeaddrinfo(server_res);
                    492:            errno = saved_errno;
                    493:             i_errno = IESETBUF;
                    494:             return -1;
                    495:         }
                    496:         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
                    497:            saved_errno = errno;
                    498:            close(s);
                    499:            freeaddrinfo(server_res);
                    500:            errno = saved_errno;
                    501:             i_errno = IESETBUF;
                    502:             return -1;
                    503:         }
                    504:     }
1.1.1.2 ! misho     505: 
        !           506:     /* Read back and verify the sender socket buffer size */
        !           507:     optlen = sizeof(sndbuf_actual);
        !           508:     if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) {
        !           509:        saved_errno = errno;
        !           510:        close(s);
        !           511:        freeaddrinfo(server_res);
        !           512:        errno = saved_errno;
        !           513:        i_errno = IESETBUF;
        !           514:        return -1;
        !           515:     }
1.1       misho     516:     if (test->debug) {
1.1.1.2 ! misho     517:        printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize);
        !           518:     }
        !           519:     if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) {
        !           520:        i_errno = IESETBUF2;
        !           521:        return -1;
1.1       misho     522:     }
1.1.1.2 ! misho     523: 
        !           524:     /* Read back and verify the receiver socket buffer size */
        !           525:     optlen = sizeof(rcvbuf_actual);
        !           526:     if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) {
        !           527:        saved_errno = errno;
        !           528:        close(s);
        !           529:        freeaddrinfo(server_res);
        !           530:        errno = saved_errno;
        !           531:        i_errno = IESETBUF;
        !           532:        return -1;
        !           533:     }
        !           534:     if (test->debug) {
        !           535:        printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize);
        !           536:     }
        !           537:     if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) {
        !           538:        i_errno = IESETBUF2;
        !           539:        return -1;
        !           540:     }
        !           541: 
        !           542:     if (test->json_output) {
        !           543:        cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize);
        !           544:        cJSON_AddNumberToObject(test->json_start, "sndbuf_actual", sndbuf_actual);
        !           545:        cJSON_AddNumberToObject(test->json_start, "rcvbuf_actual", rcvbuf_actual);
        !           546:     }
        !           547: 
1.1       misho     548: #if defined(HAVE_FLOWLABEL)
                    549:     if (test->settings->flowlabel) {
                    550:         if (server_res->ai_addr->sa_family != AF_INET6) {
                    551:            saved_errno = errno;
                    552:            close(s);
                    553:            freeaddrinfo(server_res);
                    554:            errno = saved_errno;
                    555:             i_errno = IESETFLOW;
                    556:             return -1;
                    557:        } else {
                    558:            struct sockaddr_in6* sa6P = (struct sockaddr_in6*) server_res->ai_addr;
                    559:             char freq_buf[sizeof(struct in6_flowlabel_req)];
                    560:             struct in6_flowlabel_req *freq = (struct in6_flowlabel_req *)freq_buf;
                    561:             int freq_len = sizeof(*freq);
                    562: 
                    563:             memset(freq, 0, sizeof(*freq));
                    564:             freq->flr_label = htonl(test->settings->flowlabel & IPV6_FLOWINFO_FLOWLABEL);
                    565:             freq->flr_action = IPV6_FL_A_GET;
                    566:             freq->flr_flags = IPV6_FL_F_CREATE;
1.1.1.2 ! misho     567:             freq->flr_share = IPV6_FL_S_ANY;
1.1       misho     568:             memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16);
                    569: 
                    570:             if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) {
                    571:                saved_errno = errno;
                    572:                 close(s);
                    573:                 freeaddrinfo(server_res);
                    574:                errno = saved_errno;
                    575:                 i_errno = IESETFLOW;
                    576:                 return -1;
                    577:             }
                    578:             sa6P->sin6_flowinfo = freq->flr_label;
                    579: 
                    580:             opt = 1;
                    581:             if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &opt, sizeof(opt)) < 0) {
                    582:                saved_errno = errno;
                    583:                 close(s);
                    584:                 freeaddrinfo(server_res);
                    585:                errno = saved_errno;
                    586:                 i_errno = IESETFLOW;
                    587:                 return -1;
                    588:             } 
                    589:        }
                    590:     }
                    591: #endif /* HAVE_FLOWLABEL */
                    592: 
                    593: #if defined(HAVE_SO_MAX_PACING_RATE)
1.1.1.2 ! misho     594:     /* If socket pacing is specified try to enable it. */
        !           595:     if (test->settings->fqrate) {
1.1       misho     596:        /* Convert bits per second to bytes per second */
1.1.1.2 ! misho     597:        unsigned int fqrate = test->settings->fqrate / 8;
        !           598:        if (fqrate > 0) {
1.1       misho     599:            if (test->debug) {
1.1.1.2 ! misho     600:                printf("Setting fair-queue socket pacing to %u\n", fqrate);
1.1       misho     601:            }
1.1.1.2 ! misho     602:            if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
        !           603:                warning("Unable to set socket pacing");
1.1       misho     604:            }
                    605:        }
                    606:     }
                    607: #endif /* HAVE_SO_MAX_PACING_RATE */
1.1.1.2 ! misho     608:     {
        !           609:        unsigned int rate = test->settings->rate / 8;
        !           610:        if (rate > 0) {
        !           611:            if (test->debug) {
        !           612:                printf("Setting application pacing to %u\n", rate);
        !           613:            }
        !           614:        }
        !           615:     }
1.1       misho     616: 
                    617:     if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
                    618:        saved_errno = errno;
                    619:        close(s);
                    620:        freeaddrinfo(server_res);
                    621:        errno = saved_errno;
                    622:         i_errno = IESTREAMCONNECT;
                    623:         return -1;
                    624:     }
                    625: 
                    626:     freeaddrinfo(server_res);
                    627: 
                    628:     /* Send cookie for verification */
                    629:     if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
                    630:        saved_errno = errno;
                    631:        close(s);
                    632:        errno = saved_errno;
                    633:         i_errno = IESENDCOOKIE;
                    634:         return -1;
                    635:     }
                    636: 
                    637:     return s;
                    638: }

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