Annotation of embedaddon/iperf/src/iperf_tcp.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 "iperf_config.h"
28:
29: #include <stdio.h>
30: #include <stdlib.h>
31: #include <string.h>
32: #include <errno.h>
33: #include <unistd.h>
34: #include <sys/socket.h>
35: #include <sys/types.h>
36: #include <netinet/in.h>
37: #include <netdb.h>
38: #include <netinet/tcp.h>
39: #include <sys/time.h>
40: #include <sys/select.h>
41:
42: #include "iperf.h"
43: #include "iperf_api.h"
44: #include "iperf_tcp.h"
45: #include "net.h"
46:
47: #if defined(HAVE_FLOWLABEL)
48: #include "flowlabel.h"
49: #endif /* HAVE_FLOWLABEL */
50:
51: /* iperf_tcp_recv
52: *
53: * receives the data for TCP
54: */
55: int
56: iperf_tcp_recv(struct iperf_stream *sp)
57: {
58: int r;
59:
60: r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);
61:
62: if (r < 0)
63: return r;
64:
65: sp->result->bytes_received += r;
66: sp->result->bytes_received_this_interval += r;
67:
68: return r;
69: }
70:
71:
72: /* iperf_tcp_send
73: *
74: * sends the data for TCP
75: */
76: int
77: iperf_tcp_send(struct iperf_stream *sp)
78: {
79: int r;
80:
81: if (sp->test->zerocopy)
82: r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->settings->blksize);
83: else
84: r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);
85:
86: if (r < 0)
87: return r;
88:
89: sp->result->bytes_sent += r;
90: sp->result->bytes_sent_this_interval += r;
91:
92: return r;
93: }
94:
95:
96: /* iperf_tcp_accept
97: *
98: * accept a new TCP stream connection
99: */
100: int
101: iperf_tcp_accept(struct iperf_test * test)
102: {
103: int s;
104: signed char rbuf = ACCESS_DENIED;
105: char cookie[COOKIE_SIZE];
106: socklen_t len;
107: struct sockaddr_storage addr;
108:
109: len = sizeof(addr);
110: if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
111: i_errno = IESTREAMCONNECT;
112: return -1;
113: }
114:
115: if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
116: i_errno = IERECVCOOKIE;
117: return -1;
118: }
119:
120: if (strcmp(test->cookie, cookie) != 0) {
121: if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
122: i_errno = IESENDMESSAGE;
123: return -1;
124: }
125: close(s);
126: }
127:
128: return s;
129: }
130:
131:
132: /* iperf_tcp_listen
133: *
134: * start up a listener for TCP stream connections
135: */
136: int
137: iperf_tcp_listen(struct iperf_test *test)
138: {
139: struct addrinfo hints, *res;
140: char portstr[6];
141: int s, opt;
142: int saved_errno;
143:
144: s = test->listener;
145:
146: /*
147: * If certain parameters are specified (such as socket buffer
148: * size), then throw away the listening socket (the one for which
149: * we just accepted the control connection) and recreate it with
150: * those parameters. That way, when new data connections are
151: * set, they'll have all the correct parameters in place.
152: *
153: * It's not clear whether this is a requirement or a convenience.
154: */
155: if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
156: FD_CLR(s, &test->read_set);
157: close(s);
158:
159: snprintf(portstr, 6, "%d", test->server_port);
160: memset(&hints, 0, sizeof(hints));
161:
162: /*
163: * If binding to the wildcard address with no explicit address
164: * family specified, then force us to get an AF_INET6 socket.
165: * More details in the comments in netanounce().
166: */
167: if (test->settings->domain == AF_UNSPEC && !test->bind_address) {
168: hints.ai_family = AF_INET6;
169: }
170: else {
171: hints.ai_family = test->settings->domain;
172: }
173: hints.ai_socktype = SOCK_STREAM;
174: hints.ai_flags = AI_PASSIVE;
175: if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) {
176: i_errno = IESTREAMLISTEN;
177: return -1;
178: }
179:
180: if ((s = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
181: freeaddrinfo(res);
182: i_errno = IESTREAMLISTEN;
183: return -1;
184: }
185:
186: if (test->no_delay) {
187: opt = 1;
188: if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
189: saved_errno = errno;
190: close(s);
191: freeaddrinfo(res);
192: errno = saved_errno;
193: i_errno = IESETNODELAY;
194: return -1;
195: }
196: }
197: // XXX: Setting MSS is very buggy!
198: if ((opt = test->settings->mss)) {
199: if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
200: saved_errno = errno;
201: close(s);
202: freeaddrinfo(res);
203: errno = saved_errno;
204: i_errno = IESETMSS;
205: return -1;
206: }
207: }
208: if ((opt = test->settings->socket_bufsize)) {
209: if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
210: saved_errno = errno;
211: close(s);
212: freeaddrinfo(res);
213: errno = saved_errno;
214: i_errno = IESETBUF;
215: return -1;
216: }
217: if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
218: saved_errno = errno;
219: close(s);
220: freeaddrinfo(res);
221: errno = saved_errno;
222: i_errno = IESETBUF;
223: return -1;
224: }
225: }
226: if (test->debug) {
227: socklen_t optlen = sizeof(opt);
228: if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) {
229: saved_errno = errno;
230: close(s);
231: freeaddrinfo(res);
232: errno = saved_errno;
233: i_errno = IESETBUF;
234: return -1;
235: }
236: printf("SO_SNDBUF is %u\n", opt);
237: }
238: #if defined(HAVE_TCP_CONGESTION)
239: if (test->congestion) {
240: if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
241: close(s);
242: freeaddrinfo(res);
243: i_errno = IESETCONGESTION;
244: return -1;
245: }
246: }
247: #endif /* HAVE_TCP_CONGESTION */
248: #if defined(HAVE_SO_MAX_PACING_RATE)
249: /* If socket pacing is available and not disabled, try it. */
250: if (! test->no_fq_socket_pacing) {
251: /* Convert bits per second to bytes per second */
252: unsigned int rate = test->settings->rate / 8;
253: if (rate > 0) {
254: if (test->debug) {
255: printf("Setting fair-queue socket pacing to %u\n", rate);
256: }
257: if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) {
258: warning("Unable to set socket pacing, using application pacing instead");
259: test->no_fq_socket_pacing = 1;
260: }
261: }
262: }
263: #endif /* HAVE_SO_MAX_PACING_RATE */
264: opt = 1;
265: if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
266: saved_errno = errno;
267: close(s);
268: freeaddrinfo(res);
269: errno = saved_errno;
270: i_errno = IEREUSEADDR;
271: return -1;
272: }
273:
274: /*
275: * If we got an IPv6 socket, figure out if it shoudl accept IPv4
276: * connections as well. See documentation in netannounce() for
277: * more details.
278: */
279: #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
280: if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET)) {
281: if (test->settings->domain == AF_UNSPEC)
282: opt = 0;
283: else
284: opt = 1;
285: if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
286: (char *) &opt, sizeof(opt)) < 0) {
287: saved_errno = errno;
288: close(s);
289: freeaddrinfo(res);
290: errno = saved_errno;
291: i_errno = IEV6ONLY;
292: return -1;
293: }
294: }
295: #endif /* IPV6_V6ONLY */
296:
297: if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
298: saved_errno = errno;
299: close(s);
300: freeaddrinfo(res);
301: errno = saved_errno;
302: i_errno = IESTREAMLISTEN;
303: return -1;
304: }
305:
306: freeaddrinfo(res);
307:
308: if (listen(s, 5) < 0) {
309: i_errno = IESTREAMLISTEN;
310: return -1;
311: }
312:
313: test->listener = s;
314: }
315:
316: return s;
317: }
318:
319:
320: /* iperf_tcp_connect
321: *
322: * connect to a TCP stream listener
323: */
324: int
325: iperf_tcp_connect(struct iperf_test *test)
326: {
327: struct addrinfo hints, *local_res, *server_res;
328: char portstr[6];
329: int s, opt;
330: int saved_errno;
331:
332: if (test->bind_address) {
333: memset(&hints, 0, sizeof(hints));
334: hints.ai_family = test->settings->domain;
335: hints.ai_socktype = SOCK_STREAM;
336: if (getaddrinfo(test->bind_address, NULL, &hints, &local_res) != 0) {
337: i_errno = IESTREAMCONNECT;
338: return -1;
339: }
340: }
341:
342: memset(&hints, 0, sizeof(hints));
343: hints.ai_family = test->settings->domain;
344: hints.ai_socktype = SOCK_STREAM;
345: snprintf(portstr, sizeof(portstr), "%d", test->server_port);
346: if (getaddrinfo(test->server_hostname, portstr, &hints, &server_res) != 0) {
347: if (test->bind_address)
348: freeaddrinfo(local_res);
349: i_errno = IESTREAMCONNECT;
350: return -1;
351: }
352:
353: if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) {
354: if (test->bind_address)
355: freeaddrinfo(local_res);
356: freeaddrinfo(server_res);
357: i_errno = IESTREAMCONNECT;
358: return -1;
359: }
360:
361: if (test->bind_address) {
362: struct sockaddr_in *lcladdr;
363: lcladdr = (struct sockaddr_in *)local_res->ai_addr;
364: lcladdr->sin_port = htons(test->bind_port);
365: local_res->ai_addr = (struct sockaddr *)lcladdr;
366:
367: if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
368: saved_errno = errno;
369: close(s);
370: freeaddrinfo(local_res);
371: freeaddrinfo(server_res);
372: errno = saved_errno;
373: i_errno = IESTREAMCONNECT;
374: return -1;
375: }
376: freeaddrinfo(local_res);
377: }
378:
379: /* Set socket options */
380: if (test->no_delay) {
381: opt = 1;
382: if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
383: saved_errno = errno;
384: close(s);
385: freeaddrinfo(server_res);
386: errno = saved_errno;
387: i_errno = IESETNODELAY;
388: return -1;
389: }
390: }
391: if ((opt = test->settings->mss)) {
392: if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
393: saved_errno = errno;
394: close(s);
395: freeaddrinfo(server_res);
396: errno = saved_errno;
397: i_errno = IESETMSS;
398: return -1;
399: }
400: }
401: if ((opt = test->settings->socket_bufsize)) {
402: if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
403: saved_errno = errno;
404: close(s);
405: freeaddrinfo(server_res);
406: errno = saved_errno;
407: i_errno = IESETBUF;
408: return -1;
409: }
410: if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
411: saved_errno = errno;
412: close(s);
413: freeaddrinfo(server_res);
414: errno = saved_errno;
415: i_errno = IESETBUF;
416: return -1;
417: }
418: }
419: if (test->debug) {
420: socklen_t optlen = sizeof(opt);
421: if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, &optlen) < 0) {
422: saved_errno = errno;
423: close(s);
424: freeaddrinfo(server_res);
425: errno = saved_errno;
426: i_errno = IESETBUF;
427: return -1;
428: }
429: printf("SO_SNDBUF is %u\n", opt);
430: }
431: #if defined(HAVE_FLOWLABEL)
432: if (test->settings->flowlabel) {
433: if (server_res->ai_addr->sa_family != AF_INET6) {
434: saved_errno = errno;
435: close(s);
436: freeaddrinfo(server_res);
437: errno = saved_errno;
438: i_errno = IESETFLOW;
439: return -1;
440: } else {
441: struct sockaddr_in6* sa6P = (struct sockaddr_in6*) server_res->ai_addr;
442: char freq_buf[sizeof(struct in6_flowlabel_req)];
443: struct in6_flowlabel_req *freq = (struct in6_flowlabel_req *)freq_buf;
444: int freq_len = sizeof(*freq);
445:
446: memset(freq, 0, sizeof(*freq));
447: freq->flr_label = htonl(test->settings->flowlabel & IPV6_FLOWINFO_FLOWLABEL);
448: freq->flr_action = IPV6_FL_A_GET;
449: freq->flr_flags = IPV6_FL_F_CREATE;
450: freq->flr_share = IPV6_FL_F_CREATE | IPV6_FL_S_EXCL;
451: memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16);
452:
453: if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) {
454: saved_errno = errno;
455: close(s);
456: freeaddrinfo(server_res);
457: errno = saved_errno;
458: i_errno = IESETFLOW;
459: return -1;
460: }
461: sa6P->sin6_flowinfo = freq->flr_label;
462:
463: opt = 1;
464: if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &opt, sizeof(opt)) < 0) {
465: saved_errno = errno;
466: close(s);
467: freeaddrinfo(server_res);
468: errno = saved_errno;
469: i_errno = IESETFLOW;
470: return -1;
471: }
472: }
473: }
474: #endif /* HAVE_FLOWLABEL */
475:
476: #if defined(HAVE_TCP_CONGESTION)
477: if (test->congestion) {
478: if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
479: close(s);
480: freeaddrinfo(server_res);
481: i_errno = IESETCONGESTION;
482: return -1;
483: }
484: }
485: #endif /* HAVE_TCP_CONGESTION */
486:
487: #if defined(HAVE_SO_MAX_PACING_RATE)
488: /* If socket pacing is available and not disabled, try it. */
489: if (! test->no_fq_socket_pacing) {
490: /* Convert bits per second to bytes per second */
491: unsigned int rate = test->settings->rate / 8;
492: if (rate > 0) {
493: if (test->debug) {
494: printf("Socket pacing set to %u\n", rate);
495: }
496: if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &rate, sizeof(rate)) < 0) {
497: warning("Unable to set socket pacing, using application pacing instead");
498: test->no_fq_socket_pacing = 1;
499: }
500: }
501: }
502: #endif /* HAVE_SO_MAX_PACING_RATE */
503:
504: if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
505: saved_errno = errno;
506: close(s);
507: freeaddrinfo(server_res);
508: errno = saved_errno;
509: i_errno = IESTREAMCONNECT;
510: return -1;
511: }
512:
513: freeaddrinfo(server_res);
514:
515: /* Send cookie for verification */
516: if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
517: saved_errno = errno;
518: close(s);
519: errno = saved_errno;
520: i_errno = IESENDCOOKIE;
521: return -1;
522: }
523:
524: return s;
525: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>