xref: /iperf/src/iperf_udp.c (revision 647d3b95)
1a951c980SBrian Tierney /*
27d375156SJon Dugan  * Copyright (c) 2009-2011, 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>
19a951c980SBrian Tierney #include <stdint.h>
20a951c980SBrian Tierney #include <sys/time.h>
2166ce7ad4Ssethdelliott #include <sys/select.h>
22a951c980SBrian Tierney 
23a951c980SBrian Tierney #include "iperf.h"
24a951c980SBrian Tierney #include "iperf_api.h"
259673370fSJef Poskanzer #include "iperf_util.h"
26a951c980SBrian Tierney #include "iperf_udp.h"
27a951c980SBrian Tierney #include "timer.h"
28a951c980SBrian Tierney #include "net.h"
29a951c980SBrian Tierney 
30a951c980SBrian Tierney 
318a0b5a5dSsethdelliott /* iperf_udp_recv
32a951c980SBrian Tierney  *
338a0b5a5dSsethdelliott  * receives the data for UDP
34a951c980SBrian Tierney  */
35a951c980SBrian Tierney int
36a951c980SBrian Tierney iperf_udp_recv(struct iperf_stream *sp)
37a951c980SBrian Tierney {
3843929b36SJef Poskanzer     int       r;
39a951c980SBrian Tierney     int       size = sp->settings->blksize;
408556db5dSsethdelliott     int       sec, usec, pcount;
41a951c980SBrian Tierney     double    transit = 0, d = 0;
428556db5dSsethdelliott     struct timeval sent_time, arrival_time;
43a951c980SBrian Tierney 
4443929b36SJef Poskanzer     r = Nread(sp->socket, sp->buffer, size, Pudp);
45a951c980SBrian Tierney 
4643929b36SJef Poskanzer     if (r < 0)
4743929b36SJef Poskanzer         return r;
488a0b5a5dSsethdelliott 
4943929b36SJef Poskanzer     sp->result->bytes_received += r;
5043929b36SJef Poskanzer     sp->result->bytes_received_this_interval += r;
518556db5dSsethdelliott 
528556db5dSsethdelliott     memcpy(&sec, sp->buffer, sizeof(sec));
538556db5dSsethdelliott     memcpy(&usec, sp->buffer+4, sizeof(usec));
548556db5dSsethdelliott     memcpy(&pcount, sp->buffer+8, sizeof(pcount));
558556db5dSsethdelliott     sec = ntohl(sec);
568556db5dSsethdelliott     usec = ntohl(usec);
578556db5dSsethdelliott     pcount = ntohl(pcount);
588556db5dSsethdelliott     sent_time.tv_sec = sec;
598556db5dSsethdelliott     sent_time.tv_usec = usec;
608556db5dSsethdelliott 
618556db5dSsethdelliott     /* Out of order packets */
628556db5dSsethdelliott     if (pcount >= sp->packet_count + 1) {
638556db5dSsethdelliott         if (pcount > sp->packet_count + 1) {
648556db5dSsethdelliott             sp->cnt_error += (pcount - 1) - sp->packet_count;
658556db5dSsethdelliott         }
668556db5dSsethdelliott         sp->packet_count = pcount;
678556db5dSsethdelliott     } else {
688556db5dSsethdelliott         sp->outoforder_packets++;
69b5e0751fSJef Poskanzer 	iperf_err(sp->test, "OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d", pcount, sp->packet_count, sp->socket);
708556db5dSsethdelliott     }
71a951c980SBrian Tierney 
72a951c980SBrian Tierney     /* jitter measurement */
73b60a49ddSsethdelliott     gettimeofday(&arrival_time, NULL);
74b60a49ddSsethdelliott 
758556db5dSsethdelliott     transit = timeval_diff(&sent_time, &arrival_time);
76a951c980SBrian Tierney     d = transit - sp->prev_transit;
77a951c980SBrian Tierney     if (d < 0)
78a951c980SBrian Tierney         d = -d;
79a951c980SBrian Tierney     sp->prev_transit = transit;
808556db5dSsethdelliott     // XXX: This is NOT the way to calculate jitter
818556db5dSsethdelliott     //      J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average]
82a951c980SBrian Tierney     sp->jitter += (d - sp->jitter) / 16.0;
83a951c980SBrian Tierney 
8443929b36SJef Poskanzer     return r;
85ec2d0670SJef Poskanzer }
86ec2d0670SJef Poskanzer 
87ec2d0670SJef Poskanzer 
888a0b5a5dSsethdelliott /* iperf_udp_send
898a0b5a5dSsethdelliott  *
908a0b5a5dSsethdelliott  * sends the data for UDP
918a0b5a5dSsethdelliott  */
92a951c980SBrian Tierney int
93a951c980SBrian Tierney iperf_udp_send(struct iperf_stream *sp)
94a951c980SBrian Tierney {
9543929b36SJef Poskanzer     int r;
968556db5dSsethdelliott     uint64_t  sec, usec, pcount;
978556db5dSsethdelliott     int       size = sp->settings->blksize;
98*647d3b95SJef Poskanzer     struct timeval before;
9943929b36SJef Poskanzer 
100b60a49ddSsethdelliott     gettimeofday(&before, 0);
101b60a49ddSsethdelliott 
1028556db5dSsethdelliott     ++sp->packet_count;
1038556db5dSsethdelliott     sec = htonl(before.tv_sec);
1048556db5dSsethdelliott     usec = htonl(before.tv_usec);
1058556db5dSsethdelliott     pcount = htonl(sp->packet_count);
106a951c980SBrian Tierney 
1078556db5dSsethdelliott     memcpy(sp->buffer, &sec, sizeof(sec));
1088556db5dSsethdelliott     memcpy(sp->buffer+4, &usec, sizeof(usec));
1098556db5dSsethdelliott     memcpy(sp->buffer+8, &pcount, sizeof(pcount));
110a951c980SBrian Tierney 
11143929b36SJef Poskanzer     r = Nwrite(sp->socket, sp->buffer, size, Pudp);
112a951c980SBrian Tierney 
11343929b36SJef Poskanzer     if (r < 0)
11443929b36SJef Poskanzer 	return r;
1158556db5dSsethdelliott 
11643929b36SJef Poskanzer     sp->result->bytes_sent += r;
11743929b36SJef Poskanzer     sp->result->bytes_sent_this_interval += r;
118aa89cda2Ssethdelliott 
11943929b36SJef Poskanzer     return r;
120a951c980SBrian Tierney }
121a951c980SBrian Tierney 
122a951c980SBrian Tierney 
123a951c980SBrian Tierney /**************************************************************************/
124a951c980SBrian Tierney 
1258a0b5a5dSsethdelliott /* iperf_udp_accept
126a951c980SBrian Tierney  *
1278a0b5a5dSsethdelliott  * accepts a new UDP connection
128a951c980SBrian Tierney  */
129a951c980SBrian Tierney int
130a951c980SBrian Tierney iperf_udp_accept(struct iperf_test *test)
131a951c980SBrian Tierney {
132111645edSJef Poskanzer     struct sockaddr_storage sa_peer;
1338556db5dSsethdelliott     int       buf;
134a951c980SBrian Tierney     socklen_t len;
1358556db5dSsethdelliott     int       sz, s;
136a951c980SBrian Tierney 
1378a0b5a5dSsethdelliott     s = test->prot_listener;
138a951c980SBrian Tierney 
139111645edSJef Poskanzer     len = sizeof(sa_peer);
1408a0b5a5dSsethdelliott     if ((sz = recvfrom(test->prot_listener, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
141b60a49ddSsethdelliott         i_errno = IESTREAMACCEPT;
142ec2d0670SJef Poskanzer         return -1;
1438556db5dSsethdelliott     }
144a951c980SBrian Tierney 
1458556db5dSsethdelliott     if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) {
146b60a49ddSsethdelliott         i_errno = IESTREAMACCEPT;
147ec2d0670SJef Poskanzer         return -1;
148a951c980SBrian Tierney     }
149a951c980SBrian Tierney 
150f99bd3b2Ssethdelliott     test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port);
1518a0b5a5dSsethdelliott     if (test->prot_listener < 0) {
1528a0b5a5dSsethdelliott         i_errno = IESTREAMLISTEN;
153ec2d0670SJef Poskanzer         return -1;
154b60a49ddSsethdelliott     }
155a951c980SBrian Tierney 
1568a0b5a5dSsethdelliott     FD_SET(test->prot_listener, &test->read_set);
1578a0b5a5dSsethdelliott     test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd;
158a951c980SBrian Tierney 
1598556db5dSsethdelliott     /* Let the client know we're ready "accept" another UDP "stream" */
160111645edSJef Poskanzer     buf = 987654321;
1618a0b5a5dSsethdelliott     if (write(s, &buf, sizeof(buf)) < 0) {
162b60a49ddSsethdelliott         i_errno = IESTREAMWRITE;
163ec2d0670SJef Poskanzer         return -1;
164a951c980SBrian Tierney     }
165a951c980SBrian Tierney 
166ec2d0670SJef Poskanzer     return s;
1678a0b5a5dSsethdelliott }
1688a0b5a5dSsethdelliott 
1698a0b5a5dSsethdelliott 
1708a0b5a5dSsethdelliott /* iperf_udp_listen
1718a0b5a5dSsethdelliott  *
1728a0b5a5dSsethdelliott  * start up a listener for UDP stream connections
1738a0b5a5dSsethdelliott  */
1748a0b5a5dSsethdelliott int
1758a0b5a5dSsethdelliott iperf_udp_listen(struct iperf_test *test)
1768a0b5a5dSsethdelliott {
1778a0b5a5dSsethdelliott     int s;
1788a0b5a5dSsethdelliott 
179f99bd3b2Ssethdelliott     if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port)) < 0) {
1808a0b5a5dSsethdelliott         i_errno = IESTREAMLISTEN;
181ec2d0670SJef Poskanzer         return -1;
1828a0b5a5dSsethdelliott     }
1838a0b5a5dSsethdelliott 
184ec2d0670SJef Poskanzer     return s;
1858a0b5a5dSsethdelliott }
1868a0b5a5dSsethdelliott 
1878a0b5a5dSsethdelliott 
1888a0b5a5dSsethdelliott /* iperf_udp_connect
1898a0b5a5dSsethdelliott  *
1908a0b5a5dSsethdelliott  * connect to a TCP stream listener
1918a0b5a5dSsethdelliott  */
1928a0b5a5dSsethdelliott int
1938a0b5a5dSsethdelliott iperf_udp_connect(struct iperf_test *test)
1948a0b5a5dSsethdelliott {
195111645edSJef Poskanzer     int s, buf, sz;
1968a0b5a5dSsethdelliott 
197f99bd3b2Ssethdelliott     if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->server_hostname, test->server_port)) < 0) {
1988a0b5a5dSsethdelliott         i_errno = IESTREAMCONNECT;
199ec2d0670SJef Poskanzer         return -1;
2008a0b5a5dSsethdelliott     }
2018a0b5a5dSsethdelliott 
202111645edSJef Poskanzer     /* Write to the UDP stream to let the server know we're here. */
203111645edSJef Poskanzer     buf = 123456789;
2048a0b5a5dSsethdelliott     if (write(s, &buf, sizeof(buf)) < 0) {
2058a0b5a5dSsethdelliott         // XXX: Should this be changed to IESTREAMCONNECT?
2068a0b5a5dSsethdelliott         i_errno = IESTREAMWRITE;
207ec2d0670SJef Poskanzer         return -1;
2088a0b5a5dSsethdelliott     }
209111645edSJef Poskanzer 
2108a0b5a5dSsethdelliott     /* Wait until the server confirms the client UDP write */
2118a0b5a5dSsethdelliott     // XXX: Should this read be TCP instead?
212111645edSJef Poskanzer     if ((sz = recv(s, &buf, sizeof(buf), 0)) < 0) {
2138a0b5a5dSsethdelliott         i_errno = IESTREAMREAD;
214ec2d0670SJef Poskanzer         return -1;
2158a0b5a5dSsethdelliott     }
2168a0b5a5dSsethdelliott 
217ec2d0670SJef Poskanzer     return s;
2188a0b5a5dSsethdelliott }
2198a0b5a5dSsethdelliott 
2208a0b5a5dSsethdelliott 
2218a0b5a5dSsethdelliott /* iperf_udp_init
2228a0b5a5dSsethdelliott  *
2238a0b5a5dSsethdelliott  * initializer for UDP streams in TEST_START
2248a0b5a5dSsethdelliott  */
2258a0b5a5dSsethdelliott int
2268a0b5a5dSsethdelliott iperf_udp_init(struct iperf_test *test)
2278a0b5a5dSsethdelliott {
228ec2d0670SJef Poskanzer     return 0;
229a951c980SBrian Tierney }
230