Annotation of embedaddon/iperf/src/iperf_udp.c, revision 1.1.1.1
1.1 misho 1: /*
2: * iperf, Copyright (c) 2014, 2016, The Regents of the University of
3: * California, through Lawrence Berkeley National Laboratory (subject
4: * to receipt of any required approvals from the U.S. Dept. of
5: * Energy). All rights reserved.
6: *
7: * If you have questions about your rights to use or distribute this
8: * software, please contact Berkeley Lab's Technology Transfer
9: * Department at TTD@lbl.gov.
10: *
11: * NOTICE. This software is owned by the U.S. Department of Energy.
12: * As such, the U.S. Government has been granted for itself and others
13: * acting on its behalf a paid-up, nonexclusive, irrevocable,
14: * worldwide license in the Software to reproduce, prepare derivative
15: * works, and perform publicly and display publicly. Beginning five
16: * (5) years after the date permission to assert copyright is obtained
17: * from the U.S. Department of Energy, and subject to any subsequent
18: * five (5) year renewals, the U.S. Government is granted for itself
19: * and others acting on its behalf a paid-up, nonexclusive,
20: * irrevocable, worldwide license in the Software to reproduce,
21: * prepare derivative works, distribute copies to the public, perform
22: * publicly and display publicly, and to permit others to do so.
23: *
24: * This code is distributed under a BSD style license, see the LICENSE
25: * file for complete information.
26: */
27: #include <stdio.h>
28: #include <stdlib.h>
29: #include <string.h>
30: #include <errno.h>
31: #include <unistd.h>
32: #include <assert.h>
33: #include <sys/socket.h>
34: #include <sys/types.h>
35: #include <netinet/in.h>
36: #ifdef HAVE_STDINT_H
37: #include <stdint.h>
38: #endif
39: #include <sys/time.h>
40: #include <sys/select.h>
41:
42: #include "iperf.h"
43: #include "iperf_api.h"
44: #include "iperf_util.h"
45: #include "iperf_udp.h"
46: #include "timer.h"
47: #include "net.h"
48: #include "portable_endian.h"
49:
50: /* iperf_udp_recv
51: *
52: * receives the data for UDP
53: */
54: int
55: iperf_udp_recv(struct iperf_stream *sp)
56: {
57: uint32_t sec, usec;
58: uint64_t pcount;
59: int r;
60: int size = sp->settings->blksize;
61: double transit = 0, d = 0;
62: struct timeval sent_time, arrival_time;
63:
64: r = Nread(sp->socket, sp->buffer, size, Pudp);
65:
66: /*
67: * If we got an error in the read, or if we didn't read anything
68: * because the underlying read(2) got a EAGAIN, then skip packet
69: * processing.
70: */
71: if (r <= 0)
72: return r;
73:
74: sp->result->bytes_received += r;
75: sp->result->bytes_received_this_interval += r;
76:
77: if (sp->test->udp_counters_64bit) {
78: memcpy(&sec, sp->buffer, sizeof(sec));
79: memcpy(&usec, sp->buffer+4, sizeof(usec));
80: memcpy(&pcount, sp->buffer+8, sizeof(pcount));
81: sec = ntohl(sec);
82: usec = ntohl(usec);
83: pcount = be64toh(pcount);
84: sent_time.tv_sec = sec;
85: sent_time.tv_usec = usec;
86: }
87: else {
88: uint32_t pc;
89: memcpy(&sec, sp->buffer, sizeof(sec));
90: memcpy(&usec, sp->buffer+4, sizeof(usec));
91: memcpy(&pc, sp->buffer+8, sizeof(pc));
92: sec = ntohl(sec);
93: usec = ntohl(usec);
94: pcount = ntohl(pc);
95: sent_time.tv_sec = sec;
96: sent_time.tv_usec = usec;
97: }
98:
99: /* Out of order packets */
100: if (pcount >= sp->packet_count + 1) {
101: if (pcount > sp->packet_count + 1) {
102: sp->cnt_error += (pcount - 1) - sp->packet_count;
103: }
104: sp->packet_count = pcount;
105: } else {
106: sp->outoforder_packets++;
107: iperf_err(sp->test, "OUT OF ORDER - incoming packet = %zu and received packet = %d AND SP = %d", pcount, sp->packet_count, sp->socket);
108: }
109:
110: /* jitter measurement */
111: gettimeofday(&arrival_time, NULL);
112:
113: transit = timeval_diff(&sent_time, &arrival_time);
114: d = transit - sp->prev_transit;
115: if (d < 0)
116: d = -d;
117: sp->prev_transit = transit;
118: // XXX: This is NOT the way to calculate jitter
119: // J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average]
120: sp->jitter += (d - sp->jitter) / 16.0;
121:
122: if (sp->test->debug) {
123: fprintf(stderr, "packet_count %d\n", sp->packet_count);
124: }
125:
126: return r;
127: }
128:
129:
130: /* iperf_udp_send
131: *
132: * sends the data for UDP
133: */
134: int
135: iperf_udp_send(struct iperf_stream *sp)
136: {
137: int r;
138: int size = sp->settings->blksize;
139: struct timeval before;
140:
141: gettimeofday(&before, 0);
142:
143: ++sp->packet_count;
144:
145: if (sp->test->udp_counters_64bit) {
146:
147: uint32_t sec, usec;
148: uint64_t pcount;
149:
150: sec = htonl(before.tv_sec);
151: usec = htonl(before.tv_usec);
152: pcount = htobe64(sp->packet_count);
153:
154: memcpy(sp->buffer, &sec, sizeof(sec));
155: memcpy(sp->buffer+4, &usec, sizeof(usec));
156: memcpy(sp->buffer+8, &pcount, sizeof(pcount));
157:
158: }
159: else {
160:
161: uint32_t sec, usec, pcount;
162:
163: sec = htonl(before.tv_sec);
164: usec = htonl(before.tv_usec);
165: pcount = htonl(sp->packet_count);
166:
167: memcpy(sp->buffer, &sec, sizeof(sec));
168: memcpy(sp->buffer+4, &usec, sizeof(usec));
169: memcpy(sp->buffer+8, &pcount, sizeof(pcount));
170:
171: }
172:
173: r = Nwrite(sp->socket, sp->buffer, size, Pudp);
174:
175: if (r < 0)
176: return r;
177:
178: sp->result->bytes_sent += r;
179: sp->result->bytes_sent_this_interval += r;
180:
181: return r;
182: }
183:
184:
185: /**************************************************************************/
186:
187: /*
188: * The following functions all have to do with managing UDP data sockets.
189: * UDP of course is connectionless, so there isn't really a concept of
190: * setting up a connection, although connect(2) can (and is) used to
191: * bind the remote end of sockets. We need to simulate some of the
192: * connection management that is built-in to TCP so that each side of the
193: * connection knows about each other before the real data transfers begin.
194: */
195:
196: /*
197: * iperf_udp_accept
198: *
199: * Accepts a new UDP "connection"
200: */
201: int
202: iperf_udp_accept(struct iperf_test *test)
203: {
204: struct sockaddr_storage sa_peer;
205: int buf;
206: socklen_t len;
207: int sz, s;
208:
209: /*
210: * Get the current outstanding socket. This socket will be used to handle
211: * data transfers and a new "listening" socket will be created.
212: */
213: s = test->prot_listener;
214:
215: /*
216: * Grab the UDP packet sent by the client. From that we can extract the
217: * client's address, and then use that information to bind the remote side
218: * of the socket to the client.
219: */
220: len = sizeof(sa_peer);
221: if ((sz = recvfrom(test->prot_listener, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) {
222: i_errno = IESTREAMACCEPT;
223: return -1;
224: }
225:
226: if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) {
227: i_errno = IESTREAMACCEPT;
228: return -1;
229: }
230:
231: /*
232: * Set socket buffer size if requested. Do this for both sending and
233: * receiving so that we can cover both normal and --reverse operation.
234: */
235: int opt;
236: if ((opt = test->settings->socket_bufsize)) {
237: if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
238: i_errno = IESETBUF;
239: return -1;
240: }
241: if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
242: i_errno = IESETBUF;
243: return -1;
244: }
245: }
246:
247: #if defined(HAVE_SO_MAX_PACING_RATE)
248: /* If socket pacing is available and not disabled, try it. */
249: if (! test->no_fq_socket_pacing) {
250: /* Convert bits per second to bytes per second */
251: unsigned int rate = test->settings->rate / 8;
252: if (rate > 0) {
253: if (test->debug) {
254: printf("Setting fair-queue socket pacing to %u\n", rate);
255: }
256: if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) {
257: warning("Unable to set socket pacing, using application pacing instead");
258: test->no_fq_socket_pacing = 1;
259: }
260: }
261: }
262: #endif /* HAVE_SO_MAX_PACING_RATE */
263:
264: /*
265: * Create a new "listening" socket to replace the one we were using before.
266: */
267: test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port);
268: if (test->prot_listener < 0) {
269: i_errno = IESTREAMLISTEN;
270: return -1;
271: }
272:
273: FD_SET(test->prot_listener, &test->read_set);
274: test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd;
275:
276: /* Let the client know we're ready "accept" another UDP "stream" */
277: buf = 987654321; /* any content will work here */
278: if (write(s, &buf, sizeof(buf)) < 0) {
279: i_errno = IESTREAMWRITE;
280: return -1;
281: }
282:
283: return s;
284: }
285:
286:
287: /*
288: * iperf_udp_listen
289: *
290: * Start up a listener for UDP stream connections. Unlike for TCP,
291: * there is no listen(2) for UDP. This socket will however accept
292: * a UDP datagram from a client (indicating the client's presence).
293: */
294: int
295: iperf_udp_listen(struct iperf_test *test)
296: {
297: int s;
298:
299: if ((s = netannounce(test->settings->domain, Pudp, test->bind_address, test->server_port)) < 0) {
300: i_errno = IESTREAMLISTEN;
301: return -1;
302: }
303:
304: /*
305: * The caller will put this value into test->prot_listener.
306: */
307: return s;
308: }
309:
310:
311: /*
312: * iperf_udp_connect
313: *
314: * "Connect" to a UDP stream listener.
315: */
316: int
317: iperf_udp_connect(struct iperf_test *test)
318: {
319: int s, buf, sz;
320: #ifdef SO_RCVTIMEO
321: struct timeval tv;
322: #endif
323:
324: /* Create and bind our local socket. */
325: if ((s = netdial(test->settings->domain, Pudp, test->bind_address, test->bind_port, test->server_hostname, test->server_port)) < 0) {
326: i_errno = IESTREAMCONNECT;
327: return -1;
328: }
329:
330: /*
331: * Set socket buffer size if requested. Do this for both sending and
332: * receiving so that we can cover both normal and --reverse operation.
333: */
334: int opt;
335: if ((opt = test->settings->socket_bufsize)) {
336: if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
337: i_errno = IESETBUF;
338: return -1;
339: }
340: if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
341: i_errno = IESETBUF;
342: return -1;
343: }
344: }
345:
346: #if defined(HAVE_SO_MAX_PACING_RATE)
347: /* If socket pacing is available and not disabled, try it. */
348: if (! test->no_fq_socket_pacing) {
349: /* Convert bits per second to bytes per second */
350: unsigned int rate = test->settings->rate / 8;
351: if (rate > 0) {
352: if (test->debug) {
353: printf("Setting fair-queue socket pacing to %u\n", rate);
354: }
355: if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) {
356: warning("Unable to set socket pacing, using application pacing instead");
357: test->no_fq_socket_pacing = 1;
358: }
359: }
360: }
361: #endif /* HAVE_SO_MAX_PACING_RATE */
362:
363: #ifdef SO_RCVTIMEO
364: /* 30 sec timeout for a case when there is a network problem. */
365: tv.tv_sec = 30;
366: tv.tv_usec = 0;
367: setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
368: #endif
369:
370: /*
371: * Write a datagram to the UDP stream to let the server know we're here.
372: * The server learns our address by obtaining its peer's address.
373: */
374: buf = 123456789; /* this can be pretty much anything */
375: if (write(s, &buf, sizeof(buf)) < 0) {
376: // XXX: Should this be changed to IESTREAMCONNECT?
377: i_errno = IESTREAMWRITE;
378: return -1;
379: }
380:
381: /*
382: * Wait until the server replies back to us.
383: */
384: if ((sz = recv(s, &buf, sizeof(buf), 0)) < 0) {
385: i_errno = IESTREAMREAD;
386: return -1;
387: }
388:
389: return s;
390: }
391:
392:
393: /* iperf_udp_init
394: *
395: * initializer for UDP streams in TEST_START
396: */
397: int
398: iperf_udp_init(struct iperf_test *test)
399: {
400: return 0;
401: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>