xref: /iperf/src/iperf_udp.c (revision 8556db5d)
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 {
56*8556db5dSsethdelliott     int       result;
57a951c980SBrian Tierney     int       size = sp->settings->blksize;
58*8556db5dSsethdelliott     int       sec, usec, pcount;
59a951c980SBrian Tierney     double    transit = 0, d = 0;
60*8556db5dSsethdelliott     struct timeval sent_time, arrival_time;
61a951c980SBrian Tierney 
62*8556db5dSsethdelliott     // XXX: Is this necessary? We've already checked the buffer to see if it's allocated.
63*8556db5dSsethdelliott     if (!sp->buffer) {
64a951c980SBrian Tierney         fprintf(stderr, "receive buffer not allocated \n");
65a951c980SBrian Tierney         exit(0);
66a951c980SBrian Tierney     }
67a951c980SBrian Tierney #ifdef USE_SEND
68*8556db5dSsethdelliott     do {
69a951c980SBrian Tierney         result = recv(sp->socket, sp->buffer, size, 0);
70a951c980SBrian Tierney     } while (result == -1 && errno == EINTR);
71a951c980SBrian Tierney #else
72a951c980SBrian Tierney     result = Nread(sp->socket, sp->buffer, size, Pudp);
73a951c980SBrian Tierney #endif
74a951c980SBrian Tierney 
75*8556db5dSsethdelliott     if (result < 0) {
76*8556db5dSsethdelliott         perror("Nread udp result");
77*8556db5dSsethdelliott         return (-1);
78a951c980SBrian Tierney     }
79a951c980SBrian Tierney     sp->result->bytes_received += result;
80*8556db5dSsethdelliott     sp->result->bytes_received_this_interval += result;
81*8556db5dSsethdelliott 
82*8556db5dSsethdelliott     memcpy(&sec, sp->buffer, sizeof(sec));
83*8556db5dSsethdelliott     memcpy(&usec, sp->buffer+4, sizeof(usec));
84*8556db5dSsethdelliott     memcpy(&pcount, sp->buffer+8, sizeof(pcount));
85*8556db5dSsethdelliott     sec = ntohl(sec);
86*8556db5dSsethdelliott     usec = ntohl(usec);
87*8556db5dSsethdelliott     pcount = ntohl(pcount);
88*8556db5dSsethdelliott     sent_time.tv_sec = sec;
89*8556db5dSsethdelliott     sent_time.tv_usec = usec;
90*8556db5dSsethdelliott 
91*8556db5dSsethdelliott     /* Out of order packets */
92*8556db5dSsethdelliott     if (pcount >= sp->packet_count + 1) {
93*8556db5dSsethdelliott         if (pcount > sp->packet_count + 1) {
94*8556db5dSsethdelliott             sp->cnt_error += (pcount - 1) - sp->packet_count;
95*8556db5dSsethdelliott         }
96*8556db5dSsethdelliott         sp->packet_count = pcount;
97*8556db5dSsethdelliott     } else {
98*8556db5dSsethdelliott         sp->outoforder_packets++;
99*8556db5dSsethdelliott         printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", pcount, sp->packet_count, sp->socket);
100*8556db5dSsethdelliott     }
101a951c980SBrian Tierney 
102a951c980SBrian Tierney     /* jitter measurement */
103*8556db5dSsethdelliott     if (gettimeofday(&arrival_time, NULL) < 0) {
104a951c980SBrian Tierney         perror("gettimeofday");
105a951c980SBrian Tierney     }
106*8556db5dSsethdelliott     transit = timeval_diff(&sent_time, &arrival_time);
107a951c980SBrian Tierney     d = transit - sp->prev_transit;
108a951c980SBrian Tierney     if (d < 0)
109a951c980SBrian Tierney         d = -d;
110a951c980SBrian Tierney     sp->prev_transit = transit;
111*8556db5dSsethdelliott     // XXX: This is NOT the way to calculate jitter
112*8556db5dSsethdelliott     //      J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average]
113a951c980SBrian Tierney     sp->jitter += (d - sp->jitter) / 16.0;
114a951c980SBrian Tierney 
115*8556db5dSsethdelliott     return result;
116a951c980SBrian Tierney }
117a951c980SBrian Tierney 
118a951c980SBrian Tierney 
119a951c980SBrian Tierney /**************************************************************************/
120a951c980SBrian Tierney int
121a951c980SBrian Tierney iperf_udp_send(struct iperf_stream *sp)
122a951c980SBrian Tierney {
123*8556db5dSsethdelliott     ssize_t   result = 0;
124a951c980SBrian Tierney     int64_t   dtargus;
125a951c980SBrian Tierney     int64_t   adjustus = 0;
126*8556db5dSsethdelliott     uint64_t  sec, usec, pcount;
127*8556db5dSsethdelliott     int       size = sp->settings->blksize;
128*8556db5dSsethdelliott     struct timeval before, after;
129a951c980SBrian Tierney 
130a951c980SBrian Tierney     /*
131a951c980SBrian Tierney      * the || part ensures that last packet is sent to server - the
132a951c980SBrian Tierney      * STREAM_END MESSAGE
133a951c980SBrian Tierney      */
134*8556db5dSsethdelliott //    if (sp->send_timer->expired(sp->send_timer) || sp->settings->state == STREAM_END) {
135a951c980SBrian Tierney 
136*8556db5dSsethdelliott /*
137a951c980SBrian Tierney         dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8;
138a951c980SBrian Tierney         dtargus /= sp->settings->rate;
139a951c980SBrian Tierney 
140a951c980SBrian Tierney         assert(dtargus != 0);
141*8556db5dSsethdelliott */
142a951c980SBrian Tierney         if (gettimeofday(&before, 0) < 0)
143a951c980SBrian Tierney             perror("gettimeofday");
144*8556db5dSsethdelliott         ++sp->packet_count;
145*8556db5dSsethdelliott         sec = htonl(before.tv_sec);
146*8556db5dSsethdelliott         usec = htonl(before.tv_usec);
147*8556db5dSsethdelliott         pcount = htonl(sp->packet_count);
148a951c980SBrian Tierney 
149*8556db5dSsethdelliott         memcpy(sp->buffer, &sec, sizeof(sec));
150*8556db5dSsethdelliott         memcpy(sp->buffer+4, &usec, sizeof(usec));
151*8556db5dSsethdelliott         memcpy(sp->buffer+8, &pcount, sizeof(pcount));
152a951c980SBrian Tierney 
153a951c980SBrian Tierney #ifdef USE_SEND
154a951c980SBrian Tierney         result = send(sp->socket, sp->buffer, size, 0);
155a951c980SBrian Tierney #else
156a951c980SBrian Tierney         result = Nwrite(sp->socket, sp->buffer, size, Pudp);
157a951c980SBrian Tierney #endif
158a951c980SBrian Tierney 
159*8556db5dSsethdelliott         if (result < 0)
160*8556db5dSsethdelliott             perror("Nwrite udp error");
161*8556db5dSsethdelliott 
162*8556db5dSsethdelliott         sp->result->bytes_sent += result;
163*8556db5dSsethdelliott         sp->result->bytes_sent_this_interval += result;
164*8556db5dSsethdelliott /*
165a951c980SBrian Tierney         if (gettimeofday(&after, 0) < 0)
166a951c980SBrian Tierney             perror("gettimeofday");
167a951c980SBrian Tierney 
168*8556db5dSsethdelliott         //
169*8556db5dSsethdelliott         // CHECK: Packet length and ID if(sp->settings->state ==
170*8556db5dSsethdelliott         // STREAM_RUNNING) printf("State = %d Outgoing packet = %d AND SP =
171*8556db5dSsethdelliott         // %d\n",sp->settings->state, sp->packet_count, sp->socket);
172*8556db5dSsethdelliott         //
173a951c980SBrian Tierney 
174a951c980SBrian Tierney 
175a951c980SBrian Tierney         adjustus = dtargus;
176a951c980SBrian Tierney         adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US;
177a951c980SBrian Tierney         adjustus += (before.tv_usec - after.tv_usec);
178a951c980SBrian Tierney 
179*8556db5dSsethdelliott         if (adjustus > 0) {
180a951c980SBrian Tierney             dtargus = adjustus;
181a951c980SBrian Tierney         }
182*8556db5dSsethdelliott         // RESET THE TIMER
183a951c980SBrian Tierney         update_timer(sp->send_timer, 0, dtargus);
184*8556db5dSsethdelliott //    } // timer_expired_micro
185*8556db5dSsethdelliott */
186a951c980SBrian Tierney     return result;
187a951c980SBrian Tierney }
188a951c980SBrian Tierney 
189a951c980SBrian Tierney /**************************************************************************/
190a951c980SBrian Tierney struct iperf_stream *
191a951c980SBrian Tierney iperf_new_udp_stream(struct iperf_test * testp)
192a951c980SBrian Tierney {
193a951c980SBrian Tierney     struct iperf_stream *sp;
194a951c980SBrian Tierney 
195a951c980SBrian Tierney     sp = (struct iperf_stream *) iperf_new_stream(testp);
196*8556db5dSsethdelliott     if (!sp) {
197a951c980SBrian Tierney         perror("malloc");
198a951c980SBrian Tierney         return (NULL);
199a951c980SBrian Tierney     }
200a951c980SBrian Tierney     sp->rcv = iperf_udp_recv;
201a951c980SBrian Tierney     sp->snd = iperf_udp_send;
202a951c980SBrian Tierney 
203a951c980SBrian Tierney     return sp;
204a951c980SBrian Tierney }
205a951c980SBrian Tierney 
206a951c980SBrian Tierney /**************************************************************************/
207a951c980SBrian Tierney 
208a951c980SBrian Tierney /**
209a951c980SBrian Tierney  * iperf_udp_accept -- accepts a new UDP connection
210a951c980SBrian Tierney  * on udp_listener_socket
211a951c980SBrian Tierney  *returns 0 on success
212a951c980SBrian Tierney  *
213a951c980SBrian Tierney  */
214a951c980SBrian Tierney 
215a951c980SBrian Tierney 
216a951c980SBrian Tierney int
217a951c980SBrian Tierney iperf_udp_accept(struct iperf_test *test)
218a951c980SBrian Tierney {
219a951c980SBrian Tierney     struct iperf_stream *sp;
220a951c980SBrian Tierney     struct sockaddr_in sa_peer;
221*8556db5dSsethdelliott     int       buf;
222a951c980SBrian Tierney     socklen_t len;
223*8556db5dSsethdelliott     int       sz, s;
224a951c980SBrian Tierney 
225*8556db5dSsethdelliott     s = test->listener_udp;
226a951c980SBrian Tierney 
227a951c980SBrian Tierney     len = sizeof sa_peer;
228*8556db5dSsethdelliott     if ((sz = recvfrom(test->listener_udp, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
229*8556db5dSsethdelliott         perror("recvfrom in udp accept");
230*8556db5dSsethdelliott         return (-1);
231*8556db5dSsethdelliott     }
232a951c980SBrian Tierney 
233*8556db5dSsethdelliott     if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) {
234a3281a3dSBrian Tierney         perror("iperf_udp_accept: connect error");
235a951c980SBrian Tierney         return -1;
236a951c980SBrian Tierney     }
237*8556db5dSsethdelliott 
238a951c980SBrian Tierney     sp = test->new_stream(test);
239*8556db5dSsethdelliott     if (!sp)
240*8556db5dSsethdelliott         return (-1);
241*8556db5dSsethdelliott     sp->socket = s;
242a951c980SBrian Tierney     iperf_init_stream(sp, test);
243a951c980SBrian Tierney     iperf_add_stream(test, sp);
244*8556db5dSsethdelliott     FD_SET(s, &test->read_set);
245*8556db5dSsethdelliott     FD_SET(s, &test->write_set);
246*8556db5dSsethdelliott     test->max_fd = (s > test->max_fd) ? s : test->max_fd;
247a951c980SBrian Tierney 
248*8556db5dSsethdelliott     test->listener_udp = netannounce(Pudp, NULL, test->server_port);
249*8556db5dSsethdelliott     if (test->listener_udp < 0)
250a951c980SBrian Tierney         return -1;
251a951c980SBrian Tierney 
252*8556db5dSsethdelliott     FD_SET(test->listener_udp, &test->read_set);
253*8556db5dSsethdelliott     test->max_fd = (test->max_fd < test->listener_udp) ? test->listener_udp : test->max_fd;
254a951c980SBrian Tierney 
255*8556db5dSsethdelliott     /* Let the client know we're ready "accept" another UDP "stream" */
256*8556db5dSsethdelliott     if (write(sp->socket, &buf, sizeof(buf)) < 0) {
257*8556db5dSsethdelliott         perror("write listen message");
258*8556db5dSsethdelliott         return -1;
259a951c980SBrian Tierney     }
260a951c980SBrian Tierney 
261*8556db5dSsethdelliott     connect_msg(sp);
262*8556db5dSsethdelliott     test->streams_accepted++;
263a951c980SBrian Tierney 
264a951c980SBrian Tierney     return 0;
265a951c980SBrian Tierney }
266a951c980SBrian Tierney 
267