xref: /iperf/src/iperf_udp.c (revision a3281a3d)
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 {
56a951c980SBrian Tierney     int       result, message;
57a951c980SBrian Tierney     int       size = sp->settings->blksize;
58a951c980SBrian Tierney     double    transit = 0, d = 0;
59a951c980SBrian Tierney     struct udp_datagram *udp = (struct udp_datagram *) sp->buffer;
60a951c980SBrian Tierney     struct timeval arrival_time;
61a951c980SBrian Tierney 
62a951c980SBrian Tierney     printf("in iperf_udp_recv: reading %d bytes \n", size);
63a951c980SBrian Tierney     if (!sp->buffer)
64a951c980SBrian Tierney     {
65a951c980SBrian Tierney 	fprintf(stderr, "receive buffer not allocated \n");
66a951c980SBrian Tierney 	exit(0);
67a951c980SBrian Tierney     }
68a951c980SBrian Tierney #ifdef USE_SEND
69a951c980SBrian Tierney     do
70a951c980SBrian Tierney     {
71a951c980SBrian Tierney 	result = recv(sp->socket, sp->buffer, size, 0);
72a951c980SBrian Tierney 
73a951c980SBrian Tierney     } while (result == -1 && errno == EINTR);
74a951c980SBrian Tierney #else
75a951c980SBrian Tierney     result = Nread(sp->socket, sp->buffer, size, Pudp);
76a951c980SBrian Tierney #endif
77a951c980SBrian Tierney 
78a951c980SBrian Tierney     /* interprete the type of message in packet */
79a951c980SBrian Tierney     if (result > 0)
80a951c980SBrian Tierney     {
81a951c980SBrian Tierney 	message = udp->state;
82a951c980SBrian Tierney     }
83a951c980SBrian Tierney     if (message != 7)
84a951c980SBrian Tierney     {
85a951c980SBrian Tierney 	//printf("result = %d state = %d, %d = error\n", result, sp->buffer[0], errno);
86a951c980SBrian Tierney     }
87a951c980SBrian Tierney     if (message == STREAM_RUNNING && (sp->stream_id == udp->stream_id))
88a951c980SBrian Tierney     {
89a951c980SBrian Tierney 	sp->result->bytes_received += result;
90a951c980SBrian Tierney 	if (udp->packet_count == sp->packet_count + 1)
91a951c980SBrian Tierney 	    sp->packet_count++;
92a951c980SBrian Tierney 
93a951c980SBrian Tierney 	/* jitter measurement */
94a951c980SBrian Tierney 	if (gettimeofday(&arrival_time, NULL) < 0)
95a951c980SBrian Tierney 	{
96a951c980SBrian Tierney 	    perror("gettimeofday");
97a951c980SBrian Tierney 	}
98a951c980SBrian Tierney 	transit = timeval_diff(&udp->sent_time, &arrival_time);
99a951c980SBrian Tierney 	d = transit - sp->prev_transit;
100a951c980SBrian Tierney 	if (d < 0)
101a951c980SBrian Tierney 	    d = -d;
102a951c980SBrian Tierney 	sp->prev_transit = transit;
103a951c980SBrian Tierney 	sp->jitter += (d - sp->jitter) / 16.0;
104a951c980SBrian Tierney 
105a951c980SBrian Tierney 
106a951c980SBrian Tierney 	/* OUT OF ORDER PACKETS */
107a951c980SBrian Tierney 	if (udp->packet_count != sp->packet_count)
108a951c980SBrian Tierney 	{
109a951c980SBrian Tierney 	    if (udp->packet_count < sp->packet_count + 1)
110a951c980SBrian Tierney 	    {
111a951c980SBrian Tierney 		sp->outoforder_packets++;
112a951c980SBrian Tierney 		printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket);
113a951c980SBrian Tierney 	    } else
114a951c980SBrian Tierney 		sp->cnt_error += udp->packet_count - sp->packet_count;
115a951c980SBrian Tierney 	}
116a951c980SBrian Tierney 	/* store the latest packet id */
117a951c980SBrian Tierney 	if (udp->packet_count > sp->packet_count)
118a951c980SBrian Tierney 	    sp->packet_count = udp->packet_count;
119a951c980SBrian Tierney 
120a951c980SBrian Tierney 	//printf("incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket);
121a951c980SBrian Tierney 
122a951c980SBrian Tierney     }
123a951c980SBrian Tierney     return message;
124a951c980SBrian Tierney 
125a951c980SBrian Tierney }
126a951c980SBrian Tierney 
127a951c980SBrian Tierney 
128a951c980SBrian Tierney /**************************************************************************/
129a951c980SBrian Tierney int
130a951c980SBrian Tierney iperf_udp_send(struct iperf_stream * sp)
131a951c980SBrian Tierney {
132a951c980SBrian Tierney     int       result = 0;
133a951c980SBrian Tierney     struct timeval before, after;
134a951c980SBrian Tierney     int64_t   dtargus;
135a951c980SBrian Tierney     int64_t   adjustus = 0;
136a951c980SBrian Tierney 
137a951c980SBrian Tierney     //printf("in iperf_udp_send \n");
138a951c980SBrian Tierney     /*
139a951c980SBrian Tierney      * the || part ensures that last packet is sent to server - the
140a951c980SBrian Tierney      * STREAM_END MESSAGE
141a951c980SBrian Tierney      */
142a951c980SBrian Tierney     if (sp->send_timer->expired(sp->send_timer) || sp->settings->state == STREAM_END)
143a951c980SBrian Tierney     {
144a951c980SBrian Tierney 	int       size = sp->settings->blksize;
145a951c980SBrian Tierney 
146a951c980SBrian Tierney 	/* this is for udp packet/jitter/lost packet measurements */
147a951c980SBrian Tierney 	struct udp_datagram *udp = (struct udp_datagram *) sp->buffer;
148a951c980SBrian Tierney 	struct param_exchange *param = NULL;
149a951c980SBrian Tierney 
150a951c980SBrian Tierney 	dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8;
151a951c980SBrian Tierney 	dtargus /= sp->settings->rate;
152a951c980SBrian Tierney 
153a951c980SBrian Tierney 	assert(dtargus != 0);
154a951c980SBrian Tierney 
155a951c980SBrian Tierney 	switch (sp->settings->state)
156a951c980SBrian Tierney 	{
157a951c980SBrian Tierney 	case STREAM_BEGIN:
158a951c980SBrian Tierney 	    udp->state = STREAM_BEGIN;
159a951c980SBrian Tierney 	    udp->stream_id = (int) sp;
160a951c980SBrian Tierney 	    /* udp->packet_count = ++sp->packet_count; */
161a951c980SBrian Tierney 	    break;
162a951c980SBrian Tierney 
163a951c980SBrian Tierney 	case STREAM_END:
164a951c980SBrian Tierney 	    udp->state = STREAM_END;
165a951c980SBrian Tierney 	    udp->stream_id = (int) sp;
166a951c980SBrian Tierney 	    break;
167a951c980SBrian Tierney 
168a951c980SBrian Tierney 	case RESULT_REQUEST:
169a951c980SBrian Tierney 	    udp->state = RESULT_REQUEST;
170a951c980SBrian Tierney 	    udp->stream_id = (int) sp;
171a951c980SBrian Tierney 	    break;
172a951c980SBrian Tierney 
173a951c980SBrian Tierney 	case ALL_STREAMS_END:
174a951c980SBrian Tierney 	    udp->state = ALL_STREAMS_END;
175a951c980SBrian Tierney 	    break;
176a951c980SBrian Tierney 
177a951c980SBrian Tierney 	case STREAM_RUNNING:
178a951c980SBrian Tierney 	    udp->state = STREAM_RUNNING;
179a951c980SBrian Tierney 	    udp->stream_id = (int) sp;
180a951c980SBrian Tierney 	    udp->packet_count = ++sp->packet_count;
181a951c980SBrian Tierney 	    break;
182a951c980SBrian Tierney 	}
183a951c980SBrian Tierney 
184a951c980SBrian Tierney 	if (sp->settings->state == STREAM_BEGIN)
185a951c980SBrian Tierney 	{
186a951c980SBrian Tierney 	    sp->settings->state = STREAM_RUNNING;
187a951c980SBrian Tierney 	}
188a951c980SBrian Tierney 	if (gettimeofday(&before, 0) < 0)
189a951c980SBrian Tierney 	    perror("gettimeofday");
190a951c980SBrian Tierney 
191a951c980SBrian Tierney 	udp->sent_time = before;
192a951c980SBrian Tierney 
193a951c980SBrian Tierney 	printf("iperf_udp_send: writing %d bytes \n", size);
194a951c980SBrian Tierney #ifdef USE_SEND
195a951c980SBrian Tierney 	result = send(sp->socket, sp->buffer, size, 0);
196a951c980SBrian Tierney #else
197a951c980SBrian Tierney 	result = Nwrite(sp->socket, sp->buffer, size, Pudp);
198a951c980SBrian Tierney #endif
199a951c980SBrian Tierney 
200a951c980SBrian Tierney 	if (gettimeofday(&after, 0) < 0)
201a951c980SBrian Tierney 	    perror("gettimeofday");
202a951c980SBrian Tierney 
203a951c980SBrian Tierney 	/*
204a951c980SBrian Tierney 	 * CHECK: Packet length and ID if(sp->settings->state ==
205a951c980SBrian Tierney 	 * STREAM_RUNNING) printf("State = %d Outgoing packet = %d AND SP =
206a951c980SBrian Tierney 	 * %d\n",sp->settings->state, sp->packet_count, sp->socket);
207a951c980SBrian Tierney 	 */
208a951c980SBrian Tierney 
209a951c980SBrian Tierney 	if (sp->settings->state == STREAM_RUNNING)
210a951c980SBrian Tierney 	    sp->result->bytes_sent += result;
211a951c980SBrian Tierney 
212a951c980SBrian Tierney 	adjustus = dtargus;
213a951c980SBrian Tierney 	adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US;
214a951c980SBrian Tierney 	adjustus += (before.tv_usec - after.tv_usec);
215a951c980SBrian Tierney 
216a951c980SBrian Tierney 	if (adjustus > 0)
217a951c980SBrian Tierney 	{
218a951c980SBrian Tierney 	    dtargus = adjustus;
219a951c980SBrian Tierney 	}
220a951c980SBrian Tierney 	/* RESET THE TIMER  */
221a951c980SBrian Tierney 	update_timer(sp->send_timer, 0, dtargus);
222a951c980SBrian Tierney 	param = NULL;
223a951c980SBrian Tierney 
224a951c980SBrian Tierney     }				/* timer_expired_micro */
225a951c980SBrian Tierney     return result;
226a951c980SBrian Tierney }
227a951c980SBrian Tierney 
228a951c980SBrian Tierney /**************************************************************************/
229a951c980SBrian Tierney struct iperf_stream *
230a951c980SBrian Tierney iperf_new_udp_stream(struct iperf_test * testp)
231a951c980SBrian Tierney {
232a951c980SBrian Tierney     struct iperf_stream *sp;
233a951c980SBrian Tierney 
234a951c980SBrian Tierney     sp = (struct iperf_stream *) iperf_new_stream(testp);
235a951c980SBrian Tierney     if (!sp)
236a951c980SBrian Tierney     {
237a951c980SBrian Tierney 	perror("malloc");
238a951c980SBrian Tierney 	return (NULL);
239a951c980SBrian Tierney     }
240a951c980SBrian Tierney     sp->rcv = iperf_udp_recv;
241a951c980SBrian Tierney     sp->snd = iperf_udp_send;
242a951c980SBrian Tierney 
243a951c980SBrian Tierney     return sp;
244a951c980SBrian Tierney }
245a951c980SBrian Tierney 
246a951c980SBrian Tierney /**************************************************************************/
247a951c980SBrian Tierney 
248a951c980SBrian Tierney /**
249a951c980SBrian Tierney  * iperf_udp_accept -- accepts a new UDP connection
250a951c980SBrian Tierney  * on udp_listener_socket
251a951c980SBrian Tierney  *returns 0 on success
252a951c980SBrian Tierney  *
253a951c980SBrian Tierney  */
254a951c980SBrian Tierney 
255a951c980SBrian Tierney 
256a951c980SBrian Tierney int
257a951c980SBrian Tierney iperf_udp_accept(struct iperf_test * test)
258a951c980SBrian Tierney {
259a951c980SBrian Tierney 
260a951c980SBrian Tierney     struct iperf_stream *sp;
261a951c980SBrian Tierney     struct sockaddr_in sa_peer;
262a951c980SBrian Tierney     char     *buf;
263a951c980SBrian Tierney     socklen_t len;
264a951c980SBrian Tierney     int       sz;
265a951c980SBrian Tierney 
266a951c980SBrian Tierney     buf = (char *) malloc(test->default_settings->blksize);
267a951c980SBrian Tierney     struct udp_datagram *udp = (struct udp_datagram *) buf;
268a951c980SBrian Tierney 
269a951c980SBrian Tierney     len = sizeof sa_peer;
270a951c980SBrian Tierney 
271a951c980SBrian Tierney     sz = recvfrom(test->listener_sock_udp, buf, test->default_settings->blksize, 0, (struct sockaddr *) & sa_peer, &len);
272a951c980SBrian Tierney 
273a951c980SBrian Tierney     if (!sz)
274a951c980SBrian Tierney 	return -1;
275a951c980SBrian Tierney 
276a951c980SBrian Tierney     if (connect(test->listener_sock_udp, (struct sockaddr *) & sa_peer, len) < 0)
277a951c980SBrian Tierney     {
278*a3281a3dSBrian Tierney 	perror("iperf_udp_accept: connect error");
279*a3281a3dSBrian Tierney 	exit(-1);  /* XXX: for debugging */
280a951c980SBrian Tierney 	return -1;
281a951c980SBrian Tierney     }
282a951c980SBrian Tierney     sp = test->new_stream(test);
283a951c980SBrian Tierney 
284a951c980SBrian Tierney     sp->socket = test->listener_sock_udp;
285a951c980SBrian Tierney 
286a951c980SBrian Tierney     setnonblocking(sp->socket);
287a951c980SBrian Tierney 
288a951c980SBrian Tierney     iperf_init_stream(sp, test);
289a951c980SBrian Tierney     iperf_add_stream(test, sp);
290a951c980SBrian Tierney 
291a951c980SBrian Tierney 
292a951c980SBrian Tierney     test->listener_sock_udp = netannounce(Pudp, NULL, test->server_port);
293a951c980SBrian Tierney     if (test->listener_sock_udp < 0)
294a951c980SBrian Tierney 	return -1;
295a951c980SBrian Tierney 
296a951c980SBrian Tierney     FD_SET(test->listener_sock_udp, &test->read_set);
297a951c980SBrian Tierney     test->max_fd = (test->max_fd < test->listener_sock_udp) ? test->listener_sock_udp : test->max_fd;
298a951c980SBrian Tierney 
299a951c980SBrian Tierney     if (test->default_settings->state != RESULT_REQUEST)
300a951c980SBrian Tierney 	connect_msg(sp);
301a951c980SBrian Tierney 
302a951c980SBrian Tierney     printf("iperf_udp_accept: 1st UDP data  packet for socket %d has arrived \n", sp->socket);
303a951c980SBrian Tierney     sp->stream_id = udp->stream_id;
304a951c980SBrian Tierney     sp->result->bytes_received += sz;
305a951c980SBrian Tierney 
306a951c980SBrian Tierney     /* Count OUT OF ORDER PACKETS */
307a951c980SBrian Tierney     if (udp->packet_count != 0)
308a951c980SBrian Tierney     {
309a951c980SBrian Tierney 	if (udp->packet_count < sp->packet_count + 1)
310a951c980SBrian Tierney 	    sp->outoforder_packets++;
311a951c980SBrian Tierney 	else
312a951c980SBrian Tierney 	    sp->cnt_error += udp->packet_count - sp->packet_count;
313a951c980SBrian Tierney     }
314a951c980SBrian Tierney     /* store the latest packet id */
315a951c980SBrian Tierney     if (udp->packet_count > sp->packet_count)
316a951c980SBrian Tierney 	sp->packet_count = udp->packet_count;
317a951c980SBrian Tierney 
318a951c980SBrian Tierney     //printf("incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket);
319a951c980SBrian Tierney 
320a951c980SBrian Tierney     free(buf);
321a951c980SBrian Tierney     return 0;
322a951c980SBrian Tierney }
323a951c980SBrian Tierney 
324