1: /*
2: * iperf, Copyright (c) 2014-2022, 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 <arpa/inet.h>
33: #include <sys/socket.h>
34: #include <sys/types.h>
35: #include <netinet/in.h>
36: #include <netdb.h>
37: #include <sys/time.h>
38: #include <sys/select.h>
39: #include <limits.h>
40:
41: #include "iperf.h"
42: #include "iperf_api.h"
43: #include "iperf_tcp.h"
44: #include "net.h"
45: #include "cjson.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: /* Only count bytes received while we're in the correct state. */
66: if (sp->test->state == TEST_RUNNING) {
67: sp->result->bytes_received += r;
68: sp->result->bytes_received_this_interval += r;
69: }
70: else {
71: if (sp->test->debug)
72: printf("Late receive, state = %d\n", sp->test->state);
73: }
74:
75: return r;
76: }
77:
78:
79: /* iperf_tcp_send
80: *
81: * sends the data for TCP
82: */
83: int
84: iperf_tcp_send(struct iperf_stream *sp)
85: {
86: int r;
87:
88: if (!sp->pending_size)
89: sp->pending_size = sp->settings->blksize;
90:
91: if (sp->test->zerocopy)
92: r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->pending_size);
93: else
94: r = Nwrite(sp->socket, sp->buffer, sp->pending_size, Ptcp);
95:
96: if (r < 0)
97: return r;
98:
99: sp->pending_size -= r;
100: sp->result->bytes_sent += r;
101: sp->result->bytes_sent_this_interval += r;
102:
103: if (sp->test->debug_level >= DEBUG_LEVEL_DEBUG)
104: printf("sent %d bytes of %d, pending %d, total %" PRIu64 "\n",
105: r, sp->settings->blksize, sp->pending_size, sp->result->bytes_sent);
106:
107: return r;
108: }
109:
110:
111: /* iperf_tcp_accept
112: *
113: * accept a new TCP stream connection
114: */
115: int
116: iperf_tcp_accept(struct iperf_test * test)
117: {
118: int s;
119: signed char rbuf = ACCESS_DENIED;
120: char cookie[COOKIE_SIZE];
121: socklen_t len;
122: struct sockaddr_storage addr;
123:
124: len = sizeof(addr);
125: if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
126: i_errno = IESTREAMCONNECT;
127: return -1;
128: }
129:
130: if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
131: i_errno = IERECVCOOKIE;
132: return -1;
133: }
134:
135: if (strcmp(test->cookie, cookie) != 0) {
136: if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
137: iperf_err(test, "failed to send access denied from busy server to new connecting client, errno = %d\n", errno);
138: }
139: close(s);
140: }
141:
142: return s;
143: }
144:
145:
146: /* iperf_tcp_listen
147: *
148: * start up a listener for TCP stream connections
149: */
150: int
151: iperf_tcp_listen(struct iperf_test *test)
152: {
153: int s, opt;
154: socklen_t optlen;
155: int saved_errno;
156: int rcvbuf_actual, sndbuf_actual;
157:
158: s = test->listener;
159:
160: /*
161: * If certain parameters are specified (such as socket buffer
162: * size), then throw away the listening socket (the one for which
163: * we just accepted the control connection) and recreate it with
164: * those parameters. That way, when new data connections are
165: * set, they'll have all the correct parameters in place.
166: *
167: * It's not clear whether this is a requirement or a convenience.
168: */
169: if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
170: struct addrinfo hints, *res;
171: char portstr[6];
172:
173: FD_CLR(s, &test->read_set);
174: close(s);
175:
176: snprintf(portstr, 6, "%d", test->server_port);
177: memset(&hints, 0, sizeof(hints));
178:
179: /*
180: * If binding to the wildcard address with no explicit address
181: * family specified, then force us to get an AF_INET6 socket.
182: * More details in the comments in netanounce().
183: */
184: if (test->settings->domain == AF_UNSPEC && !test->bind_address) {
185: hints.ai_family = AF_INET6;
186: }
187: else {
188: hints.ai_family = test->settings->domain;
189: }
190: hints.ai_socktype = SOCK_STREAM;
191: hints.ai_flags = AI_PASSIVE;
192: if ((gerror = getaddrinfo(test->bind_address, portstr, &hints, &res)) != 0) {
193: i_errno = IESTREAMLISTEN;
194: return -1;
195: }
196:
197: if ((s = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
198: freeaddrinfo(res);
199: i_errno = IESTREAMLISTEN;
200: return -1;
201: }
202:
203: if (test->no_delay) {
204: opt = 1;
205: if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
206: saved_errno = errno;
207: close(s);
208: freeaddrinfo(res);
209: errno = saved_errno;
210: i_errno = IESETNODELAY;
211: return -1;
212: }
213: }
214: // XXX: Setting MSS is very buggy!
215: if ((opt = test->settings->mss)) {
216: if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
217: saved_errno = errno;
218: close(s);
219: freeaddrinfo(res);
220: errno = saved_errno;
221: i_errno = IESETMSS;
222: return -1;
223: }
224: }
225: if ((opt = test->settings->socket_bufsize)) {
226: if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
227: saved_errno = errno;
228: close(s);
229: freeaddrinfo(res);
230: errno = saved_errno;
231: i_errno = IESETBUF;
232: return -1;
233: }
234: if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
235: saved_errno = errno;
236: close(s);
237: freeaddrinfo(res);
238: errno = saved_errno;
239: i_errno = IESETBUF;
240: return -1;
241: }
242: }
243: #if defined(HAVE_SO_MAX_PACING_RATE)
244: /* If fq socket pacing is specified, enable it. */
245: if (test->settings->fqrate) {
246: /* Convert bits per second to bytes per second */
247: unsigned int fqrate = test->settings->fqrate / 8;
248: if (fqrate > 0) {
249: if (test->debug) {
250: printf("Setting fair-queue socket pacing to %u\n", fqrate);
251: }
252: if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
253: warning("Unable to set socket pacing");
254: }
255: }
256: }
257: #endif /* HAVE_SO_MAX_PACING_RATE */
258: {
259: unsigned int rate = test->settings->rate / 8;
260: if (rate > 0) {
261: if (test->debug) {
262: printf("Setting application pacing to %u\n", rate);
263: }
264: }
265: }
266: opt = 1;
267: if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
268: saved_errno = errno;
269: close(s);
270: freeaddrinfo(res);
271: errno = saved_errno;
272: i_errno = IEREUSEADDR;
273: return -1;
274: }
275:
276: /*
277: * If we got an IPv6 socket, figure out if it should accept IPv4
278: * connections as well. See documentation in netannounce() for
279: * more details.
280: */
281: #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
282: if (res->ai_family == AF_INET6 && (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET)) {
283: if (test->settings->domain == AF_UNSPEC)
284: opt = 0;
285: else
286: opt = 1;
287: if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
288: (char *) &opt, sizeof(opt)) < 0) {
289: saved_errno = errno;
290: close(s);
291: freeaddrinfo(res);
292: errno = saved_errno;
293: i_errno = IEV6ONLY;
294: return -1;
295: }
296: }
297: #endif /* IPV6_V6ONLY */
298:
299: if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
300: saved_errno = errno;
301: close(s);
302: freeaddrinfo(res);
303: errno = saved_errno;
304: i_errno = IESTREAMLISTEN;
305: return -1;
306: }
307:
308: freeaddrinfo(res);
309:
310: if (listen(s, INT_MAX) < 0) {
311: i_errno = IESTREAMLISTEN;
312: return -1;
313: }
314:
315: test->listener = s;
316: }
317:
318: /* Read back and verify the sender socket buffer size */
319: optlen = sizeof(sndbuf_actual);
320: if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) {
321: saved_errno = errno;
322: close(s);
323: errno = saved_errno;
324: i_errno = IESETBUF;
325: return -1;
326: }
327: if (test->debug) {
328: printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize);
329: }
330: if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) {
331: i_errno = IESETBUF2;
332: return -1;
333: }
334:
335: /* Read back and verify the receiver socket buffer size */
336: optlen = sizeof(rcvbuf_actual);
337: if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) {
338: saved_errno = errno;
339: close(s);
340: errno = saved_errno;
341: i_errno = IESETBUF;
342: return -1;
343: }
344: if (test->debug) {
345: printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize);
346: }
347: if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) {
348: i_errno = IESETBUF2;
349: return -1;
350: }
351:
352: if (test->json_output) {
353: cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize);
354: cJSON_AddNumberToObject(test->json_start, "sndbuf_actual", sndbuf_actual);
355: cJSON_AddNumberToObject(test->json_start, "rcvbuf_actual", rcvbuf_actual);
356: }
357:
358: return s;
359: }
360:
361:
362: /* iperf_tcp_connect
363: *
364: * connect to a TCP stream listener
365: * This function is roughly similar to netdial(), and may indeed have
366: * been derived from it at some point, but it sets many TCP-specific
367: * options between socket creation and connection.
368: */
369: int
370: iperf_tcp_connect(struct iperf_test *test)
371: {
372: struct addrinfo *server_res;
373: int s, opt;
374: socklen_t optlen;
375: int saved_errno;
376: int rcvbuf_actual, sndbuf_actual;
377:
378: s = create_socket(test->settings->domain, SOCK_STREAM, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, &server_res);
379: if (s < 0) {
380: i_errno = IESTREAMCONNECT;
381: return -1;
382: }
383:
384: /* Set socket options */
385: if (test->no_delay) {
386: opt = 1;
387: if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
388: saved_errno = errno;
389: close(s);
390: freeaddrinfo(server_res);
391: errno = saved_errno;
392: i_errno = IESETNODELAY;
393: return -1;
394: }
395: }
396: if ((opt = test->settings->mss)) {
397: if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
398: saved_errno = errno;
399: close(s);
400: freeaddrinfo(server_res);
401: errno = saved_errno;
402: i_errno = IESETMSS;
403: return -1;
404: }
405: }
406: if ((opt = test->settings->socket_bufsize)) {
407: if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
408: saved_errno = errno;
409: close(s);
410: freeaddrinfo(server_res);
411: errno = saved_errno;
412: i_errno = IESETBUF;
413: return -1;
414: }
415: if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
416: saved_errno = errno;
417: close(s);
418: freeaddrinfo(server_res);
419: errno = saved_errno;
420: i_errno = IESETBUF;
421: return -1;
422: }
423: }
424: #if defined(HAVE_TCP_USER_TIMEOUT)
425: if ((opt = test->settings->snd_timeout)) {
426: if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
427: saved_errno = errno;
428: close(s);
429: freeaddrinfo(server_res);
430: errno = saved_errno;
431: i_errno = IESETUSERTIMEOUT;
432: return -1;
433: }
434: }
435: #endif /* HAVE_TCP_USER_TIMEOUT */
436:
437: /* Read back and verify the sender socket buffer size */
438: optlen = sizeof(sndbuf_actual);
439: if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_actual, &optlen) < 0) {
440: saved_errno = errno;
441: close(s);
442: freeaddrinfo(server_res);
443: errno = saved_errno;
444: i_errno = IESETBUF;
445: return -1;
446: }
447: if (test->debug) {
448: printf("SNDBUF is %u, expecting %u\n", sndbuf_actual, test->settings->socket_bufsize);
449: }
450: if (test->settings->socket_bufsize && test->settings->socket_bufsize > sndbuf_actual) {
451: i_errno = IESETBUF2;
452: return -1;
453: }
454:
455: /* Read back and verify the receiver socket buffer size */
456: optlen = sizeof(rcvbuf_actual);
457: if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf_actual, &optlen) < 0) {
458: saved_errno = errno;
459: close(s);
460: freeaddrinfo(server_res);
461: errno = saved_errno;
462: i_errno = IESETBUF;
463: return -1;
464: }
465: if (test->debug) {
466: printf("RCVBUF is %u, expecting %u\n", rcvbuf_actual, test->settings->socket_bufsize);
467: }
468: if (test->settings->socket_bufsize && test->settings->socket_bufsize > rcvbuf_actual) {
469: i_errno = IESETBUF2;
470: return -1;
471: }
472:
473: if (test->json_output) {
474: cJSON *sock_bufsize_item = cJSON_GetObjectItem(test->json_start, "sock_bufsize");
475: if (sock_bufsize_item == NULL) {
476: cJSON_AddNumberToObject(test->json_start, "sock_bufsize", test->settings->socket_bufsize);
477: }
478:
479: cJSON *sndbuf_actual_item = cJSON_GetObjectItem(test->json_start, "sndbuf_actual");
480: if (sndbuf_actual_item == NULL) {
481: cJSON_AddNumberToObject(test->json_start, "sndbuf_actual", sndbuf_actual);
482: }
483:
484: cJSON *rcvbuf_actual_item = cJSON_GetObjectItem(test->json_start, "rcvbuf_actual");
485: if (rcvbuf_actual_item == NULL) {
486: cJSON_AddNumberToObject(test->json_start, "rcvbuf_actual", rcvbuf_actual);
487: }
488: }
489:
490: #if defined(HAVE_FLOWLABEL)
491: if (test->settings->flowlabel) {
492: if (server_res->ai_addr->sa_family != AF_INET6) {
493: saved_errno = errno;
494: close(s);
495: freeaddrinfo(server_res);
496: errno = saved_errno;
497: i_errno = IESETFLOW;
498: return -1;
499: } else {
500: struct sockaddr_in6* sa6P = (struct sockaddr_in6*) server_res->ai_addr;
501: char freq_buf[sizeof(struct in6_flowlabel_req)];
502: struct in6_flowlabel_req *freq = (struct in6_flowlabel_req *)freq_buf;
503: int freq_len = sizeof(*freq);
504:
505: memset(freq, 0, sizeof(*freq));
506: freq->flr_label = htonl(test->settings->flowlabel & IPV6_FLOWINFO_FLOWLABEL);
507: freq->flr_action = IPV6_FL_A_GET;
508: freq->flr_flags = IPV6_FL_F_CREATE;
509: freq->flr_share = IPV6_FL_S_ANY;
510: memcpy(&freq->flr_dst, &sa6P->sin6_addr, 16);
511:
512: if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR, freq, freq_len) < 0) {
513: saved_errno = errno;
514: close(s);
515: freeaddrinfo(server_res);
516: errno = saved_errno;
517: i_errno = IESETFLOW;
518: return -1;
519: }
520: sa6P->sin6_flowinfo = freq->flr_label;
521:
522: opt = 1;
523: if (setsockopt(s, IPPROTO_IPV6, IPV6_FLOWINFO_SEND, &opt, sizeof(opt)) < 0) {
524: saved_errno = errno;
525: close(s);
526: freeaddrinfo(server_res);
527: errno = saved_errno;
528: i_errno = IESETFLOW;
529: return -1;
530: }
531: }
532: }
533: #endif /* HAVE_FLOWLABEL */
534:
535: #if defined(HAVE_SO_MAX_PACING_RATE)
536: /* If socket pacing is specified try to enable it. */
537: if (test->settings->fqrate) {
538: /* Convert bits per second to bytes per second */
539: unsigned int fqrate = test->settings->fqrate / 8;
540: if (fqrate > 0) {
541: if (test->debug) {
542: printf("Setting fair-queue socket pacing to %u\n", fqrate);
543: }
544: if (setsockopt(s, SOL_SOCKET, SO_MAX_PACING_RATE, &fqrate, sizeof(fqrate)) < 0) {
545: warning("Unable to set socket pacing");
546: }
547: }
548: }
549: #endif /* HAVE_SO_MAX_PACING_RATE */
550: {
551: unsigned int rate = test->settings->rate / 8;
552: if (rate > 0) {
553: if (test->debug) {
554: printf("Setting application pacing to %u\n", rate);
555: }
556: }
557: }
558:
559: /* Set common socket options */
560: iperf_common_sockopts(test, s);
561:
562: if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
563: saved_errno = errno;
564: close(s);
565: freeaddrinfo(server_res);
566: errno = saved_errno;
567: i_errno = IESTREAMCONNECT;
568: return -1;
569: }
570:
571: freeaddrinfo(server_res);
572:
573: /* Send cookie for verification */
574: if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
575: saved_errno = errno;
576: close(s);
577: errno = saved_errno;
578: i_errno = IESENDCOOKIE;
579: return -1;
580: }
581:
582: return s;
583: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>