1a951c980SBrian Tierney /* 2329523a5SBruce A. Mah * Copyright (c) 2009-2011, 2014, The Regents of the University of California, 37d375156SJon Dugan * through Lawrence Berkeley National Laboratory (subject to receipt of any 47d375156SJon Dugan * required approvals from the U.S. Dept. of Energy). All rights reserved. 57d375156SJon Dugan * 67d375156SJon Dugan * This code is distributed under a BSD style license, see the LICENSE file 77d375156SJon Dugan * for complete information. 8a951c980SBrian Tierney */ 9a951c980SBrian Tierney 10a951c980SBrian Tierney #include <stdio.h> 11a951c980SBrian Tierney #include <stdlib.h> 12a951c980SBrian Tierney #include <string.h> 13a951c980SBrian Tierney #include <errno.h> 14a951c980SBrian Tierney #include <unistd.h> 15a951c980SBrian Tierney #include <assert.h> 16a951c980SBrian Tierney #include <sys/socket.h> 17a951c980SBrian Tierney #include <sys/types.h> 18a951c980SBrian Tierney #include <netinet/in.h> 19426221a3SBruce A. Mah #ifdef HAVE_STDINT_H 20a951c980SBrian Tierney #include <stdint.h> 21426221a3SBruce A. Mah #endif 22a951c980SBrian Tierney #include <sys/time.h> 2366ce7ad4Ssethdelliott #include <sys/select.h> 24a951c980SBrian Tierney 25a951c980SBrian Tierney #include "iperf.h" 26a951c980SBrian Tierney #include "iperf_api.h" 279673370fSJef Poskanzer #include "iperf_util.h" 28a951c980SBrian Tierney #include "iperf_udp.h" 29a951c980SBrian Tierney #include "timer.h" 30a951c980SBrian Tierney #include "net.h" 31329523a5SBruce A. Mah #include "portable_endian.h" 32a951c980SBrian Tierney 338a0b5a5dSsethdelliott /* iperf_udp_recv 34a951c980SBrian Tierney * 358a0b5a5dSsethdelliott * receives the data for UDP 36a951c980SBrian Tierney */ 37a951c980SBrian Tierney int 38a951c980SBrian Tierney iperf_udp_recv(struct iperf_stream *sp) 39a951c980SBrian Tierney { 40329523a5SBruce A. Mah uint32_t sec, usec; 41329523a5SBruce A. Mah uint64_t pcount; 4243929b36SJef Poskanzer int r; 43a951c980SBrian Tierney int size = sp->settings->blksize; 44a951c980SBrian Tierney double transit = 0, d = 0; 458556db5dSsethdelliott struct timeval sent_time, arrival_time; 46a951c980SBrian Tierney 4743929b36SJef Poskanzer r = Nread(sp->socket, sp->buffer, size, Pudp); 48a951c980SBrian Tierney 4943929b36SJef Poskanzer if (r < 0) 5043929b36SJef Poskanzer return r; 518a0b5a5dSsethdelliott 5243929b36SJef Poskanzer sp->result->bytes_received += r; 5343929b36SJef Poskanzer sp->result->bytes_received_this_interval += r; 548556db5dSsethdelliott 55329523a5SBruce A. Mah if (sp->test->udp_counters_64bit) { 568556db5dSsethdelliott memcpy(&sec, sp->buffer, sizeof(sec)); 578556db5dSsethdelliott memcpy(&usec, sp->buffer+4, sizeof(usec)); 588556db5dSsethdelliott memcpy(&pcount, sp->buffer+8, sizeof(pcount)); 598556db5dSsethdelliott sec = ntohl(sec); 608556db5dSsethdelliott usec = ntohl(usec); 61329523a5SBruce A. Mah pcount = be64toh(pcount); 628556db5dSsethdelliott sent_time.tv_sec = sec; 638556db5dSsethdelliott sent_time.tv_usec = usec; 64329523a5SBruce A. Mah } 65329523a5SBruce A. Mah else { 66329523a5SBruce A. Mah uint32_t pc; 67329523a5SBruce A. Mah memcpy(&sec, sp->buffer, sizeof(sec)); 68329523a5SBruce A. Mah memcpy(&usec, sp->buffer+4, sizeof(usec)); 69329523a5SBruce A. Mah memcpy(&pc, sp->buffer+8, sizeof(pc)); 70329523a5SBruce A. Mah sec = ntohl(sec); 71329523a5SBruce A. Mah usec = ntohl(usec); 72329523a5SBruce A. Mah pcount = ntohl(pc); 73329523a5SBruce A. Mah sent_time.tv_sec = sec; 74329523a5SBruce A. Mah sent_time.tv_usec = usec; 75329523a5SBruce A. Mah } 768556db5dSsethdelliott 778556db5dSsethdelliott /* Out of order packets */ 788556db5dSsethdelliott if (pcount >= sp->packet_count + 1) { 798556db5dSsethdelliott if (pcount > sp->packet_count + 1) { 808556db5dSsethdelliott sp->cnt_error += (pcount - 1) - sp->packet_count; 818556db5dSsethdelliott } 828556db5dSsethdelliott sp->packet_count = pcount; 838556db5dSsethdelliott } else { 848556db5dSsethdelliott sp->outoforder_packets++; 85329523a5SBruce A. Mah iperf_err(sp->test, "OUT OF ORDER - incoming packet = %llu and received packet = %d AND SP = %d", pcount, sp->packet_count, sp->socket); 868556db5dSsethdelliott } 87a951c980SBrian Tierney 88a951c980SBrian Tierney /* jitter measurement */ 89b60a49ddSsethdelliott gettimeofday(&arrival_time, NULL); 90b60a49ddSsethdelliott 918556db5dSsethdelliott transit = timeval_diff(&sent_time, &arrival_time); 92a951c980SBrian Tierney d = transit - sp->prev_transit; 93a951c980SBrian Tierney if (d < 0) 94a951c980SBrian Tierney d = -d; 95a951c980SBrian Tierney sp->prev_transit = transit; 968556db5dSsethdelliott // XXX: This is NOT the way to calculate jitter 978556db5dSsethdelliott // J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average] 98a951c980SBrian Tierney sp->jitter += (d - sp->jitter) / 16.0; 99a951c980SBrian Tierney 100329523a5SBruce A. Mah if (sp->test->debug) { 101329523a5SBruce A. Mah fprintf(stderr, "packet_count %llu\n", sp->packet_count); 102329523a5SBruce A. Mah } 103329523a5SBruce A. Mah 10443929b36SJef Poskanzer return r; 105ec2d0670SJef Poskanzer } 106ec2d0670SJef Poskanzer 107ec2d0670SJef Poskanzer 1088a0b5a5dSsethdelliott /* iperf_udp_send 1098a0b5a5dSsethdelliott * 1108a0b5a5dSsethdelliott * sends the data for UDP 1118a0b5a5dSsethdelliott */ 112a951c980SBrian Tierney int 113a951c980SBrian Tierney iperf_udp_send(struct iperf_stream *sp) 114a951c980SBrian Tierney { 11543929b36SJef Poskanzer int r; 1168556db5dSsethdelliott int size = sp->settings->blksize; 117647d3b95SJef Poskanzer struct timeval before; 11843929b36SJef Poskanzer 119b60a49ddSsethdelliott gettimeofday(&before, 0); 120b60a49ddSsethdelliott 1218556db5dSsethdelliott ++sp->packet_count; 122329523a5SBruce A. Mah 123329523a5SBruce A. Mah if (sp->test->udp_counters_64bit) { 124329523a5SBruce A. Mah 125329523a5SBruce A. Mah uint32_t sec, usec; 126329523a5SBruce A. Mah uint64_t pcount; 127329523a5SBruce A. Mah 128329523a5SBruce A. Mah sec = htonl(before.tv_sec); 129329523a5SBruce A. Mah usec = htonl(before.tv_usec); 130329523a5SBruce A. Mah pcount = htobe64(sp->packet_count); 131329523a5SBruce A. Mah 132329523a5SBruce A. Mah memcpy(sp->buffer, &sec, sizeof(sec)); 133329523a5SBruce A. Mah memcpy(sp->buffer+4, &usec, sizeof(usec)); 134329523a5SBruce A. Mah memcpy(sp->buffer+8, &pcount, sizeof(pcount)); 135329523a5SBruce A. Mah 136329523a5SBruce A. Mah } 137329523a5SBruce A. Mah else { 138329523a5SBruce A. Mah 139329523a5SBruce A. Mah uint32_t sec, usec, pcount; 140329523a5SBruce A. Mah 1418556db5dSsethdelliott sec = htonl(before.tv_sec); 1428556db5dSsethdelliott usec = htonl(before.tv_usec); 1438556db5dSsethdelliott pcount = htonl(sp->packet_count); 144a951c980SBrian Tierney 1458556db5dSsethdelliott memcpy(sp->buffer, &sec, sizeof(sec)); 1468556db5dSsethdelliott memcpy(sp->buffer+4, &usec, sizeof(usec)); 1478556db5dSsethdelliott memcpy(sp->buffer+8, &pcount, sizeof(pcount)); 148a951c980SBrian Tierney 149329523a5SBruce A. Mah } 150329523a5SBruce A. Mah 15143929b36SJef Poskanzer r = Nwrite(sp->socket, sp->buffer, size, Pudp); 152a951c980SBrian Tierney 15343929b36SJef Poskanzer if (r < 0) 15443929b36SJef Poskanzer return r; 1558556db5dSsethdelliott 15643929b36SJef Poskanzer sp->result->bytes_sent += r; 15743929b36SJef Poskanzer sp->result->bytes_sent_this_interval += r; 158aa89cda2Ssethdelliott 15943929b36SJef Poskanzer return r; 160a951c980SBrian Tierney } 161a951c980SBrian Tierney 162a951c980SBrian Tierney 163a951c980SBrian Tierney /**************************************************************************/ 164a951c980SBrian Tierney 1658a0b5a5dSsethdelliott /* iperf_udp_accept 166a951c980SBrian Tierney * 1678a0b5a5dSsethdelliott * accepts a new UDP connection 168a951c980SBrian Tierney */ 169a951c980SBrian Tierney int 170a951c980SBrian Tierney iperf_udp_accept(struct iperf_test *test) 171a951c980SBrian Tierney { 172111645edSJef Poskanzer struct sockaddr_storage sa_peer; 1738556db5dSsethdelliott int buf; 174a951c980SBrian Tierney socklen_t len; 1758556db5dSsethdelliott int sz, s; 176a951c980SBrian Tierney 1778a0b5a5dSsethdelliott s = test->prot_listener; 178a951c980SBrian Tierney 179111645edSJef Poskanzer len = sizeof(sa_peer); 1808a0b5a5dSsethdelliott if ((sz = recvfrom(test->prot_listener, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) { 181b60a49ddSsethdelliott i_errno = IESTREAMACCEPT; 182ec2d0670SJef Poskanzer return -1; 1838556db5dSsethdelliott } 184a951c980SBrian Tierney 1858556db5dSsethdelliott if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) { 186b60a49ddSsethdelliott i_errno = IESTREAMACCEPT; 187ec2d0670SJef Poskanzer return -1; 188a951c980SBrian Tierney } 189a951c980SBrian Tierney 190f99bd3b2Ssethdelliott test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port); 1918a0b5a5dSsethdelliott if (test->prot_listener < 0) { 1928a0b5a5dSsethdelliott i_errno = IESTREAMLISTEN; 193ec2d0670SJef Poskanzer return -1; 194b60a49ddSsethdelliott } 195a951c980SBrian Tierney 1968a0b5a5dSsethdelliott FD_SET(test->prot_listener, &test->read_set); 1978a0b5a5dSsethdelliott test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd; 198a951c980SBrian Tierney 1998556db5dSsethdelliott /* Let the client know we're ready "accept" another UDP "stream" */ 200111645edSJef Poskanzer buf = 987654321; 2018a0b5a5dSsethdelliott if (write(s, &buf, sizeof(buf)) < 0) { 202b60a49ddSsethdelliott i_errno = IESTREAMWRITE; 203ec2d0670SJef Poskanzer return -1; 204a951c980SBrian Tierney } 205a951c980SBrian Tierney 206ec2d0670SJef Poskanzer return s; 2078a0b5a5dSsethdelliott } 2088a0b5a5dSsethdelliott 2098a0b5a5dSsethdelliott 2108a0b5a5dSsethdelliott /* iperf_udp_listen 2118a0b5a5dSsethdelliott * 2128a0b5a5dSsethdelliott * start up a listener for UDP stream connections 2138a0b5a5dSsethdelliott */ 2148a0b5a5dSsethdelliott int 2158a0b5a5dSsethdelliott iperf_udp_listen(struct iperf_test *test) 2168a0b5a5dSsethdelliott { 2178a0b5a5dSsethdelliott int s; 2188a0b5a5dSsethdelliott 219f99bd3b2Ssethdelliott if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port)) < 0) { 2208a0b5a5dSsethdelliott i_errno = IESTREAMLISTEN; 221ec2d0670SJef Poskanzer return -1; 2228a0b5a5dSsethdelliott } 2238a0b5a5dSsethdelliott 224ec2d0670SJef Poskanzer return s; 2258a0b5a5dSsethdelliott } 2268a0b5a5dSsethdelliott 2278a0b5a5dSsethdelliott 2288a0b5a5dSsethdelliott /* iperf_udp_connect 2298a0b5a5dSsethdelliott * 2308a0b5a5dSsethdelliott * connect to a TCP stream listener 2318a0b5a5dSsethdelliott */ 2328a0b5a5dSsethdelliott int 2338a0b5a5dSsethdelliott iperf_udp_connect(struct iperf_test *test) 2348a0b5a5dSsethdelliott { 235111645edSJef Poskanzer int s, buf, sz; 2368a0b5a5dSsethdelliott 237*023fb45eSKevin Constantine if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_port, test->server_hostname, test->server_port)) < 0) { 2388a0b5a5dSsethdelliott i_errno = IESTREAMCONNECT; 239ec2d0670SJef Poskanzer return -1; 2408a0b5a5dSsethdelliott } 2418a0b5a5dSsethdelliott 242111645edSJef Poskanzer /* Write to the UDP stream to let the server know we're here. */ 243111645edSJef Poskanzer buf = 123456789; 2448a0b5a5dSsethdelliott if (write(s, &buf, sizeof(buf)) < 0) { 2458a0b5a5dSsethdelliott // XXX: Should this be changed to IESTREAMCONNECT? 2468a0b5a5dSsethdelliott i_errno = IESTREAMWRITE; 247ec2d0670SJef Poskanzer return -1; 2488a0b5a5dSsethdelliott } 249111645edSJef Poskanzer 2508a0b5a5dSsethdelliott /* Wait until the server confirms the client UDP write */ 2518a0b5a5dSsethdelliott // XXX: Should this read be TCP instead? 252111645edSJef Poskanzer if ((sz = recv(s, &buf, sizeof(buf), 0)) < 0) { 2538a0b5a5dSsethdelliott i_errno = IESTREAMREAD; 254ec2d0670SJef Poskanzer return -1; 2558a0b5a5dSsethdelliott } 2568a0b5a5dSsethdelliott 257ec2d0670SJef Poskanzer return s; 2588a0b5a5dSsethdelliott } 2598a0b5a5dSsethdelliott 2608a0b5a5dSsethdelliott 2618a0b5a5dSsethdelliott /* iperf_udp_init 2628a0b5a5dSsethdelliott * 2638a0b5a5dSsethdelliott * initializer for UDP streams in TEST_START 2648a0b5a5dSsethdelliott */ 2658a0b5a5dSsethdelliott int 2668a0b5a5dSsethdelliott iperf_udp_init(struct iperf_test *test) 2678a0b5a5dSsethdelliott { 268ec2d0670SJef Poskanzer return 0; 269a951c980SBrian Tierney } 270