xref: /iperf/src/iperf_udp.c (revision aa89cda2)
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"
39a951c980SBrian Tierney #include "timer.h"
40a951c980SBrian Tierney #include "net.h"
41a951c980SBrian Tierney #include "locale.h"
42a951c980SBrian Tierney 
43a951c980SBrian Tierney 
44a951c980SBrian Tierney /**************************************************************************/
45a951c980SBrian Tierney 
46a951c980SBrian Tierney /**
47a951c980SBrian Tierney  * iperf_udp_recv -- receives the client data for UDP
48a951c980SBrian Tierney  *
49a951c980SBrian Tierney  *returns state of packet received
50a951c980SBrian Tierney  *
51a951c980SBrian Tierney  */
52a951c980SBrian Tierney 
53a951c980SBrian Tierney int
54a951c980SBrian Tierney iperf_udp_recv(struct iperf_stream *sp)
55a951c980SBrian Tierney {
568556db5dSsethdelliott     int       result;
57a951c980SBrian Tierney     int       size = sp->settings->blksize;
588556db5dSsethdelliott     int       sec, usec, pcount;
59a951c980SBrian Tierney     double    transit = 0, d = 0;
608556db5dSsethdelliott     struct timeval sent_time, arrival_time;
61a951c980SBrian Tierney 
62a951c980SBrian Tierney #ifdef USE_SEND
638556db5dSsethdelliott     do {
64a951c980SBrian Tierney         result = recv(sp->socket, sp->buffer, size, 0);
65a951c980SBrian Tierney     } while (result == -1 && errno == EINTR);
66a951c980SBrian Tierney #else
67a951c980SBrian Tierney     result = Nread(sp->socket, sp->buffer, size, Pudp);
68a951c980SBrian Tierney #endif
69a951c980SBrian Tierney 
708556db5dSsethdelliott     if (result < 0) {
718556db5dSsethdelliott         perror("Nread udp result");
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 */
988556db5dSsethdelliott     if (gettimeofday(&arrival_time, NULL) < 0) {
99a951c980SBrian Tierney         perror("gettimeofday");
100a951c980SBrian Tierney     }
1018556db5dSsethdelliott     transit = timeval_diff(&sent_time, &arrival_time);
102a951c980SBrian Tierney     d = transit - sp->prev_transit;
103a951c980SBrian Tierney     if (d < 0)
104a951c980SBrian Tierney         d = -d;
105a951c980SBrian Tierney     sp->prev_transit = transit;
1068556db5dSsethdelliott     // XXX: This is NOT the way to calculate jitter
1078556db5dSsethdelliott     //      J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average]
108a951c980SBrian Tierney     sp->jitter += (d - sp->jitter) / 16.0;
109a951c980SBrian Tierney 
1108556db5dSsethdelliott     return result;
111a951c980SBrian Tierney }
112a951c980SBrian Tierney 
113a951c980SBrian Tierney 
114a951c980SBrian Tierney /**************************************************************************/
115a951c980SBrian Tierney int
116a951c980SBrian Tierney iperf_udp_send(struct iperf_stream *sp)
117a951c980SBrian Tierney {
1188556db5dSsethdelliott     ssize_t   result = 0;
119a951c980SBrian Tierney     int64_t   dtargus;
120a951c980SBrian Tierney     int64_t   adjustus = 0;
1218556db5dSsethdelliott     uint64_t  sec, usec, pcount;
1228556db5dSsethdelliott     int       size = sp->settings->blksize;
1238556db5dSsethdelliott     struct timeval before, after;
124a951c980SBrian Tierney 
125*aa89cda2Ssethdelliott     if (timer_expired(sp->send_timer)) {
126a951c980SBrian Tierney 
127a951c980SBrian Tierney         dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8;
128a951c980SBrian Tierney         dtargus /= sp->settings->rate;
129a951c980SBrian Tierney 
130a951c980SBrian Tierney         assert(dtargus != 0);
131*aa89cda2Ssethdelliott 
132a951c980SBrian Tierney         if (gettimeofday(&before, 0) < 0)
133a951c980SBrian Tierney             perror("gettimeofday");
1348556db5dSsethdelliott         ++sp->packet_count;
1358556db5dSsethdelliott         sec = htonl(before.tv_sec);
1368556db5dSsethdelliott         usec = htonl(before.tv_usec);
1378556db5dSsethdelliott         pcount = htonl(sp->packet_count);
138a951c980SBrian Tierney 
1398556db5dSsethdelliott         memcpy(sp->buffer, &sec, sizeof(sec));
1408556db5dSsethdelliott         memcpy(sp->buffer+4, &usec, sizeof(usec));
1418556db5dSsethdelliott         memcpy(sp->buffer+8, &pcount, sizeof(pcount));
142a951c980SBrian Tierney 
143a951c980SBrian Tierney #ifdef USE_SEND
144a951c980SBrian Tierney         result = send(sp->socket, sp->buffer, size, 0);
145a951c980SBrian Tierney #else
146a951c980SBrian Tierney         result = Nwrite(sp->socket, sp->buffer, size, Pudp);
147a951c980SBrian Tierney #endif
148a951c980SBrian Tierney 
1498556db5dSsethdelliott         if (result < 0)
1508556db5dSsethdelliott             perror("Nwrite udp error");
1518556db5dSsethdelliott 
1528556db5dSsethdelliott         sp->result->bytes_sent += result;
1538556db5dSsethdelliott         sp->result->bytes_sent_this_interval += result;
154*aa89cda2Ssethdelliott 
155a951c980SBrian Tierney         if (gettimeofday(&after, 0) < 0)
156a951c980SBrian Tierney             perror("gettimeofday");
157a951c980SBrian Tierney 
158a951c980SBrian Tierney         adjustus = dtargus;
159a951c980SBrian Tierney         adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US;
160a951c980SBrian Tierney         adjustus += (before.tv_usec - after.tv_usec);
161a951c980SBrian Tierney 
1628556db5dSsethdelliott         if (adjustus > 0) {
163a951c980SBrian Tierney             dtargus = adjustus;
164a951c980SBrian Tierney         }
165*aa89cda2Ssethdelliott 
166a951c980SBrian Tierney         update_timer(sp->send_timer, 0, dtargus);
167*aa89cda2Ssethdelliott     }
168*aa89cda2Ssethdelliott 
169a951c980SBrian Tierney     return result;
170a951c980SBrian Tierney }
171a951c980SBrian Tierney 
172a951c980SBrian Tierney /**************************************************************************/
173a951c980SBrian Tierney struct iperf_stream *
174a951c980SBrian Tierney iperf_new_udp_stream(struct iperf_test * testp)
175a951c980SBrian Tierney {
176a951c980SBrian Tierney     struct iperf_stream *sp;
177a951c980SBrian Tierney 
178a951c980SBrian Tierney     sp = (struct iperf_stream *) iperf_new_stream(testp);
1798556db5dSsethdelliott     if (!sp) {
180a951c980SBrian Tierney         perror("malloc");
181a951c980SBrian Tierney         return (NULL);
182a951c980SBrian Tierney     }
183a951c980SBrian Tierney     sp->rcv = iperf_udp_recv;
184a951c980SBrian Tierney     sp->snd = iperf_udp_send;
185a951c980SBrian Tierney 
186a951c980SBrian Tierney     return sp;
187a951c980SBrian Tierney }
188a951c980SBrian Tierney 
189a951c980SBrian Tierney /**************************************************************************/
190a951c980SBrian Tierney 
191a951c980SBrian Tierney /**
192a951c980SBrian Tierney  * iperf_udp_accept -- accepts a new UDP connection
193a951c980SBrian Tierney  * on udp_listener_socket
194a951c980SBrian Tierney  *returns 0 on success
195a951c980SBrian Tierney  *
196a951c980SBrian Tierney  */
197a951c980SBrian Tierney 
198a951c980SBrian Tierney 
199a951c980SBrian Tierney int
200a951c980SBrian Tierney iperf_udp_accept(struct iperf_test *test)
201a951c980SBrian Tierney {
202a951c980SBrian Tierney     struct iperf_stream *sp;
203a951c980SBrian Tierney     struct sockaddr_in sa_peer;
2048556db5dSsethdelliott     int       buf;
205a951c980SBrian Tierney     socklen_t len;
2068556db5dSsethdelliott     int       sz, s;
207a951c980SBrian Tierney 
2088556db5dSsethdelliott     s = test->listener_udp;
209a951c980SBrian Tierney 
210a951c980SBrian Tierney     len = sizeof sa_peer;
2118556db5dSsethdelliott     if ((sz = recvfrom(test->listener_udp, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
2128556db5dSsethdelliott         perror("recvfrom in udp accept");
2138556db5dSsethdelliott         return (-1);
2148556db5dSsethdelliott     }
215a951c980SBrian Tierney 
2168556db5dSsethdelliott     if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) {
217a3281a3dSBrian Tierney         perror("iperf_udp_accept: connect error");
218a951c980SBrian Tierney         return -1;
219a951c980SBrian Tierney     }
2208556db5dSsethdelliott 
221a951c980SBrian Tierney     sp = test->new_stream(test);
2228556db5dSsethdelliott     if (!sp)
2238556db5dSsethdelliott         return (-1);
2248556db5dSsethdelliott     sp->socket = s;
225a951c980SBrian Tierney     iperf_init_stream(sp, test);
226a951c980SBrian Tierney     iperf_add_stream(test, sp);
2278556db5dSsethdelliott     FD_SET(s, &test->read_set);
2288556db5dSsethdelliott     FD_SET(s, &test->write_set);
2298556db5dSsethdelliott     test->max_fd = (s > test->max_fd) ? s : test->max_fd;
230a951c980SBrian Tierney 
2318556db5dSsethdelliott     test->listener_udp = netannounce(Pudp, NULL, test->server_port);
2328556db5dSsethdelliott     if (test->listener_udp < 0)
233a951c980SBrian Tierney         return -1;
234a951c980SBrian Tierney 
2358556db5dSsethdelliott     FD_SET(test->listener_udp, &test->read_set);
2368556db5dSsethdelliott     test->max_fd = (test->max_fd < test->listener_udp) ? test->listener_udp : test->max_fd;
237a951c980SBrian Tierney 
2388556db5dSsethdelliott     /* Let the client know we're ready "accept" another UDP "stream" */
2398556db5dSsethdelliott     if (write(sp->socket, &buf, sizeof(buf)) < 0) {
2408556db5dSsethdelliott         perror("write listen message");
2418556db5dSsethdelliott         return -1;
242a951c980SBrian Tierney     }
243a951c980SBrian Tierney 
2448556db5dSsethdelliott     connect_msg(sp);
2458556db5dSsethdelliott     test->streams_accepted++;
246a951c980SBrian Tierney 
247a951c980SBrian Tierney     return 0;
248a951c980SBrian Tierney }
249a951c980SBrian Tierney 
250