File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iperf / src / iperf_tcp.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Oct 18 13:28:18 2016 UTC (7 years, 8 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /*
    2:  * iperf, Copyright (c) 2014, 2016, 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 <stdlib.h>
   31: #include <string.h>
   32: #include <errno.h>
   33: #include <unistd.h>
   34: #include <sys/socket.h>
   35: #include <sys/types.h>
   36: #include <netinet/in.h>
   37: #include <netdb.h>
   38: #include <netinet/tcp.h>
   39: #include <sys/time.h>
   40: #include <sys/select.h>
   41: 
   42: #include "iperf.h"
   43: #include "iperf_api.h"
   44: #include "iperf_tcp.h"
   45: #include "net.h"
   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: 
   65:     sp->result->bytes_received += r;
   66:     sp->result->bytes_received_this_interval += r;
   67: 
   68:     return r;
   69: }
   70: 
   71: 
   72: /* iperf_tcp_send 
   73:  *
   74:  * sends the data for TCP
   75:  */
   76: int
   77: iperf_tcp_send(struct iperf_stream *sp)
   78: {
   79:     int r;
   80: 
   81:     if (sp->test->zerocopy)
   82: 	r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->settings->blksize);
   83:     else
   84: 	r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);
   85: 
   86:     if (r < 0)
   87:         return r;
   88: 
   89:     sp->result->bytes_sent += r;
   90:     sp->result->bytes_sent_this_interval += r;
   91: 
   92:     return r;
   93: }
   94: 
   95: 
   96: /* iperf_tcp_accept
   97:  *
   98:  * accept a new TCP stream connection
   99:  */
  100: int
  101: iperf_tcp_accept(struct iperf_test * test)
  102: {
  103:     int     s;
  104:     signed char rbuf = ACCESS_DENIED;
  105:     char    cookie[COOKIE_SIZE];
  106:     socklen_t len;
  107:     struct sockaddr_storage addr;
  108: 
  109:     len = sizeof(addr);
  110:     if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
  111:         i_errno = IESTREAMCONNECT;
  112:         return -1;
  113:     }
  114: 
  115:     if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
  116:         i_errno = IERECVCOOKIE;
  117:         return -1;
  118:     }
  119: 
  120:     if (strcmp(test->cookie, cookie) != 0) {
  121:         if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
  122:             i_errno = IESENDMESSAGE;
  123:             return -1;
  124:         }
  125:         close(s);
  126:     }
  127: 
  128:     return s;
  129: }
  130: 
  131: 
  132: /* iperf_tcp_listen
  133:  *
  134:  * start up a listener for TCP stream connections
  135:  */
  136: int
  137: iperf_tcp_listen(struct iperf_test *test)
  138: {
  139:     struct addrinfo hints, *res;
  140:     char portstr[6];
  141:     int s, opt;
  142:     int saved_errno;
  143: 
  144:     s = test->listener;
  145: 
  146:     /*
  147:      * If certain parameters are specified (such as socket buffer
  148:      * size), then throw away the listening socket (the one for which
  149:      * we just accepted the control connection) and recreate it with
  150:      * those parameters.  That way, when new data connections are
  151:      * set, they'll have all the correct parameters in place.
  152:      *
  153:      * It's not clear whether this is a requirement or a convenience.
  154:      */
  155:     if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
  156:         FD_CLR(s, &test->read_set);
  157:         close(s);
  158: 
  159:         snprintf(portstr, 6, "%d", test->server_port);
  160:         memset(&hints, 0, sizeof(hints));
  161: 
  162: 	/*
  163: 	 * If binding to the wildcard address with no explicit address
  164: 	 * family specified, then force us to get an AF_INET6 socket.
  165: 	 * More details in the comments in netanounce().
  166: 	 */
  167: 	if (test->settings->domain == AF_UNSPEC && !test->bind_address) {
  168: 	    hints.ai_family = AF_INET6;
  169: 	}
  170: 	else {
  171: 	    hints.ai_family = test->settings->domain;
  172: 	}
  173:         hints.ai_socktype = SOCK_STREAM;
  174:         hints.ai_flags = AI_PASSIVE;
  175:         if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) {
  176:             i_errno = IESTREAMLISTEN;
  177:             return -1;
  178:         }
  179: 
  180:         if ((s = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
  181: 	    freeaddrinfo(res);
  182:             i_errno = IESTREAMLISTEN;
  183:             return -1;
  184:         }
  185: 
  186:         if (test->no_delay) {
  187:             opt = 1;
  188:             if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
  189: 		saved_errno = errno;
  190: 		close(s);
  191: 		freeaddrinfo(res);
  192: 		errno = saved_errno;
  193:                 i_errno = IESETNODELAY;
  194:                 return -1;
  195:             }
  196:         }
  197:         // XXX: Setting MSS is very buggy!
  198:         if ((opt = test->settings->mss)) {
  199:             if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
  200: 		saved_errno = errno;
  201: 		close(s);
  202: 		freeaddrinfo(res);
  203: 		errno = saved_errno;
  204:                 i_errno = IESETMSS;
  205:                 return -1;
  206:             }
  207:         }
  208:         if ((opt = test->settings->socket_bufsize)) {
  209:             if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
  210: 		saved_errno = errno;
  211: 		close(s);
  212: 		freeaddrinfo(res);
  213: 		errno = saved_errno;
  214:                 i_errno = IESETBUF;
  215:                 return -1;
  216:             }
  217:             if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
  218: 		saved_errno = errno;
  219: 		close(s);
  220: 		freeaddrinfo(res);
  221: 		errno = saved_errno;
  222:                 i_errno = IESETBUF;
  223:                 return -1;
  224:             }
  225:         }
  226: 	if (test->debug) {
  227: 	    socklen_t optlen = sizeof(opt);
  228: 	    if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) {
  229: 		saved_errno = errno;
  230: 		close(s);
  231: 		freeaddrinfo(res);
  232: 		errno = saved_errno;
  233: 		i_errno = IESETBUF;
  234: 		return -1;
  235: 	    }
  236: 	    printf("SO_SNDBUF is %u\n", opt);
  237: 	}
  238: #if defined(HAVE_TCP_CONGESTION)
  239: 	if (test->congestion) {
  240: 	    if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
  241: 		close(s);
  242: 		freeaddrinfo(res);
  243: 		i_errno = IESETCONGESTION;
  244: 		return -1;
  245: 	    } 
  246: 	}
  247: #endif /* HAVE_TCP_CONGESTION */
  248: #if defined(HAVE_SO_MAX_PACING_RATE)
  249:     /* If socket pacing is available and not disabled, try it. */
  250:     if (! test->no_fq_socket_pacing) {
  251: 	/* Convert bits per second to bytes per second */
  252: 	unsigned int rate = test->settings->rate / 8;
  253: 	if (rate > 0) {
  254: 	    if (test->debug) {
  255: 		printf("Setting fair-queue socket pacing to %u\n", rate);
  256: 	    }
  257: 	    if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) {
  258: 		warning("Unable to set socket pacing, using application pacing instead");
  259: 		test->no_fq_socket_pacing = 1;
  260: 	    }
  261: 	}
  262:     }
  263: #endif /* HAVE_SO_MAX_PACING_RATE */
  264:         opt = 1;
  265:         if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
  266: 	    saved_errno = errno;
  267:             close(s);
  268: 	    freeaddrinfo(res);
  269: 	    errno = saved_errno;
  270:             i_errno = IEREUSEADDR;
  271:             return -1;
  272:         }
  273: 
  274: 	/*
  275: 	 * If we got an IPv6 socket, figure out if it shoudl accept IPv4
  276: 	 * connections as well.  See documentation in netannounce() for
  277: 	 * more details.
  278: 	 */
  279: #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
  280: 	if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET)) {
  281: 	    if (test->settings->domain == AF_UNSPEC)
  282: 		opt = 0;
  283: 	    else 
  284: 		opt = 1;
  285: 	    if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 
  286: 			   (char *) &opt, sizeof(opt)) < 0) {
  287: 		saved_errno = errno;
  288: 		close(s);
  289: 		freeaddrinfo(res);
  290: 		errno = saved_errno;
  291: 		i_errno = IEV6ONLY;
  292: 		return -1;
  293: 	    }
  294: 	}
  295: #endif /* IPV6_V6ONLY */
  296: 
  297:         if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
  298: 	    saved_errno = errno;
  299:             close(s);
  300: 	    freeaddrinfo(res);
  301: 	    errno = saved_errno;
  302:             i_errno = IESTREAMLISTEN;
  303:             return -1;
  304:         }
  305: 
  306:         freeaddrinfo(res);
  307: 
  308:         if (listen(s, 5) < 0) {
  309:             i_errno = IESTREAMLISTEN;
  310:             return -1;
  311:         }
  312: 
  313:         test->listener = s;
  314:     }
  315:     
  316:     return s;
  317: }
  318: 
  319: 
  320: /* iperf_tcp_connect
  321:  *
  322:  * connect to a TCP stream listener
  323:  */
  324: int
  325: iperf_tcp_connect(struct iperf_test *test)
  326: {
  327:     struct addrinfo hints, *local_res, *server_res;
  328:     char portstr[6];
  329:     int s, opt;
  330:     int saved_errno;
  331: 
  332:     if (test->bind_address) {
  333:         memset(&hints, 0, sizeof(hints));
  334:         hints.ai_family = test->settings->domain;
  335:         hints.ai_socktype = SOCK_STREAM;
  336:         if (getaddrinfo(test->bind_address, NULL, &hints, &local_res) != 0) {
  337:             i_errno = IESTREAMCONNECT;
  338:             return -1;
  339:         }
  340:     }
  341: 
  342:     memset(&hints, 0, sizeof(hints));
  343:     hints.ai_family = test->settings->domain;
  344:     hints.ai_socktype = SOCK_STREAM;
  345:     snprintf(portstr, sizeof(portstr), "%d", test->server_port);
  346:     if (getaddrinfo(test->server_hostname, portstr, &hints, &server_res) != 0) {
  347: 	if (test->bind_address)
  348: 	    freeaddrinfo(local_res);
  349:         i_errno = IESTREAMCONNECT;
  350:         return -1;
  351:     }
  352: 
  353:     if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) {
  354: 	if (test->bind_address)
  355: 	    freeaddrinfo(local_res);
  356: 	freeaddrinfo(server_res);
  357:         i_errno = IESTREAMCONNECT;
  358:         return -1;
  359:     }
  360: 
  361:     if (test->bind_address) {
  362:         struct sockaddr_in *lcladdr;
  363:         lcladdr = (struct sockaddr_in *)local_res->ai_addr;
  364:         lcladdr->sin_port = htons(test->bind_port);
  365:         local_res->ai_addr = (struct sockaddr *)lcladdr;
  366: 
  367:         if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
  368: 	    saved_errno = errno;
  369: 	    close(s);
  370: 	    freeaddrinfo(local_res);
  371: 	    freeaddrinfo(server_res);
  372: 	    errno = saved_errno;
  373:             i_errno = IESTREAMCONNECT;
  374:             return -1;
  375:         }
  376:         freeaddrinfo(local_res);
  377:     }
  378: 
  379:     /* Set socket options */
  380:     if (test->no_delay) {
  381:         opt = 1;
  382:         if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
  383: 	    saved_errno = errno;
  384: 	    close(s);
  385: 	    freeaddrinfo(server_res);
  386: 	    errno = saved_errno;
  387:             i_errno = IESETNODELAY;
  388:             return -1;
  389:         }
  390:     }
  391:     if ((opt = test->settings->mss)) {
  392:         if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
  393: 	    saved_errno = errno;
  394: 	    close(s);
  395: 	    freeaddrinfo(server_res);
  396: 	    errno = saved_errno;
  397:             i_errno = IESETMSS;
  398:             return -1;
  399:         }
  400:     }
  401:     if ((opt = test->settings->socket_bufsize)) {
  402:         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
  403: 	    saved_errno = errno;
  404: 	    close(s);
  405: 	    freeaddrinfo(server_res);
  406: 	    errno = saved_errno;
  407:             i_errno = IESETBUF;
  408:             return -1;
  409:         }
  410:         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
  411: 	    saved_errno = errno;
  412: 	    close(s);
  413: 	    freeaddrinfo(server_res);
  414: 	    errno = saved_errno;
  415:             i_errno = IESETBUF;
  416:             return -1;
  417:         }
  418:     }
  419:     if (test->debug) {
  420: 	socklen_t optlen = sizeof(opt);
  421: 	if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) {
  422: 	    saved_errno = errno;
  423: 	    close(s);
  424: 	    freeaddrinfo(server_res);
  425: 	    errno = saved_errno;
  426: 	    i_errno = IESETBUF;
  427: 	    return -1;
  428: 	}
  429: 	printf("SO_SNDBUF is %u\n", opt);
  430:     }
  431: #if defined(HAVE_FLOWLABEL)
  432:     if (test->settings->flowlabel) {
  433:         if (server_res->ai_addr->sa_family != AF_INET6) {
  434: 	    saved_errno = errno;
  435: 	    close(s);
  436: 	    freeaddrinfo(server_res);
  437: 	    errno = saved_errno;
  438:             i_errno = IESETFLOW;
  439:             return -1;
  440: 	} else {
  441: 	    struct sockaddr_in6* sa6P = (struct sockaddr_in6*) server_res->ai_addr;
  442:             char freq_buf[sizeof(struct in6_flowlabel_req)];
  443:             struct in6_flowlabel_req *freq = (struct in6_flowlabel_req *)freq_buf;
  444:             int freq_len = sizeof(*freq);
  445: 
  446:             memset(freq, 0, sizeof(*freq));
  447:             freq->flr_label = htonl(test->settings->flowlabel & IPV6_FLOWINFO_FLOWLABEL);
  448:             freq->flr_action = IPV6_FL_A_GET;
  449:             freq->flr_flags = IPV6_FL_F_CREATE;
  450:             freq->flr_share = IPV6_FL_F_CREATE | IPV6_FL_S_EXCL;
  451:             memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16);
  452: 
  453:             if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) {
  454: 		saved_errno = errno;
  455:                 close(s);
  456:                 freeaddrinfo(server_res);
  457: 		errno = saved_errno;
  458:                 i_errno = IESETFLOW;
  459:                 return -1;
  460:             }
  461:             sa6P->sin6_flowinfo = freq->flr_label;
  462: 
  463:             opt = 1;
  464:             if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &opt, sizeof(opt)) < 0) {
  465: 		saved_errno = errno;
  466:                 close(s);
  467:                 freeaddrinfo(server_res);
  468: 		errno = saved_errno;
  469:                 i_errno = IESETFLOW;
  470:                 return -1;
  471:             } 
  472: 	}
  473:     }
  474: #endif /* HAVE_FLOWLABEL */
  475: 
  476: #if defined(HAVE_TCP_CONGESTION)
  477:     if (test->congestion) {
  478: 	if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
  479: 	    close(s);
  480: 	    freeaddrinfo(server_res);
  481: 	    i_errno = IESETCONGESTION;
  482: 	    return -1;
  483: 	}
  484:     }
  485: #endif /* HAVE_TCP_CONGESTION */
  486: 
  487: #if defined(HAVE_SO_MAX_PACING_RATE)
  488:     /* If socket pacing is available and not disabled, try it. */
  489:     if (! test->no_fq_socket_pacing) {
  490: 	/* Convert bits per second to bytes per second */
  491: 	unsigned int rate = test->settings->rate / 8;
  492: 	if (rate > 0) {
  493: 	    if (test->debug) {
  494: 		printf("Socket pacing set to %u\n", rate);
  495: 	    }
  496: 	    if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) {
  497: 		warning("Unable to set socket pacing, using application pacing instead");
  498: 		test->no_fq_socket_pacing = 1;
  499: 	    }
  500: 	}
  501:     }
  502: #endif /* HAVE_SO_MAX_PACING_RATE */
  503: 
  504:     if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
  505: 	saved_errno = errno;
  506: 	close(s);
  507: 	freeaddrinfo(server_res);
  508: 	errno = saved_errno;
  509:         i_errno = IESTREAMCONNECT;
  510:         return -1;
  511:     }
  512: 
  513:     freeaddrinfo(server_res);
  514: 
  515:     /* Send cookie for verification */
  516:     if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
  517: 	saved_errno = errno;
  518: 	close(s);
  519: 	errno = saved_errno;
  520:         i_errno = IESENDCOOKIE;
  521:         return -1;
  522:     }
  523: 
  524:     return s;
  525: }

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