xref: /iperf/src/iperf_udp.c (revision b60a49dd)
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 
13a951c980SBrian Tierney #include <stdio.h>
14a951c980SBrian Tierney #include <stdlib.h>
15a951c980SBrian Tierney #include <string.h>
16a951c980SBrian Tierney #include <getopt.h>
17a951c980SBrian Tierney #include <errno.h>
18a951c980SBrian Tierney #include <signal.h>
19a951c980SBrian Tierney #include <unistd.h>
20a951c980SBrian Tierney #include <assert.h>
21a951c980SBrian Tierney #include <fcntl.h>
22a951c980SBrian Tierney #include <sys/socket.h>
23a951c980SBrian Tierney #include <sys/types.h>
24a951c980SBrian Tierney #include <netinet/in.h>
25a951c980SBrian Tierney #include <arpa/inet.h>
26a951c980SBrian Tierney #include <netdb.h>
27a951c980SBrian Tierney #include <pthread.h>
28a951c980SBrian Tierney #include <stdint.h>
29a951c980SBrian Tierney #include <netinet/tcp.h>
30a951c980SBrian Tierney #include <sys/time.h>
31a951c980SBrian Tierney #include <sys/resource.h>
32a951c980SBrian Tierney #include <sched.h>
33a951c980SBrian Tierney #include <signal.h>
34a951c980SBrian Tierney #include <setjmp.h>
35a951c980SBrian Tierney 
36a951c980SBrian Tierney #include "iperf.h"
37a951c980SBrian Tierney #include "iperf_api.h"
38a951c980SBrian Tierney #include "iperf_udp.h"
39*b60a49ddSsethdelliott #include "iperf_error.h"
40a951c980SBrian Tierney #include "timer.h"
41a951c980SBrian Tierney #include "net.h"
42a951c980SBrian Tierney #include "locale.h"
43a951c980SBrian Tierney 
44a951c980SBrian Tierney 
45a951c980SBrian Tierney /**************************************************************************/
46a951c980SBrian Tierney 
47a951c980SBrian Tierney /**
48a951c980SBrian Tierney  * iperf_udp_recv -- receives the client data for UDP
49a951c980SBrian Tierney  *
50a951c980SBrian Tierney  *returns state of packet received
51a951c980SBrian Tierney  *
52a951c980SBrian Tierney  */
53a951c980SBrian Tierney 
54a951c980SBrian Tierney int
55a951c980SBrian Tierney iperf_udp_recv(struct iperf_stream *sp)
56a951c980SBrian Tierney {
578556db5dSsethdelliott     int       result;
58a951c980SBrian Tierney     int       size = sp->settings->blksize;
598556db5dSsethdelliott     int       sec, usec, pcount;
60a951c980SBrian Tierney     double    transit = 0, d = 0;
618556db5dSsethdelliott     struct timeval sent_time, arrival_time;
62a951c980SBrian Tierney 
63a951c980SBrian Tierney #ifdef USE_SEND
648556db5dSsethdelliott     do {
65a951c980SBrian Tierney         result = recv(sp->socket, sp->buffer, size, 0);
66a951c980SBrian Tierney     } while (result == -1 && errno == EINTR);
67a951c980SBrian Tierney #else
68a951c980SBrian Tierney     result = Nread(sp->socket, sp->buffer, size, Pudp);
69a951c980SBrian Tierney #endif
70a951c980SBrian Tierney 
718556db5dSsethdelliott     if (result < 0) {
728556db5dSsethdelliott         return (-1);
73a951c980SBrian Tierney     }
74a951c980SBrian Tierney     sp->result->bytes_received += result;
758556db5dSsethdelliott     sp->result->bytes_received_this_interval += result;
768556db5dSsethdelliott 
778556db5dSsethdelliott     memcpy(&sec, sp->buffer, sizeof(sec));
788556db5dSsethdelliott     memcpy(&usec, sp->buffer+4, sizeof(usec));
798556db5dSsethdelliott     memcpy(&pcount, sp->buffer+8, sizeof(pcount));
808556db5dSsethdelliott     sec = ntohl(sec);
818556db5dSsethdelliott     usec = ntohl(usec);
828556db5dSsethdelliott     pcount = ntohl(pcount);
838556db5dSsethdelliott     sent_time.tv_sec = sec;
848556db5dSsethdelliott     sent_time.tv_usec = usec;
858556db5dSsethdelliott 
868556db5dSsethdelliott     /* Out of order packets */
878556db5dSsethdelliott     if (pcount >= sp->packet_count + 1) {
888556db5dSsethdelliott         if (pcount > sp->packet_count + 1) {
898556db5dSsethdelliott             sp->cnt_error += (pcount - 1) - sp->packet_count;
908556db5dSsethdelliott         }
918556db5dSsethdelliott         sp->packet_count = pcount;
928556db5dSsethdelliott     } else {
938556db5dSsethdelliott         sp->outoforder_packets++;
948556db5dSsethdelliott         printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", pcount, sp->packet_count, sp->socket);
958556db5dSsethdelliott     }
96a951c980SBrian Tierney 
97a951c980SBrian Tierney     /* jitter measurement */
98*b60a49ddSsethdelliott     gettimeofday(&arrival_time, NULL);
99*b60a49ddSsethdelliott 
1008556db5dSsethdelliott     transit = timeval_diff(&sent_time, &arrival_time);
101a951c980SBrian Tierney     d = transit - sp->prev_transit;
102a951c980SBrian Tierney     if (d < 0)
103a951c980SBrian Tierney         d = -d;
104a951c980SBrian Tierney     sp->prev_transit = transit;
1058556db5dSsethdelliott     // XXX: This is NOT the way to calculate jitter
1068556db5dSsethdelliott     //      J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average]
107a951c980SBrian Tierney     sp->jitter += (d - sp->jitter) / 16.0;
108a951c980SBrian Tierney 
1098556db5dSsethdelliott     return result;
110a951c980SBrian Tierney }
111a951c980SBrian Tierney 
112a951c980SBrian Tierney 
113a951c980SBrian Tierney /**************************************************************************/
114a951c980SBrian Tierney int
115a951c980SBrian Tierney iperf_udp_send(struct iperf_stream *sp)
116a951c980SBrian Tierney {
1178556db5dSsethdelliott     ssize_t   result = 0;
118a951c980SBrian Tierney     int64_t   dtargus;
119a951c980SBrian Tierney     int64_t   adjustus = 0;
1208556db5dSsethdelliott     uint64_t  sec, usec, pcount;
1218556db5dSsethdelliott     int       size = sp->settings->blksize;
1228556db5dSsethdelliott     struct timeval before, after;
123a951c980SBrian Tierney 
124aa89cda2Ssethdelliott     if (timer_expired(sp->send_timer)) {
125a951c980SBrian Tierney 
126a951c980SBrian Tierney         dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8;
127a951c980SBrian Tierney         dtargus /= sp->settings->rate;
128a951c980SBrian Tierney 
129a951c980SBrian Tierney         assert(dtargus != 0);
130aa89cda2Ssethdelliott 
131*b60a49ddSsethdelliott         gettimeofday(&before, 0);
132*b60a49ddSsethdelliott 
1338556db5dSsethdelliott         ++sp->packet_count;
1348556db5dSsethdelliott         sec = htonl(before.tv_sec);
1358556db5dSsethdelliott         usec = htonl(before.tv_usec);
1368556db5dSsethdelliott         pcount = htonl(sp->packet_count);
137a951c980SBrian Tierney 
1388556db5dSsethdelliott         memcpy(sp->buffer, &sec, sizeof(sec));
1398556db5dSsethdelliott         memcpy(sp->buffer+4, &usec, sizeof(usec));
1408556db5dSsethdelliott         memcpy(sp->buffer+8, &pcount, sizeof(pcount));
141a951c980SBrian Tierney 
142a951c980SBrian Tierney #ifdef USE_SEND
143a951c980SBrian Tierney         result = send(sp->socket, sp->buffer, size, 0);
144a951c980SBrian Tierney #else
145a951c980SBrian Tierney         result = Nwrite(sp->socket, sp->buffer, size, Pudp);
146a951c980SBrian Tierney #endif
147a951c980SBrian Tierney 
1488556db5dSsethdelliott         if (result < 0)
149*b60a49ddSsethdelliott             return (-1);
1508556db5dSsethdelliott 
1518556db5dSsethdelliott         sp->result->bytes_sent += result;
1528556db5dSsethdelliott         sp->result->bytes_sent_this_interval += result;
153aa89cda2Ssethdelliott 
154*b60a49ddSsethdelliott         gettimeofday(&after, 0);
155a951c980SBrian Tierney 
156a951c980SBrian Tierney         adjustus = dtargus;
157a951c980SBrian Tierney         adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US;
158a951c980SBrian Tierney         adjustus += (before.tv_usec - after.tv_usec);
159a951c980SBrian Tierney 
1608556db5dSsethdelliott         if (adjustus > 0) {
161a951c980SBrian Tierney             dtargus = adjustus;
162a951c980SBrian Tierney         }
163aa89cda2Ssethdelliott 
164*b60a49ddSsethdelliott         if (update_timer(sp->send_timer, 0, dtargus) < 0)
165*b60a49ddSsethdelliott             return (-1);
166aa89cda2Ssethdelliott     }
167aa89cda2Ssethdelliott 
168a951c980SBrian Tierney     return result;
169a951c980SBrian Tierney }
170a951c980SBrian Tierney 
171a951c980SBrian Tierney /**************************************************************************/
172a951c980SBrian Tierney struct iperf_stream *
173a951c980SBrian Tierney iperf_new_udp_stream(struct iperf_test * testp)
174a951c980SBrian Tierney {
175a951c980SBrian Tierney     struct iperf_stream *sp;
176a951c980SBrian Tierney 
177a951c980SBrian Tierney     sp = (struct iperf_stream *) iperf_new_stream(testp);
1788556db5dSsethdelliott     if (!sp) {
179a951c980SBrian Tierney         return (NULL);
180a951c980SBrian Tierney     }
181a951c980SBrian Tierney     sp->rcv = iperf_udp_recv;
182a951c980SBrian Tierney     sp->snd = iperf_udp_send;
183a951c980SBrian Tierney 
184a951c980SBrian Tierney     return sp;
185a951c980SBrian Tierney }
186a951c980SBrian Tierney 
187a951c980SBrian Tierney /**************************************************************************/
188a951c980SBrian Tierney 
189a951c980SBrian Tierney /**
190a951c980SBrian Tierney  * iperf_udp_accept -- accepts a new UDP connection
191a951c980SBrian Tierney  * on udp_listener_socket
192a951c980SBrian Tierney  *returns 0 on success
193a951c980SBrian Tierney  *
194a951c980SBrian Tierney  */
195a951c980SBrian Tierney 
196a951c980SBrian Tierney 
197a951c980SBrian Tierney int
198a951c980SBrian Tierney iperf_udp_accept(struct iperf_test *test)
199a951c980SBrian Tierney {
200a951c980SBrian Tierney     struct iperf_stream *sp;
201a951c980SBrian Tierney     struct sockaddr_in sa_peer;
2028556db5dSsethdelliott     int       buf;
203a951c980SBrian Tierney     socklen_t len;
2048556db5dSsethdelliott     int       sz, s;
205a951c980SBrian Tierney 
2068556db5dSsethdelliott     s = test->listener_udp;
207a951c980SBrian Tierney 
208a951c980SBrian Tierney     len = sizeof sa_peer;
2098556db5dSsethdelliott     if ((sz = recvfrom(test->listener_udp, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
210*b60a49ddSsethdelliott         i_errno = IESTREAMACCEPT;
2118556db5dSsethdelliott         return (-1);
2128556db5dSsethdelliott     }
213a951c980SBrian Tierney 
2148556db5dSsethdelliott     if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) {
215*b60a49ddSsethdelliott         i_errno = IESTREAMACCEPT;
216*b60a49ddSsethdelliott         return (-1);
217a951c980SBrian Tierney     }
2188556db5dSsethdelliott 
219a951c980SBrian Tierney     sp = test->new_stream(test);
2208556db5dSsethdelliott     if (!sp)
2218556db5dSsethdelliott         return (-1);
2228556db5dSsethdelliott     sp->socket = s;
223*b60a49ddSsethdelliott     if (iperf_init_stream(sp, test) < 0)
224*b60a49ddSsethdelliott         return (-1);
225a951c980SBrian Tierney     iperf_add_stream(test, sp);
2268556db5dSsethdelliott     FD_SET(s, &test->read_set);
2278556db5dSsethdelliott     FD_SET(s, &test->write_set);
2288556db5dSsethdelliott     test->max_fd = (s > test->max_fd) ? s : test->max_fd;
229a951c980SBrian Tierney 
2308556db5dSsethdelliott     test->listener_udp = netannounce(Pudp, NULL, test->server_port);
231*b60a49ddSsethdelliott     if (test->listener_udp < 0) {
232*b60a49ddSsethdelliott         i_errno = IELISTEN;
233*b60a49ddSsethdelliott         return (-1);
234*b60a49ddSsethdelliott     }
235a951c980SBrian Tierney 
2368556db5dSsethdelliott     FD_SET(test->listener_udp, &test->read_set);
2378556db5dSsethdelliott     test->max_fd = (test->max_fd < test->listener_udp) ? test->listener_udp : test->max_fd;
238a951c980SBrian Tierney 
2398556db5dSsethdelliott     /* Let the client know we're ready "accept" another UDP "stream" */
2408556db5dSsethdelliott     if (write(sp->socket, &buf, sizeof(buf)) < 0) {
241*b60a49ddSsethdelliott         i_errno = IESTREAMWRITE;
242*b60a49ddSsethdelliott         return (-1);
243a951c980SBrian Tierney     }
244a951c980SBrian Tierney 
2458556db5dSsethdelliott     connect_msg(sp);
2468556db5dSsethdelliott     test->streams_accepted++;
247a951c980SBrian Tierney 
248*b60a49ddSsethdelliott     return (0);
249a951c980SBrian Tierney }
250a951c980SBrian Tierney 
251