File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / iperf / src / iperf_udp.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:14:54 2023 UTC (9 months ago) by misho
Branches: iperf, MAIN
CVS tags: v3_15, HEAD
Version 3.15

    1: /*
    2:  * iperf, Copyright (c) 2014-2022, 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_level >= DEBUG_LEVEL_DEBUG)
  127: 	    fprintf(stderr, "pcount %" PRIu64 " packet_count %" PRIu64 "\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 %" PRIu64 " 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:         --sp->packet_count;     /* Don't count messages that no data was sent from them.
  255:                                  * Allows "resending" a massage with the same numbering */
  256:         if (r < 0) {
  257:             if (r == NET_SOFTERROR && sp->test->debug_level >= DEBUG_LEVEL_INFO)
  258:                 printf("UDP send failed on NET_SOFTERROR. errno=%s\n", strerror(errno));
  259:             return r;
  260:         }
  261:     }
  262: 
  263:     sp->result->bytes_sent += r;
  264:     sp->result->bytes_sent_this_interval += r;
  265: 
  266:     if (sp->test->debug_level >=  DEBUG_LEVEL_DEBUG)
  267: 	printf("sent %d bytes of %d, total %" PRIu64 "\n", r, sp->settings->blksize, sp->result->bytes_sent);
  268: 
  269:     return r;
  270: }
  271: 
  272: 
  273: /**************************************************************************/
  274: 
  275: /*
  276:  * The following functions all have to do with managing UDP data sockets.
  277:  * UDP of course is connectionless, so there isn't really a concept of
  278:  * setting up a connection, although connect(2) can (and is) used to
  279:  * bind the remote end of sockets.  We need to simulate some of the
  280:  * connection management that is built-in to TCP so that each side of the
  281:  * connection knows about each other before the real data transfers begin.
  282:  */
  283: 
  284: /*
  285:  * Set and verify socket buffer sizes.
  286:  * Return 0 if no error, -1 if an error, +1 if socket buffers are
  287:  * potentially too small to hold a message.
  288:  */
  289: int
  290: iperf_udp_buffercheck(struct iperf_test *test, int s)
  291: {
  292:     int rc = 0;
  293:     int sndbuf_actual, rcvbuf_actual;
  294: 
  295:     /*
  296:      * Set socket buffer size if requested.  Do this for both sending and
  297:      * receiving so that we can cover both normal and --reverse operation.
  298:      */
  299:     int opt;
  300:     socklen_t optlen;
  301: 
  302:     if ((opt = test->settings->socket_bufsize)) {
  303:         if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
  304:             i_errno = IESETBUF;
  305:             return -1;
  306:         }
  307:         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
  308:             i_errno = IESETBUF;
  309:             return -1;
  310:         }
  311:     }
  312: 
  313:     /* Read back and verify the sender socket buffer size */
  314:     optlen = sizeof(sndbuf_actual);
  315:     if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) {
  316: 	i_errno = IESETBUF;
  317: 	return -1;
  318:     }
  319:     if (test->debug) {
  320: 	printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize);
  321:     }
  322:     if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) {
  323: 	i_errno = IESETBUF2;
  324: 	return -1;
  325:     }
  326:     if (test->settings->blksize > sndbuf_actual) {
  327: 	char str[WARN_STR_LEN];
  328: 	snprintf(str, sizeof(str),
  329: 		 "Block size %d > sending socket buffer size %d",
  330: 		 test->settings->blksize, sndbuf_actual);
  331: 	warning(str);
  332: 	rc = 1;
  333:     }
  334: 
  335:     /* Read back and verify the receiver socket buffer size */
  336:     optlen = sizeof(rcvbuf_actual);
  337:     if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) {
  338: 	i_errno = IESETBUF;
  339: 	return -1;
  340:     }
  341:     if (test->debug) {
  342: 	printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize);
  343:     }
  344:     if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) {
  345: 	i_errno = IESETBUF2;
  346: 	return -1;
  347:     }
  348:     if (test->settings->blksize > rcvbuf_actual) {
  349: 	char str[WARN_STR_LEN];
  350: 	snprintf(str, sizeof(str),
  351: 		 "Block size %d > receiving socket buffer size %d",
  352: 		 test->settings->blksize, rcvbuf_actual);
  353: 	warning(str);
  354: 	rc = 1;
  355:     }
  356: 
  357:     if (test->json_output) {
  358:     cJSON *sock_bufsize_item = cJSON_GetObjectItem(test->json_start, "sock_bufsize");
  359:     if (sock_bufsize_item == NULL) {
  360:     cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize);
  361:     }
  362: 
  363:     cJSON *sndbuf_actual_item = cJSON_GetObjectItem(test->json_start, "sndbuf_actual");
  364:     if (sndbuf_actual_item == NULL) {
  365: 	cJSON_AddNumberToObject(test->json_start, "sndbuf_actual", sndbuf_actual);
  366:     }
  367:         
  368:     cJSON *rcvbuf_actual_item = cJSON_GetObjectItem(test->json_start, "rcvbuf_actual");
  369:     if (rcvbuf_actual_item == NULL) {
  370: 	cJSON_AddNumberToObject(test->json_start, "rcvbuf_actual", rcvbuf_actual);
  371:     }
  372:     }
  373: 
  374:     return rc;
  375: }
  376: 
  377: /*
  378:  * iperf_udp_accept
  379:  *
  380:  * Accepts a new UDP "connection"
  381:  */
  382: int
  383: iperf_udp_accept(struct iperf_test *test)
  384: {
  385:     struct sockaddr_storage sa_peer;
  386:     unsigned int buf;
  387:     socklen_t len;
  388:     int       sz, s;
  389:     int	      rc;
  390: 
  391:     /*
  392:      * Get the current outstanding socket.  This socket will be used to handle
  393:      * data transfers and a new "listening" socket will be created.
  394:      */
  395:     s = test->prot_listener;
  396: 
  397:     /*
  398:      * Grab the UDP packet sent by the client.  From that we can extract the
  399:      * client's address, and then use that information to bind the remote side
  400:      * of the socket to the client.
  401:      */
  402:     len = sizeof(sa_peer);
  403:     if ((sz = recvfrom(test->prot_listener, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
  404:         i_errno = IESTREAMACCEPT;
  405:         return -1;
  406:     }
  407: 
  408:     if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) {
  409:         i_errno = IESTREAMACCEPT;
  410:         return -1;
  411:     }
  412: 
  413:     /* Check and set socket buffer sizes */
  414:     rc = iperf_udp_buffercheck(test, s);
  415:     if (rc < 0)
  416: 	/* error */
  417: 	return rc;
  418:     /*
  419:      * If the socket buffer was too small, but it was the default
  420:      * size, then try explicitly setting it to something larger.
  421:      */
  422:     if (rc > 0) {
  423: 	if (test->settings->socket_bufsize == 0) {
  424:             char str[WARN_STR_LEN];
  425: 	    int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA;
  426: 	    snprintf(str, sizeof(str), "Increasing socket buffer size to %d",
  427: 	             bufsize);
  428: 	    warning(str);
  429: 	    test->settings->socket_bufsize = bufsize;
  430: 	    rc = iperf_udp_buffercheck(test, s);
  431: 	    if (rc < 0)
  432: 		return rc;
  433: 	}
  434:     }
  435: 
  436: #if defined(HAVE_SO_MAX_PACING_RATE)
  437:     /* If socket pacing is specified, try it. */
  438:     if (test->settings->fqrate) {
  439: 	/* Convert bits per second to bytes per second */
  440: 	unsigned int fqrate = test->settings->fqrate / 8;
  441: 	if (fqrate > 0) {
  442: 	    if (test->debug) {
  443: 		printf("Setting fair-queue socket pacing to %u\n", fqrate);
  444: 	    }
  445: 	    if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
  446: 		warning("Unable to set socket pacing");
  447: 	    }
  448: 	}
  449:     }
  450: #endif /* HAVE_SO_MAX_PACING_RATE */
  451:     {
  452: 	unsigned int rate = test->settings->rate / 8;
  453: 	if (rate > 0) {
  454: 	    if (test->debug) {
  455: 		printf("Setting application pacing to %u\n", rate);
  456: 	    }
  457: 	}
  458:     }
  459: 
  460:     /*
  461:      * Create a new "listening" socket to replace the one we were using before.
  462:      */
  463:     test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->server_port);
  464:     if (test->prot_listener < 0) {
  465:         i_errno = IESTREAMLISTEN;
  466:         return -1;
  467:     }
  468: 
  469:     FD_SET(test->prot_listener, &test->read_set);
  470:     test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd;
  471: 
  472:     /* Let the client know we're ready "accept" another UDP "stream" */
  473:     buf = UDP_CONNECT_REPLY;
  474:     if (write(s, &buf, sizeof(buf)) < 0) {
  475:         i_errno = IESTREAMWRITE;
  476:         return -1;
  477:     }
  478: 
  479:     return s;
  480: }
  481: 
  482: 
  483: /*
  484:  * iperf_udp_listen
  485:  *
  486:  * Start up a listener for UDP stream connections.  Unlike for TCP,
  487:  * there is no listen(2) for UDP.  This socket will however accept
  488:  * a UDP datagram from a client (indicating the client's presence).
  489:  */
  490: int
  491: iperf_udp_listen(struct iperf_test *test)
  492: {
  493:     int s;
  494: 
  495:     if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->server_port)) < 0) {
  496:         i_errno = IESTREAMLISTEN;
  497:         return -1;
  498:     }
  499: 
  500:     /*
  501:      * The caller will put this value into test->prot_listener.
  502:      */
  503:     return s;
  504: }
  505: 
  506: 
  507: /*
  508:  * iperf_udp_connect
  509:  *
  510:  * "Connect" to a UDP stream listener.
  511:  */
  512: int
  513: iperf_udp_connect(struct iperf_test *test)
  514: {
  515:     int s, sz;
  516:     unsigned int buf;
  517: #ifdef SO_RCVTIMEO
  518:     struct timeval tv;
  519: #endif
  520:     int rc;
  521:     int i, max_len_wait_for_reply;
  522: 
  523:     /* Create and bind our local socket. */
  524:     if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, -1)) < 0) {
  525:         i_errno = IESTREAMCONNECT;
  526:         return -1;
  527:     }
  528: 
  529:     /* Check and set socket buffer sizes */
  530:     rc = iperf_udp_buffercheck(test, s);
  531:     if (rc < 0)
  532: 	/* error */
  533: 	return rc;
  534:     /*
  535:      * If the socket buffer was too small, but it was the default
  536:      * size, then try explicitly setting it to something larger.
  537:      */
  538:     if (rc > 0) {
  539: 	if (test->settings->socket_bufsize == 0) {
  540:             char str[WARN_STR_LEN];
  541: 	    int bufsize = test->settings->blksize + UDP_BUFFER_EXTRA;
  542: 	    snprintf(str, sizeof(str), "Increasing socket buffer size to %d",
  543: 	             bufsize);
  544: 	    warning(str);
  545: 	    test->settings->socket_bufsize = bufsize;
  546: 	    rc = iperf_udp_buffercheck(test, s);
  547: 	    if (rc < 0)
  548: 		return rc;
  549: 	}
  550:     }
  551: 
  552: #if defined(HAVE_SO_MAX_PACING_RATE)
  553:     /* If socket pacing is available and not disabled, try it. */
  554:     if (test->settings->fqrate) {
  555: 	/* Convert bits per second to bytes per second */
  556: 	unsigned int fqrate = test->settings->fqrate / 8;
  557: 	if (fqrate > 0) {
  558: 	    if (test->debug) {
  559: 		printf("Setting fair-queue socket pacing to %u\n", fqrate);
  560: 	    }
  561: 	    if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
  562: 		warning("Unable to set socket pacing");
  563: 	    }
  564: 	}
  565:     }
  566: #endif /* HAVE_SO_MAX_PACING_RATE */
  567:     {
  568: 	unsigned int rate = test->settings->rate / 8;
  569: 	if (rate > 0) {
  570: 	    if (test->debug) {
  571: 		printf("Setting application pacing to %u\n", rate);
  572: 	    }
  573: 	}
  574:     }
  575: 
  576:     /* Set common socket options */
  577:     iperf_common_sockopts(test, s);
  578: 
  579: #ifdef SO_RCVTIMEO
  580:     /* 30 sec timeout for a case when there is a network problem. */
  581:     tv.tv_sec = 30;
  582:     tv.tv_usec = 0;
  583:     setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
  584: #endif
  585: 
  586:     /*
  587:      * Write a datagram to the UDP stream to let the server know we're here.
  588:      * The server learns our address by obtaining its peer's address.
  589:      */
  590:     buf = UDP_CONNECT_MSG;
  591:     if (test->debug) {
  592:         printf("Sending Connect message to Socket %d\n", s);
  593:     }
  594:     if (write(s, &buf, sizeof(buf)) < 0) {
  595:         // XXX: Should this be changed to IESTREAMCONNECT?
  596:         i_errno = IESTREAMWRITE;
  597:         return -1;
  598:     }
  599: 
  600:     /*
  601:      * Wait until the server replies back to us with the "accept" response.
  602:      */
  603:     i = 0;
  604:     max_len_wait_for_reply = sizeof(buf);
  605:     if (test->reverse) /* In reverse mode allow few packets to have the "accept" response - to handle out of order packets */
  606:         max_len_wait_for_reply += MAX_REVERSE_OUT_OF_ORDER_PACKETS * test->settings->blksize;
  607:     do {
  608:         if ((sz = recv(s, &buf, sizeof(buf), 0)) < 0) {
  609:             i_errno = IESTREAMREAD;
  610:             return -1;
  611:         }
  612:         if (test->debug) {
  613:             printf("Connect received for Socket %d, sz=%d, buf=%x, i=%d, max_len_wait_for_reply=%d\n", s, sz, buf, i, max_len_wait_for_reply);
  614:         }
  615:         i += sz;
  616:     } while (buf != UDP_CONNECT_REPLY && buf != LEGACY_UDP_CONNECT_REPLY && i < max_len_wait_for_reply);
  617: 
  618:     if (buf != UDP_CONNECT_REPLY  && buf != LEGACY_UDP_CONNECT_REPLY) {
  619:         i_errno = IESTREAMREAD;
  620:         return -1;
  621:     }
  622: 
  623:     return s;
  624: }
  625: 
  626: 
  627: /* iperf_udp_init
  628:  *
  629:  * initializer for UDP streams in TEST_START
  630:  */
  631: int
  632: iperf_udp_init(struct iperf_test *test)
  633: {
  634:     return 0;
  635: }

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