File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iperf / src / iperf_udp.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:36:46 2021 UTC (3 years, 4 months ago) by misho
Branches: iperf, MAIN
CVS tags: v3_3_9, HEAD
iperf 3.3.9

    1: /*
    2:  * iperf, Copyright (c) 2014-2020, 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 <stdio.h>
   28: #include <stdlib.h>
   29: #include <string.h>
   30: #include <errno.h>
   31: #include <unistd.h>
   32: #include <assert.h>
   33: #include <arpa/inet.h>
   34: #include <sys/socket.h>
   35: #include <sys/types.h>
   36: #include <netinet/in.h>
   37: #ifdef HAVE_STDINT_H
   38: #include <stdint.h>
   39: #endif
   40: #include <sys/time.h>
   41: #include <sys/select.h>
   42: 
   43: #include "iperf.h"
   44: #include "iperf_api.h"
   45: #include "iperf_util.h"
   46: #include "iperf_udp.h"
   47: #include "timer.h"
   48: #include "net.h"
   49: #include "cjson.h"
   50: #include "portable_endian.h"
   51: 
   52: #if defined(HAVE_INTTYPES_H)
   53: # include <inttypes.h>
   54: #else
   55: # ifndef PRIu64
   56: #  if sizeof(long) == 8
   57: #   define PRIu64		"lu"
   58: #  else
   59: #   define PRIu64		"llu"
   60: #  endif
   61: # endif
   62: #endif
   63: 
   64: /* iperf_udp_recv
   65:  *
   66:  * receives the data for UDP
   67:  */
   68: int
   69: iperf_udp_recv(struct iperf_stream *sp)
   70: {
   71:     uint32_t  sec, usec;
   72:     uint64_t  pcount;
   73:     int       r;
   74:     int       size = sp->settings->blksize;
   75:     int       first_packet = 0;
   76:     double    transit = 0, d = 0;
   77:     struct iperf_time sent_time, arrival_time, temp_time;
   78: 
   79:     r = Nread(sp->socket, sp->buffer, size, Pudp);
   80: 
   81:     /*
   82:      * If we got an error in the read, or if we didn't read anything
   83:      * because the underlying read(2) got a EAGAIN, then skip packet
   84:      * processing.
   85:      */
   86:     if (r <= 0)
   87:         return r;
   88: 
   89:     /* Only count bytes received while we're in the correct state. */
   90:     if (sp->test->state == TEST_RUNNING) {
   91: 
   92: 	/*
   93: 	 * For jitter computation below, it's important to know if this
   94: 	 * packet is the first packet received.
   95: 	 */
   96: 	if (sp->result->bytes_received == 0) {
   97: 	    first_packet = 1;
   98: 	}
   99: 
  100: 	sp->result->bytes_received += r;
  101: 	sp->result->bytes_received_this_interval += r;
  102: 
  103: 	/* Dig the various counters out of the incoming UDP packet */
  104: 	if (sp->test->udp_counters_64bit) {
  105: 	    memcpy(&sec, sp->buffer, sizeof(sec));
  106: 	    memcpy(&usec, sp->buffer+4, sizeof(usec));
  107: 	    memcpy(&pcount, sp->buffer+8, sizeof(pcount));
  108: 	    sec = ntohl(sec);
  109: 	    usec = ntohl(usec);
  110: 	    pcount = be64toh(pcount);
  111: 	    sent_time.secs = sec;
  112: 	    sent_time.usecs = usec;
  113: 	}
  114: 	else {
  115: 	    uint32_t pc;
  116: 	    memcpy(&sec, sp->buffer, sizeof(sec));
  117: 	    memcpy(&usec, sp->buffer+4, sizeof(usec));
  118: 	    memcpy(&pc, sp->buffer+8, sizeof(pc));
  119: 	    sec = ntohl(sec);
  120: 	    usec = ntohl(usec);
  121: 	    pcount = ntohl(pc);
  122: 	    sent_time.secs = sec;
  123: 	    sent_time.usecs = usec;
  124: 	}
  125: 
  126: 	if (sp->test->debug)
  127: 	    fprintf(stderr, "pcount %" PRIu64 " packet_count %d\n", pcount, sp->packet_count);
  128: 
  129: 	/*
  130: 	 * Try to handle out of order packets.  The way we do this
  131: 	 * uses a constant amount of storage but might not be
  132: 	 * correct in all cases.  In particular we seem to have the
  133: 	 * assumption that packets can't be duplicated in the network,
  134: 	 * because duplicate packets will possibly cause some problems here.
  135: 	 *
  136: 	 * First figure out if the sequence numbers are going forward.
  137: 	 * Note that pcount is the sequence number read from the packet,
  138: 	 * and sp->packet_count is the highest sequence number seen so
  139: 	 * far (so we're expecting to see the packet with sequence number
  140: 	 * sp->packet_count + 1 arrive next).
  141: 	 */
  142: 	if (pcount >= sp->packet_count + 1) {
  143: 
  144: 	    /* Forward, but is there a gap in sequence numbers? */
  145: 	    if (pcount > sp->packet_count + 1) {
  146: 		/* There's a gap so count that as a loss. */
  147: 		sp->cnt_error += (pcount - 1) - sp->packet_count;
  148: 	    }
  149: 	    /* Update the highest sequence number seen so far. */
  150: 	    sp->packet_count = pcount;
  151: 	} else {
  152: 
  153: 	    /* 
  154: 	     * Sequence number went backward (or was stationary?!?).
  155: 	     * This counts as an out-of-order packet.
  156: 	     */
  157: 	    sp->outoforder_packets++;
  158: 
  159: 	    /*
  160: 	     * If we have lost packets, then the fact that we are now
  161: 	     * seeing an out-of-order packet offsets a prior sequence
  162: 	     * number gap that was counted as a loss.  So we can take
  163: 	     * away a loss.
  164: 	     */
  165: 	    if (sp->cnt_error > 0)
  166: 		sp->cnt_error--;
  167: 	
  168: 	    /* Log the out-of-order packet */
  169: 	    if (sp->test->debug) 
  170: 		fprintf(stderr, "OUT OF ORDER - incoming packet sequence %" PRIu64 " but expected sequence %d on stream %d", pcount, sp->packet_count + 1, sp->socket);
  171: 	}
  172: 
  173: 	/*
  174: 	 * jitter measurement
  175: 	 *
  176: 	 * This computation is based on RFC 1889 (specifically
  177: 	 * sections 6.3.1 and A.8).
  178: 	 *
  179: 	 * Note that synchronized clocks are not required since
  180: 	 * the source packet delta times are known.  Also this
  181: 	 * computation does not require knowing the round-trip
  182: 	 * time.
  183: 	 */
  184: 	iperf_time_now(&arrival_time);
  185: 
  186: 	iperf_time_diff(&arrival_time, &sent_time, &temp_time);
  187: 	transit = iperf_time_in_secs(&temp_time);
  188: 
  189: 	/* Hack to handle the first packet by initializing prev_transit. */
  190: 	if (first_packet)
  191: 	    sp->prev_transit = transit;
  192: 
  193: 	d = transit - sp->prev_transit;
  194: 	if (d < 0)
  195: 	    d = -d;
  196: 	sp->prev_transit = transit;
  197: 	sp->jitter += (d - sp->jitter) / 16.0;
  198:     }
  199:     else {
  200: 	if (sp->test->debug)
  201: 	    printf("Late receive, state = %d\n", sp->test->state);
  202:     }
  203: 
  204:     return r;
  205: }
  206: 
  207: 
  208: /* iperf_udp_send
  209:  *
  210:  * sends the data for UDP
  211:  */
  212: int
  213: iperf_udp_send(struct iperf_stream *sp)
  214: {
  215:     int r;
  216:     int       size = sp->settings->blksize;
  217:     struct iperf_time before;
  218: 
  219:     iperf_time_now(&before);
  220: 
  221:     ++sp->packet_count;
  222: 
  223:     if (sp->test->udp_counters_64bit) {
  224: 
  225: 	uint32_t  sec, usec;
  226: 	uint64_t  pcount;
  227: 
  228: 	sec = htonl(before.secs);
  229: 	usec = htonl(before.usecs);
  230: 	pcount = htobe64(sp->packet_count);
  231: 	
  232: 	memcpy(sp->buffer, &sec, sizeof(sec));
  233: 	memcpy(sp->buffer+4, &usec, sizeof(usec));
  234: 	memcpy(sp->buffer+8, &pcount, sizeof(pcount));
  235: 	
  236:     }
  237:     else {
  238: 
  239: 	uint32_t  sec, usec, pcount;
  240: 
  241: 	sec = htonl(before.secs);
  242: 	usec = htonl(before.usecs);
  243: 	pcount = htonl(sp->packet_count);
  244: 	
  245: 	memcpy(sp->buffer, &sec, sizeof(sec));
  246: 	memcpy(sp->buffer+4, &usec, sizeof(usec));
  247: 	memcpy(sp->buffer+8, &pcount, sizeof(pcount));
  248: 	
  249:     }
  250: 
  251:     r = Nwrite(sp->socket, sp->buffer, size, Pudp);
  252: 
  253:     if (r < 0)
  254: 	return r;
  255: 
  256:     sp->result->bytes_sent += r;
  257:     sp->result->bytes_sent_this_interval += r;
  258: 
  259:     if (sp->test->debug)
  260: 	printf("sent %d bytes of %d, total %" PRIu64 "\n", r, sp->settings->blksize, sp->result->bytes_sent);
  261: 
  262:     return r;
  263: }
  264: 
  265: 
  266: /**************************************************************************/
  267: 
  268: /*
  269:  * The following functions all have to do with managing UDP data sockets.
  270:  * UDP of course is connectionless, so there isn't really a concept of
  271:  * setting up a connection, although connect(2) can (and is) used to
  272:  * bind the remote end of sockets.  We need to simulate some of the
  273:  * connection management that is built-in to TCP so that each side of the
  274:  * connection knows about each other before the real data transfers begin.
  275:  */
  276: 
  277: /*
  278:  * Set and verify socket buffer sizes.
  279:  * Return 0 if no error, -1 if an error, +1 if socket buffers are
  280:  * potentially too small to hold a message.
  281:  */
  282: int
  283: iperf_udp_buffercheck(struct iperf_test *test, int s)
  284: {
  285:     int rc = 0;
  286:     int sndbuf_actual, rcvbuf_actual;
  287: 
  288:     /*
  289:      * Set socket buffer size if requested.  Do this for both sending and
  290:      * receiving so that we can cover both normal and --reverse operation.
  291:      */
  292:     int opt;
  293:     socklen_t optlen;
  294:     
  295:     if ((opt = test->settings->socket_bufsize)) {
  296:         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
  297:             i_errno = IESETBUF;
  298:             return -1;
  299:         }
  300:         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
  301:             i_errno = IESETBUF;
  302:             return -1;
  303:         }
  304:     }
  305: 
  306:     /* Read back and verify the sender socket buffer size */
  307:     optlen = sizeof(sndbuf_actual);
  308:     if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) {
  309: 	i_errno = IESETBUF;
  310: 	return -1;
  311:     }
  312:     if (test->debug) {
  313: 	printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize);
  314:     }
  315:     if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) {
  316: 	i_errno = IESETBUF2;
  317: 	return -1;
  318:     }
  319:     if (test->settings->blksize > sndbuf_actual) {
  320: 	char str[80];
  321: 	snprintf(str, sizeof(str),
  322: 		 "Block size %d > sending socket buffer size %d",
  323: 		 test->settings->blksize, sndbuf_actual);
  324: 	warning(str);
  325: 	rc = 1;
  326:     }
  327: 
  328:     /* Read back and verify the receiver socket buffer size */
  329:     optlen = sizeof(rcvbuf_actual);
  330:     if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) {
  331: 	i_errno = IESETBUF;
  332: 	return -1;
  333:     }
  334:     if (test->debug) {
  335: 	printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize);
  336:     }
  337:     if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) {
  338: 	i_errno = IESETBUF2;
  339: 	return -1;
  340:     }
  341:     if (test->settings->blksize > rcvbuf_actual) {
  342: 	char str[80];
  343: 	snprintf(str, sizeof(str),
  344: 		 "Block size %d > receiving socket buffer size %d",
  345: 		 test->settings->blksize, rcvbuf_actual);
  346: 	warning(str);
  347: 	rc = 1;
  348:     }
  349: 
  350:     if (test->json_output) {
  351: 	cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize);
  352: 	cJSON_AddNumberToObject(test->json_start, "sndbuf_actual", sndbuf_actual);
  353: 	cJSON_AddNumberToObject(test->json_start, "rcvbuf_actual", rcvbuf_actual);
  354:     }
  355: 
  356:     return rc;
  357: }
  358: 
  359: /*
  360:  * iperf_udp_accept
  361:  *
  362:  * Accepts a new UDP "connection"
  363:  */
  364: int
  365: iperf_udp_accept(struct iperf_test *test)
  366: {
  367:     struct sockaddr_storage sa_peer;
  368:     int       buf;
  369:     socklen_t len;
  370:     int       sz, s;
  371:     int	      rc;
  372: 
  373:     /*
  374:      * Get the current outstanding socket.  This socket will be used to handle
  375:      * data transfers and a new "listening" socket will be created.
  376:      */
  377:     s = test->prot_listener;
  378: 
  379:     /*
  380:      * Grab the UDP packet sent by the client.  From that we can extract the
  381:      * client's address, and then use that information to bind the remote side
  382:      * of the socket to the client.
  383:      */
  384:     len = sizeof(sa_peer);
  385:     if ((sz = recvfrom(test->prot_listener, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
  386:         i_errno = IESTREAMACCEPT;
  387:         return -1;
  388:     }
  389: 
  390:     if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) {
  391:         i_errno = IESTREAMACCEPT;
  392:         return -1;
  393:     }
  394: 
  395:     /* Check and set socket buffer sizes */
  396:     rc = iperf_udp_buffercheck(test, s);
  397:     if (rc < 0)
  398: 	/* error */
  399: 	return rc;
  400:     /*
  401:      * If the socket buffer was too small, but it was the default
  402:      * size, then try explicitly setting it to something larger.
  403:      */
  404:     if (rc > 0) {
  405: 	if (test->settings->socket_bufsize == 0) {
  406: 	    int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA;
  407: 	    printf("Increasing socket buffer size to %d\n",
  408: 		bufsize);
  409: 	    test->settings->socket_bufsize = bufsize;
  410: 	    rc = iperf_udp_buffercheck(test, s);
  411: 	    if (rc < 0)
  412: 		return rc;
  413: 	}
  414:     }
  415: 	
  416: #if defined(HAVE_SO_MAX_PACING_RATE)
  417:     /* If socket pacing is specified, try it. */
  418:     if (test->settings->fqrate) {
  419: 	/* Convert bits per second to bytes per second */
  420: 	unsigned int fqrate = test->settings->fqrate / 8;
  421: 	if (fqrate > 0) {
  422: 	    if (test->debug) {
  423: 		printf("Setting fair-queue socket pacing to %u\n", fqrate);
  424: 	    }
  425: 	    if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
  426: 		warning("Unable to set socket pacing");
  427: 	    }
  428: 	}
  429:     }
  430: #endif /* HAVE_SO_MAX_PACING_RATE */
  431:     {
  432: 	unsigned int rate = test->settings->rate / 8;
  433: 	if (rate > 0) {
  434: 	    if (test->debug) {
  435: 		printf("Setting application pacing to %u\n", rate);
  436: 	    }
  437: 	}
  438:     }
  439: 
  440:     /*
  441:      * Create a new "listening" socket to replace the one we were using before.
  442:      */
  443:     test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port);
  444:     if (test->prot_listener < 0) {
  445:         i_errno = IESTREAMLISTEN;
  446:         return -1;
  447:     }
  448: 
  449:     FD_SET(test->prot_listener, &test->read_set);
  450:     test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd;
  451: 
  452:     /* Let the client know we're ready "accept" another UDP "stream" */
  453:     buf = 987654321;		/* any content will work here */
  454:     if (write(s, &buf, sizeof(buf)) < 0) {
  455:         i_errno = IESTREAMWRITE;
  456:         return -1;
  457:     }
  458: 
  459:     return s;
  460: }
  461: 
  462: 
  463: /*
  464:  * iperf_udp_listen
  465:  *
  466:  * Start up a listener for UDP stream connections.  Unlike for TCP,
  467:  * there is no listen(2) for UDP.  This socket will however accept
  468:  * a UDP datagram from a client (indicating the client's presence).
  469:  */
  470: int
  471: iperf_udp_listen(struct iperf_test *test)
  472: {
  473:     int s;
  474: 
  475:     if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port)) < 0) {
  476:         i_errno = IESTREAMLISTEN;
  477:         return -1;
  478:     }
  479: 
  480:     /*
  481:      * The caller will put this value into test->prot_listener.
  482:      */
  483:     return s;
  484: }
  485: 
  486: 
  487: /*
  488:  * iperf_udp_connect
  489:  *
  490:  * "Connect" to a UDP stream listener.
  491:  */
  492: int
  493: iperf_udp_connect(struct iperf_test *test)
  494: {
  495:     int s, buf, sz;
  496: #ifdef SO_RCVTIMEO
  497:     struct timeval tv;
  498: #endif
  499:     int rc;
  500: 
  501:     /* Create and bind our local socket. */
  502:     if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_port, test->server_hostname, test->server_port, -1)) < 0) {
  503:         i_errno = IESTREAMCONNECT;
  504:         return -1;
  505:     }
  506: 
  507:     /* Check and set socket buffer sizes */
  508:     rc = iperf_udp_buffercheck(test, s);
  509:     if (rc < 0)
  510: 	/* error */
  511: 	return rc;
  512:     /*
  513:      * If the socket buffer was too small, but it was the default
  514:      * size, then try explicitly setting it to something larger.
  515:      */
  516:     if (rc > 0) {
  517: 	if (test->settings->socket_bufsize == 0) {
  518: 	    int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA;
  519: 	    printf("Increasing socket buffer size to %d\n",
  520: 		bufsize);
  521: 	    test->settings->socket_bufsize = bufsize;
  522: 	    rc = iperf_udp_buffercheck(test, s);
  523: 	    if (rc < 0)
  524: 		return rc;
  525: 	}
  526:     }
  527: 	
  528: #if defined(HAVE_SO_MAX_PACING_RATE)
  529:     /* If socket pacing is available and not disabled, try it. */
  530:     if (test->settings->fqrate) {
  531: 	/* Convert bits per second to bytes per second */
  532: 	unsigned int fqrate = test->settings->fqrate / 8;
  533: 	if (fqrate > 0) {
  534: 	    if (test->debug) {
  535: 		printf("Setting fair-queue socket pacing to %u\n", fqrate);
  536: 	    }
  537: 	    if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
  538: 		warning("Unable to set socket pacing");
  539: 	    }
  540: 	}
  541:     }
  542: #endif /* HAVE_SO_MAX_PACING_RATE */
  543:     {
  544: 	unsigned int rate = test->settings->rate / 8;
  545: 	if (rate > 0) {
  546: 	    if (test->debug) {
  547: 		printf("Setting application pacing to %u\n", rate);
  548: 	    }
  549: 	}
  550:     }
  551: 
  552: #ifdef SO_RCVTIMEO
  553:     /* 30 sec timeout for a case when there is a network problem. */
  554:     tv.tv_sec = 30;
  555:     tv.tv_usec = 0;
  556:     setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
  557: #endif
  558: 
  559:     /*
  560:      * Write a datagram to the UDP stream to let the server know we're here.
  561:      * The server learns our address by obtaining its peer's address.
  562:      */
  563:     buf = 123456789;		/* this can be pretty much anything */
  564:     if (write(s, &buf, sizeof(buf)) < 0) {
  565:         // XXX: Should this be changed to IESTREAMCONNECT? 
  566:         i_errno = IESTREAMWRITE;
  567:         return -1;
  568:     }
  569: 
  570:     /*
  571:      * Wait until the server replies back to us.
  572:      */
  573:     if ((sz = recv(s, &buf, sizeof(buf), 0)) < 0) {
  574:         i_errno = IESTREAMREAD;
  575:         return -1;
  576:     }
  577: 
  578:     return s;
  579: }
  580: 
  581: 
  582: /* iperf_udp_init
  583:  *
  584:  * initializer for UDP streams in TEST_START
  585:  */
  586: int
  587: iperf_udp_init(struct iperf_test *test)
  588: {
  589:     return 0;
  590: }

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