xref: /iperf/src/iperf_udp.c (revision 8a0b5a5d)
1a951c980SBrian Tierney 
2a951c980SBrian Tierney /*
3a951c980SBrian Tierney  * Copyright (c) 2009, The Regents of the University of California, through
4a951c980SBrian Tierney  * Lawrence Berkeley National Laboratory (subject to receipt of any required
5a951c980SBrian Tierney  * approvals from the U.S. Dept. of Energy).  All rights reserved.
6a951c980SBrian Tierney  */
7a951c980SBrian Tierney 
8a951c980SBrian Tierney /* iperf_udp.c:  UDP specific routines for iperf
9a951c980SBrian Tierney  *
10a951c980SBrian Tierney  * NOTE: not yet finished / working
11a951c980SBrian Tierney  */
12a951c980SBrian Tierney 
13*8a0b5a5dSsethdelliott // XXX: Do we really need all these headers?
14a951c980SBrian Tierney #include <stdio.h>
15a951c980SBrian Tierney #include <stdlib.h>
16a951c980SBrian Tierney #include <string.h>
17a951c980SBrian Tierney #include <getopt.h>
18a951c980SBrian Tierney #include <errno.h>
19a951c980SBrian Tierney #include <signal.h>
20a951c980SBrian Tierney #include <unistd.h>
21a951c980SBrian Tierney #include <assert.h>
22a951c980SBrian Tierney #include <fcntl.h>
23a951c980SBrian Tierney #include <sys/socket.h>
24a951c980SBrian Tierney #include <sys/types.h>
25a951c980SBrian Tierney #include <netinet/in.h>
26a951c980SBrian Tierney #include <arpa/inet.h>
27a951c980SBrian Tierney #include <netdb.h>
28a951c980SBrian Tierney #include <pthread.h>
29a951c980SBrian Tierney #include <stdint.h>
30a951c980SBrian Tierney #include <netinet/tcp.h>
31a951c980SBrian Tierney #include <sys/time.h>
32a951c980SBrian Tierney #include <sys/resource.h>
33a951c980SBrian Tierney #include <sched.h>
34a951c980SBrian Tierney #include <signal.h>
35a951c980SBrian Tierney #include <setjmp.h>
36a951c980SBrian Tierney 
37a951c980SBrian Tierney #include "iperf.h"
38a951c980SBrian Tierney #include "iperf_api.h"
39a951c980SBrian Tierney #include "iperf_udp.h"
40b60a49ddSsethdelliott #include "iperf_error.h"
41a951c980SBrian Tierney #include "timer.h"
42a951c980SBrian Tierney #include "net.h"
43a951c980SBrian Tierney #include "locale.h"
44a951c980SBrian Tierney 
45a951c980SBrian Tierney 
46*8a0b5a5dSsethdelliott /* iperf_udp_recv
47a951c980SBrian Tierney  *
48*8a0b5a5dSsethdelliott  * receives the data for UDP
49a951c980SBrian Tierney  */
50a951c980SBrian Tierney int
51a951c980SBrian Tierney iperf_udp_recv(struct iperf_stream *sp)
52a951c980SBrian Tierney {
538556db5dSsethdelliott     int       result;
54a951c980SBrian Tierney     int       size = sp->settings->blksize;
558556db5dSsethdelliott     int       sec, usec, pcount;
56a951c980SBrian Tierney     double    transit = 0, d = 0;
578556db5dSsethdelliott     struct timeval sent_time, arrival_time;
58a951c980SBrian Tierney 
59a951c980SBrian Tierney     result = Nread(sp->socket, sp->buffer, size, Pudp);
60a951c980SBrian Tierney 
618556db5dSsethdelliott     if (result < 0) {
628556db5dSsethdelliott         return (-1);
63a951c980SBrian Tierney     }
64*8a0b5a5dSsethdelliott 
65a951c980SBrian Tierney     sp->result->bytes_received += result;
668556db5dSsethdelliott     sp->result->bytes_received_this_interval += result;
678556db5dSsethdelliott 
688556db5dSsethdelliott     memcpy(&sec, sp->buffer, sizeof(sec));
698556db5dSsethdelliott     memcpy(&usec, sp->buffer+4, sizeof(usec));
708556db5dSsethdelliott     memcpy(&pcount, sp->buffer+8, sizeof(pcount));
718556db5dSsethdelliott     sec = ntohl(sec);
728556db5dSsethdelliott     usec = ntohl(usec);
738556db5dSsethdelliott     pcount = ntohl(pcount);
748556db5dSsethdelliott     sent_time.tv_sec = sec;
758556db5dSsethdelliott     sent_time.tv_usec = usec;
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++;
858556db5dSsethdelliott         printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", 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 
100*8a0b5a5dSsethdelliott     return (result);
101a951c980SBrian Tierney }
102a951c980SBrian Tierney 
103a951c980SBrian Tierney 
104*8a0b5a5dSsethdelliott /* iperf_udp_send
105*8a0b5a5dSsethdelliott  *
106*8a0b5a5dSsethdelliott  * sends the data for UDP
107*8a0b5a5dSsethdelliott  */
108a951c980SBrian Tierney int
109a951c980SBrian Tierney iperf_udp_send(struct iperf_stream *sp)
110a951c980SBrian Tierney {
1118556db5dSsethdelliott     ssize_t   result = 0;
112a951c980SBrian Tierney     int64_t   dtargus;
113a951c980SBrian Tierney     int64_t   adjustus = 0;
1148556db5dSsethdelliott     uint64_t  sec, usec, pcount;
1158556db5dSsethdelliott     int       size = sp->settings->blksize;
1168556db5dSsethdelliott     struct timeval before, after;
117a951c980SBrian Tierney 
118aa89cda2Ssethdelliott     if (timer_expired(sp->send_timer)) {
119a951c980SBrian Tierney 
120a951c980SBrian Tierney         dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8;
121a951c980SBrian Tierney         dtargus /= sp->settings->rate;
122a951c980SBrian Tierney 
123a951c980SBrian Tierney         assert(dtargus != 0);
124aa89cda2Ssethdelliott 
125b60a49ddSsethdelliott         gettimeofday(&before, 0);
126b60a49ddSsethdelliott 
1278556db5dSsethdelliott         ++sp->packet_count;
1288556db5dSsethdelliott         sec = htonl(before.tv_sec);
1298556db5dSsethdelliott         usec = htonl(before.tv_usec);
1308556db5dSsethdelliott         pcount = htonl(sp->packet_count);
131a951c980SBrian Tierney 
1328556db5dSsethdelliott         memcpy(sp->buffer, &sec, sizeof(sec));
1338556db5dSsethdelliott         memcpy(sp->buffer+4, &usec, sizeof(usec));
1348556db5dSsethdelliott         memcpy(sp->buffer+8, &pcount, sizeof(pcount));
135a951c980SBrian Tierney 
136a951c980SBrian Tierney         result = Nwrite(sp->socket, sp->buffer, size, Pudp);
137a951c980SBrian Tierney 
1388556db5dSsethdelliott         if (result < 0)
139b60a49ddSsethdelliott             return (-1);
1408556db5dSsethdelliott 
1418556db5dSsethdelliott         sp->result->bytes_sent += result;
1428556db5dSsethdelliott         sp->result->bytes_sent_this_interval += result;
143aa89cda2Ssethdelliott 
144b60a49ddSsethdelliott         gettimeofday(&after, 0);
145a951c980SBrian Tierney 
146a951c980SBrian Tierney         adjustus = dtargus;
147a951c980SBrian Tierney         adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US;
148a951c980SBrian Tierney         adjustus += (before.tv_usec - after.tv_usec);
149a951c980SBrian Tierney 
1508556db5dSsethdelliott         if (adjustus > 0) {
151a951c980SBrian Tierney             dtargus = adjustus;
152a951c980SBrian Tierney         }
153aa89cda2Ssethdelliott 
154b60a49ddSsethdelliott         if (update_timer(sp->send_timer, 0, dtargus) < 0)
155b60a49ddSsethdelliott             return (-1);
156aa89cda2Ssethdelliott     }
157aa89cda2Ssethdelliott 
158*8a0b5a5dSsethdelliott     return (result);
159a951c980SBrian Tierney }
160a951c980SBrian Tierney 
161a951c980SBrian Tierney /**************************************************************************/
162*8a0b5a5dSsethdelliott // XXX: This function is deprecated
163a951c980SBrian Tierney struct iperf_stream *
164a951c980SBrian Tierney iperf_new_udp_stream(struct iperf_test * testp)
165a951c980SBrian Tierney {
166a951c980SBrian Tierney     struct iperf_stream *sp;
167a951c980SBrian Tierney 
168a951c980SBrian Tierney     sp = (struct iperf_stream *) iperf_new_stream(testp);
1698556db5dSsethdelliott     if (!sp) {
170a951c980SBrian Tierney         return (NULL);
171a951c980SBrian Tierney     }
172a951c980SBrian Tierney     sp->rcv = iperf_udp_recv;
173a951c980SBrian Tierney     sp->snd = iperf_udp_send;
174a951c980SBrian Tierney 
175a951c980SBrian Tierney     return sp;
176a951c980SBrian Tierney }
177a951c980SBrian Tierney 
178a951c980SBrian Tierney /**************************************************************************/
179a951c980SBrian Tierney 
180*8a0b5a5dSsethdelliott /* iperf_udp_accept
181a951c980SBrian Tierney  *
182*8a0b5a5dSsethdelliott  * accepts a new UDP connection
183a951c980SBrian Tierney  */
184a951c980SBrian Tierney int
185a951c980SBrian Tierney iperf_udp_accept(struct iperf_test *test)
186a951c980SBrian Tierney {
187a951c980SBrian Tierney     struct iperf_stream *sp;
188a951c980SBrian Tierney     struct sockaddr_in sa_peer;
1898556db5dSsethdelliott     int       buf;
190a951c980SBrian Tierney     socklen_t len;
1918556db5dSsethdelliott     int       sz, s;
192a951c980SBrian Tierney 
193*8a0b5a5dSsethdelliott     s = test->prot_listener;
194a951c980SBrian Tierney 
195a951c980SBrian Tierney     len = sizeof sa_peer;
196*8a0b5a5dSsethdelliott     if ((sz = recvfrom(test->prot_listener, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
197b60a49ddSsethdelliott         i_errno = IESTREAMACCEPT;
1988556db5dSsethdelliott         return (-1);
1998556db5dSsethdelliott     }
200a951c980SBrian Tierney 
2018556db5dSsethdelliott     if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) {
202b60a49ddSsethdelliott         i_errno = IESTREAMACCEPT;
203b60a49ddSsethdelliott         return (-1);
204a951c980SBrian Tierney     }
205*8a0b5a5dSsethdelliott /*
206a951c980SBrian Tierney     sp = test->new_stream(test);
2078556db5dSsethdelliott     if (!sp)
2088556db5dSsethdelliott         return (-1);
2098556db5dSsethdelliott     sp->socket = s;
210b60a49ddSsethdelliott     if (iperf_init_stream(sp, test) < 0)
211b60a49ddSsethdelliott         return (-1);
212a951c980SBrian Tierney     iperf_add_stream(test, sp);
2138556db5dSsethdelliott     FD_SET(s, &test->read_set);
2148556db5dSsethdelliott     FD_SET(s, &test->write_set);
2158556db5dSsethdelliott     test->max_fd = (s > test->max_fd) ? s : test->max_fd;
216*8a0b5a5dSsethdelliott */
217a951c980SBrian Tierney 
218*8a0b5a5dSsethdelliott     test->prot_listener = netannounce(Pudp, NULL, test->server_port);
219*8a0b5a5dSsethdelliott     if (test->prot_listener < 0) {
220*8a0b5a5dSsethdelliott         i_errno = IESTREAMLISTEN;
221b60a49ddSsethdelliott         return (-1);
222b60a49ddSsethdelliott     }
223a951c980SBrian Tierney 
224*8a0b5a5dSsethdelliott     FD_SET(test->prot_listener, &test->read_set);
225*8a0b5a5dSsethdelliott     test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd;
226a951c980SBrian Tierney 
2278556db5dSsethdelliott     /* Let the client know we're ready "accept" another UDP "stream" */
228*8a0b5a5dSsethdelliott     if (write(s, &buf, sizeof(buf)) < 0) {
229b60a49ddSsethdelliott         i_errno = IESTREAMWRITE;
230b60a49ddSsethdelliott         return (-1);
231a951c980SBrian Tierney     }
232a951c980SBrian Tierney 
233*8a0b5a5dSsethdelliott     return (s);
234*8a0b5a5dSsethdelliott }
235*8a0b5a5dSsethdelliott 
236*8a0b5a5dSsethdelliott 
237*8a0b5a5dSsethdelliott /* iperf_udp_listen
238*8a0b5a5dSsethdelliott  *
239*8a0b5a5dSsethdelliott  * start up a listener for UDP stream connections
240*8a0b5a5dSsethdelliott  */
241*8a0b5a5dSsethdelliott int
242*8a0b5a5dSsethdelliott iperf_udp_listen(struct iperf_test *test)
243*8a0b5a5dSsethdelliott {
244*8a0b5a5dSsethdelliott     int s;
245*8a0b5a5dSsethdelliott 
246*8a0b5a5dSsethdelliott     if ((s = netannounce(Pudp, NULL, test->server_port)) < 0) {
247*8a0b5a5dSsethdelliott         i_errno = IESTREAMLISTEN;
248*8a0b5a5dSsethdelliott         return (-1);
249*8a0b5a5dSsethdelliott     }
250*8a0b5a5dSsethdelliott 
251*8a0b5a5dSsethdelliott     return (s);
252*8a0b5a5dSsethdelliott }
253*8a0b5a5dSsethdelliott 
254*8a0b5a5dSsethdelliott 
255*8a0b5a5dSsethdelliott /* iperf_udp_connect
256*8a0b5a5dSsethdelliott  *
257*8a0b5a5dSsethdelliott  * connect to a TCP stream listener
258*8a0b5a5dSsethdelliott  */
259*8a0b5a5dSsethdelliott int
260*8a0b5a5dSsethdelliott iperf_udp_connect(struct iperf_test *test)
261*8a0b5a5dSsethdelliott {
262*8a0b5a5dSsethdelliott     int s, buf;
263*8a0b5a5dSsethdelliott 
264*8a0b5a5dSsethdelliott     if ((s = netdial(Pudp, test->server_hostname, test->server_port)) < 0) {
265*8a0b5a5dSsethdelliott         i_errno = IESTREAMCONNECT;
266*8a0b5a5dSsethdelliott         return (-1);
267*8a0b5a5dSsethdelliott     }
268*8a0b5a5dSsethdelliott 
269*8a0b5a5dSsethdelliott     /* Write to the UDP stream to give the server this stream's credentials */
270*8a0b5a5dSsethdelliott     if (write(s, &buf, sizeof(buf)) < 0) {
271*8a0b5a5dSsethdelliott         // XXX: Should this be changed to IESTREAMCONNECT?
272*8a0b5a5dSsethdelliott         i_errno = IESTREAMWRITE;
273*8a0b5a5dSsethdelliott         return (-1);
274*8a0b5a5dSsethdelliott     }
275*8a0b5a5dSsethdelliott     /* Wait until the server confirms the client UDP write */
276*8a0b5a5dSsethdelliott     // XXX: Should this read be TCP instead?
277*8a0b5a5dSsethdelliott     if (read(s, &buf, sizeof(buf)) < 0) {
278*8a0b5a5dSsethdelliott         i_errno = IESTREAMREAD;
279*8a0b5a5dSsethdelliott         return (-1);
280*8a0b5a5dSsethdelliott     }
281*8a0b5a5dSsethdelliott 
282*8a0b5a5dSsethdelliott     return (s);
283*8a0b5a5dSsethdelliott }
284*8a0b5a5dSsethdelliott 
285*8a0b5a5dSsethdelliott 
286*8a0b5a5dSsethdelliott /* iperf_udp_init
287*8a0b5a5dSsethdelliott  *
288*8a0b5a5dSsethdelliott  * initializer for UDP streams in TEST_START
289*8a0b5a5dSsethdelliott  */
290*8a0b5a5dSsethdelliott int
291*8a0b5a5dSsethdelliott iperf_udp_init(struct iperf_test *test)
292*8a0b5a5dSsethdelliott {
293*8a0b5a5dSsethdelliott     int64_t dtargus;
294*8a0b5a5dSsethdelliott     struct iperf_stream *sp;
295*8a0b5a5dSsethdelliott 
296*8a0b5a5dSsethdelliott     /* Calculate the send delay needed to hit target bandwidth (-b) */
297*8a0b5a5dSsethdelliott     dtargus = (int64_t) test->default_settings->blksize * SEC_TO_US * 8;
298*8a0b5a5dSsethdelliott     dtargus /= test->default_settings->rate;
299*8a0b5a5dSsethdelliott 
300*8a0b5a5dSsethdelliott     assert(dtargus != 0);
301*8a0b5a5dSsethdelliott 
302*8a0b5a5dSsethdelliott     for (sp = test->streams; sp; sp = sp->next) {
303*8a0b5a5dSsethdelliott         sp->send_timer = new_timer(dtargus / SEC_TO_US, dtargus % SEC_TO_US);
304*8a0b5a5dSsethdelliott         if (sp->send_timer == NULL)
305*8a0b5a5dSsethdelliott             return (-1);
306*8a0b5a5dSsethdelliott     }
307a951c980SBrian Tierney 
308b60a49ddSsethdelliott     return (0);
309a951c980SBrian Tierney }
310