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 [email protected].
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 <errno.h>
28 #include <setjmp.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <signal.h>
34 #include <sys/types.h>
35 #include <netinet/in.h>
36 #include <sys/select.h>
37 #include <sys/uio.h>
38 #include <arpa/inet.h>
39
40 #include "iperf.h"
41 #include "iperf_api.h"
42 #include "iperf_util.h"
43 #include "iperf_locale.h"
44 #include "iperf_time.h"
45 #include "net.h"
46 #include "timer.h"
47
48 #if defined(HAVE_TCP_CONGESTION)
49 #if !defined(TCP_CA_NAME_MAX)
50 #define TCP_CA_NAME_MAX 16
51 #endif /* TCP_CA_NAME_MAX */
52 #endif /* HAVE_TCP_CONGESTION */
53
54 int
iperf_create_streams(struct iperf_test * test,int sender)55 iperf_create_streams(struct iperf_test *test, int sender)
56 {
57 if (NULL == test)
58 {
59 iperf_err(NULL, "No test\n");
60 return -1;
61 }
62 int i, s;
63 #if defined(HAVE_TCP_CONGESTION)
64 int saved_errno;
65 #endif /* HAVE_TCP_CONGESTION */
66 struct iperf_stream *sp;
67
68 int orig_bind_port = test->bind_port;
69 for (i = 0; i < test->num_streams; ++i) {
70
71 test->bind_port = orig_bind_port;
72 if (orig_bind_port) {
73 test->bind_port += i;
74 // If Bidir make sure send and receive ports are different
75 if (!sender && test->mode == BIDIRECTIONAL)
76 test->bind_port += test->num_streams;
77 }
78 s = test->protocol->connect(test);
79 test->bind_port = orig_bind_port;
80 if (s < 0)
81 return -1;
82
83 #if defined(HAVE_TCP_CONGESTION)
84 if (test->protocol->id == Ptcp) {
85 if (test->congestion) {
86 if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
87 saved_errno = errno;
88 close(s);
89 errno = saved_errno;
90 i_errno = IESETCONGESTION;
91 return -1;
92 }
93 }
94 {
95 socklen_t len = TCP_CA_NAME_MAX;
96 char ca[TCP_CA_NAME_MAX + 1];
97 int rc;
98 rc = getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len);
99 if (rc < 0 && test->congestion) {
100 saved_errno = errno;
101 close(s);
102 errno = saved_errno;
103 i_errno = IESETCONGESTION;
104 return -1;
105 }
106 // Set actual used congestion alg, or set to unknown if could not get it
107 if (rc < 0)
108 test->congestion_used = strdup("unknown");
109 else
110 test->congestion_used = strdup(ca);
111 if (test->debug) {
112 printf("Congestion algorithm is %s\n", test->congestion_used);
113 }
114 }
115 }
116 #endif /* HAVE_TCP_CONGESTION */
117
118 if (sender)
119 FD_SET(s, &test->write_set);
120 else
121 FD_SET(s, &test->read_set);
122 if (s > test->max_fd) test->max_fd = s;
123
124 sp = iperf_new_stream(test, s, sender);
125 if (!sp)
126 return -1;
127
128 /* Perform the new stream callback */
129 if (test->on_new_stream)
130 test->on_new_stream(sp);
131 }
132
133 return 0;
134 }
135
136 static void
test_timer_proc(TimerClientData client_data,struct iperf_time * nowP)137 test_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
138 {
139 struct iperf_test *test = client_data.p;
140
141 test->timer = NULL;
142 test->done = 1;
143 }
144
145 static void
client_stats_timer_proc(TimerClientData client_data,struct iperf_time * nowP)146 client_stats_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
147 {
148 struct iperf_test *test = client_data.p;
149
150 if (test->done)
151 return;
152 if (test->stats_callback)
153 test->stats_callback(test);
154 }
155
156 static void
client_reporter_timer_proc(TimerClientData client_data,struct iperf_time * nowP)157 client_reporter_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
158 {
159 struct iperf_test *test = client_data.p;
160
161 if (test->done)
162 return;
163 if (test->reporter_callback)
164 test->reporter_callback(test);
165 }
166
167 static int
create_client_timers(struct iperf_test * test)168 create_client_timers(struct iperf_test * test)
169 {
170 struct iperf_time now;
171 TimerClientData cd;
172 if (NULL == test)
173 {
174 iperf_err(NULL, "No test\n");
175 i_errno = IEINITTEST;
176 return -1;
177 }
178
179 if (iperf_time_now(&now) < 0) {
180 i_errno = IEINITTEST;
181 return -1;
182 }
183 cd.p = test;
184 test->timer = test->stats_timer = test->reporter_timer = NULL;
185 if (test->duration != 0) {
186 test->done = 0;
187 test->timer = tmr_create(&now, test_timer_proc, cd, ( test->duration + test->omit ) * SEC_TO_US, 0);
188 if (test->timer == NULL) {
189 i_errno = IEINITTEST;
190 return -1;
191 }
192 }
193 if (test->stats_interval != 0) {
194 test->stats_timer = tmr_create(&now, client_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
195 if (test->stats_timer == NULL) {
196 i_errno = IEINITTEST;
197 return -1;
198 }
199 }
200 if (test->reporter_interval != 0) {
201 test->reporter_timer = tmr_create(&now, client_reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1);
202 if (test->reporter_timer == NULL) {
203 i_errno = IEINITTEST;
204 return -1;
205 }
206 }
207 return 0;
208 }
209
210 static void
client_omit_timer_proc(TimerClientData client_data,struct iperf_time * nowP)211 client_omit_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
212 {
213 struct iperf_test *test = client_data.p;
214
215 test->omit_timer = NULL;
216 test->omitting = 0;
217 iperf_reset_stats(test);
218 if (test->verbose && !test->json_output && test->reporter_interval == 0)
219 iperf_printf(test, "%s", report_omit_done);
220
221 /* Reset the timers. */
222 if (test->stats_timer != NULL)
223 tmr_reset(nowP, test->stats_timer);
224 if (test->reporter_timer != NULL)
225 tmr_reset(nowP, test->reporter_timer);
226 }
227
228 static int
create_client_omit_timer(struct iperf_test * test)229 create_client_omit_timer(struct iperf_test * test)
230 {
231 struct iperf_time now;
232 TimerClientData cd;
233 if (NULL == test)
234 {
235 iperf_err(NULL, "No test\n");
236 return -1;
237 }
238
239 if (test->omit == 0) {
240 test->omit_timer = NULL;
241 test->omitting = 0;
242 } else {
243 if (iperf_time_now(&now) < 0) {
244 i_errno = IEINITTEST;
245 return -1;
246 }
247 test->omitting = 1;
248 cd.p = test;
249 test->omit_timer = tmr_create(&now, client_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
250 if (test->omit_timer == NULL) {
251 i_errno = IEINITTEST;
252 return -1;
253 }
254 }
255 return 0;
256 }
257
258 int
iperf_handle_message_client(struct iperf_test * test)259 iperf_handle_message_client(struct iperf_test *test)
260 {
261 int rval;
262 int32_t err;
263
264 if (NULL == test)
265 {
266 iperf_err(NULL, "No test\n");
267 i_errno = IEINITTEST;
268 return -1;
269 }
270 /*!!! Why is this read() and not Nread()? */
271 if ((rval = read(test->ctrl_sck, (char*) &test->state, sizeof(signed char))) <= 0) {
272 if (rval == 0) {
273 i_errno = IECTRLCLOSE;
274 return -1;
275 } else {
276 i_errno = IERECVMESSAGE;
277 return -1;
278 }
279 }
280
281 switch (test->state) {
282 case PARAM_EXCHANGE:
283 if (iperf_exchange_parameters(test) < 0)
284 return -1;
285 if (test->on_connect)
286 test->on_connect(test);
287 break;
288 case CREATE_STREAMS:
289 if (test->mode == BIDIRECTIONAL)
290 {
291 if (iperf_create_streams(test, 1) < 0)
292 return -1;
293 if (iperf_create_streams(test, 0) < 0)
294 return -1;
295 }
296 else if (iperf_create_streams(test, test->mode) < 0)
297 return -1;
298 break;
299 case TEST_START:
300 if (iperf_init_test(test) < 0)
301 return -1;
302 if (create_client_timers(test) < 0)
303 return -1;
304 if (create_client_omit_timer(test) < 0)
305 return -1;
306 if (test->mode)
307 if (iperf_create_send_timers(test) < 0)
308 return -1;
309 break;
310 case TEST_RUNNING:
311 break;
312 case EXCHANGE_RESULTS:
313 if (iperf_exchange_results(test) < 0)
314 return -1;
315 break;
316 case DISPLAY_RESULTS:
317 if (test->on_test_finish)
318 test->on_test_finish(test);
319 iperf_client_end(test);
320 break;
321 case IPERF_DONE:
322 break;
323 case SERVER_TERMINATE:
324 i_errno = IESERVERTERM;
325
326 /*
327 * Temporarily be in DISPLAY_RESULTS phase so we can get
328 * ending summary statistics.
329 */
330 signed char oldstate = test->state;
331 cpu_util(test->cpu_util);
332 test->state = DISPLAY_RESULTS;
333 test->reporter_callback(test);
334 test->state = oldstate;
335 return -1;
336 case ACCESS_DENIED:
337 i_errno = IEACCESSDENIED;
338 return -1;
339 case SERVER_ERROR:
340 if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
341 i_errno = IECTRLREAD;
342 return -1;
343 }
344 i_errno = ntohl(err);
345 if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
346 i_errno = IECTRLREAD;
347 return -1;
348 }
349 errno = ntohl(err);
350 return -1;
351 default:
352 i_errno = IEMESSAGE;
353 return -1;
354 }
355
356 return 0;
357 }
358
359
360
361 /* iperf_connect -- client to server connection function */
362 int
iperf_connect(struct iperf_test * test)363 iperf_connect(struct iperf_test *test)
364 {
365 int opt;
366 socklen_t len;
367
368 if (NULL == test)
369 {
370 iperf_err(NULL, "No test\n");
371 return -1;
372 }
373 FD_ZERO(&test->read_set);
374 FD_ZERO(&test->write_set);
375
376 make_cookie(test->cookie);
377
378 /* Create and connect the control channel */
379 if (test->ctrl_sck < 0)
380 // Create the control channel using an ephemeral port
381 test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, 0, test->server_hostname, test->server_port, test->settings->connect_timeout);
382 if (test->ctrl_sck < 0) {
383 i_errno = IECONNECT;
384 return -1;
385 }
386
387 // set TCP_NODELAY for lower latency on control messages
388 int flag = 1;
389 if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int))) {
390 i_errno = IESETNODELAY;
391 return -1;
392 }
393
394 #if defined(HAVE_TCP_USER_TIMEOUT)
395 if ((opt = test->settings->snd_timeout)) {
396 if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
397 i_errno = IESETUSERTIMEOUT;
398 return -1;
399 }
400 }
401 #endif /* HAVE_TCP_USER_TIMEOUT */
402
403 if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
404 i_errno = IESENDCOOKIE;
405 return -1;
406 }
407
408 FD_SET(test->ctrl_sck, &test->read_set);
409 if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;
410
411 len = sizeof(opt);
412 if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) {
413 test->ctrl_sck_mss = 0;
414 }
415 else {
416 if (opt > 0 && opt <= MAX_UDP_BLOCKSIZE) {
417 test->ctrl_sck_mss = opt;
418 }
419 else {
420 char str[WARN_STR_LEN];
421 snprintf(str, sizeof(str),
422 "Ignoring nonsense TCP MSS %d", opt);
423 warning(str);
424
425 test->ctrl_sck_mss = 0;
426 }
427 }
428
429 if (test->verbose) {
430 printf("Control connection MSS %d\n", test->ctrl_sck_mss);
431 }
432
433 /*
434 * If we're doing a UDP test and the block size wasn't explicitly
435 * set, then use the known MSS of the control connection to pick
436 * an appropriate default. If we weren't able to get the
437 * MSS for some reason, then default to something that should
438 * work on non-jumbo-frame Ethernet networks. The goal is to
439 * pick a reasonable default that is large but should get from
440 * sender to receiver without any IP fragmentation.
441 *
442 * We assume that the control connection is routed the same as the
443 * data packets (thus has the same PMTU). Also in the case of
444 * --reverse tests, we assume that the MTU is the same in both
445 * directions. Note that even if the algorithm guesses wrong,
446 * the user always has the option to override.
447 */
448 if (test->protocol->id == Pudp) {
449 if (test->settings->blksize == 0) {
450 if (test->ctrl_sck_mss) {
451 test->settings->blksize = test->ctrl_sck_mss;
452 }
453 else {
454 test->settings->blksize = DEFAULT_UDP_BLKSIZE;
455 }
456 if (test->verbose) {
457 printf("Setting UDP block size to %d\n", test->settings->blksize);
458 }
459 }
460
461 /*
462 * Regardless of whether explicitly or implicitly set, if the
463 * block size is larger than the MSS, print a warning.
464 */
465 if (test->ctrl_sck_mss > 0 &&
466 test->settings->blksize > test->ctrl_sck_mss) {
467 char str[WARN_STR_LEN];
468 snprintf(str, sizeof(str),
469 "UDP block size %d exceeds TCP MSS %d, may result in fragmentation / drops", test->settings->blksize, test->ctrl_sck_mss);
470 warning(str);
471 }
472 }
473
474 return 0;
475 }
476
477
478 int
iperf_client_end(struct iperf_test * test)479 iperf_client_end(struct iperf_test *test)
480 {
481 if (NULL == test)
482 {
483 iperf_err(NULL, "No test\n");
484 return -1;
485 }
486 struct iperf_stream *sp;
487
488 /* Close all stream sockets */
489 SLIST_FOREACH(sp, &test->streams, streams) {
490 close(sp->socket);
491 }
492
493 /* show final summary */
494 test->reporter_callback(test);
495
496 /* Send response only if no error in server */
497 if (test->state > 0) {
498 if (iperf_set_send_state(test, IPERF_DONE) != 0)
499 return -1;
500 }
501
502 /* Close control socket */
503 if (test->ctrl_sck >= 0)
504 close(test->ctrl_sck);
505
506 return 0;
507 }
508
509
510 int
iperf_run_client(struct iperf_test * test)511 iperf_run_client(struct iperf_test * test)
512 {
513 int startup;
514 int result = 0;
515 fd_set read_set, write_set;
516 struct iperf_time now;
517 struct timeval* timeout = NULL;
518 struct iperf_stream *sp;
519 struct iperf_time last_receive_time;
520 struct iperf_time diff_time;
521 struct timeval used_timeout;
522 int64_t t_usecs;
523 int64_t timeout_us;
524 int64_t rcv_timeout_us;
525
526 if (NULL == test)
527 {
528 iperf_err(NULL, "No test\n");
529 return -1;
530 }
531
532 if (test->logfile)
533 if (iperf_open_logfile(test) < 0)
534 return -1;
535
536 if (test->affinity != -1)
537 if (iperf_setaffinity(test, test->affinity) != 0)
538 return -1;
539
540 if (test->json_output)
541 if (iperf_json_start(test) < 0)
542 return -1;
543
544 if (test->json_output) {
545 cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
546 cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
547 } else if (test->verbose) {
548 iperf_printf(test, "%s\n", version);
549 iperf_printf(test, "%s", "");
550 iperf_printf(test, "%s\n", get_system_info());
551 iflush(test);
552 }
553
554 /* Start the client and connect to the server */
555 if (iperf_connect(test) < 0)
556 goto cleanup_and_fail;
557
558 /* Begin calculating CPU utilization */
559 cpu_util(NULL);
560 if (test->mode != SENDER)
561 rcv_timeout_us = (test->settings->rcv_timeout.secs * SEC_TO_US) + test->settings->rcv_timeout.usecs;
562 else
563 rcv_timeout_us = 0;
564
565 startup = 1;
566 while (test->state != IPERF_DONE) {
567 memcpy(&read_set, &test->read_set, sizeof(fd_set));
568 memcpy(&write_set, &test->write_set, sizeof(fd_set));
569 iperf_time_now(&now);
570 timeout = tmr_timeout(&now);
571
572 // In reverse active mode client ensures data is received
573 if (test->state == TEST_RUNNING && rcv_timeout_us > 0) {
574 timeout_us = -1;
575 if (timeout != NULL) {
576 used_timeout.tv_sec = timeout->tv_sec;
577 used_timeout.tv_usec = timeout->tv_usec;
578 timeout_us = (timeout->tv_sec * SEC_TO_US) + timeout->tv_usec;
579 }
580 if (timeout_us < 0 || timeout_us > rcv_timeout_us) {
581 used_timeout.tv_sec = test->settings->rcv_timeout.secs;
582 used_timeout.tv_usec = test->settings->rcv_timeout.usecs;
583 }
584 timeout = &used_timeout;
585 }
586
587 result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
588 if (result < 0 && errno != EINTR) {
589 i_errno = IESELECT;
590 goto cleanup_and_fail;
591 } else if (result == 0 && test->state == TEST_RUNNING && rcv_timeout_us > 0) {
592 // If nothing was received in non-reverse running state then probably something got stack -
593 // either client, server or network, and test should be terminated.
594 iperf_time_now(&now);
595 if (iperf_time_diff(&now, &last_receive_time, &diff_time) == 0) {
596 t_usecs = iperf_time_in_usecs(&diff_time);
597 if (t_usecs > rcv_timeout_us) {
598 i_errno = IENOMSG;
599 goto cleanup_and_fail;
600 }
601
602 }
603 }
604
605 if (result > 0) {
606 if (rcv_timeout_us > 0) {
607 iperf_time_now(&last_receive_time);
608 }
609 if (FD_ISSET(test->ctrl_sck, &read_set)) {
610 if (iperf_handle_message_client(test) < 0) {
611 goto cleanup_and_fail;
612 }
613 FD_CLR(test->ctrl_sck, &read_set);
614 }
615 }
616
617 if (test->state == TEST_RUNNING) {
618
619 /* Is this our first time really running? */
620 if (startup) {
621 startup = 0;
622
623 // Set non-blocking for non-UDP tests
624 if (test->protocol->id != Pudp) {
625 SLIST_FOREACH(sp, &test->streams, streams) {
626 setnonblocking(sp->socket, 1);
627 }
628 }
629 }
630
631
632 if (test->mode == BIDIRECTIONAL)
633 {
634 if (iperf_send(test, &write_set) < 0)
635 goto cleanup_and_fail;
636 if (iperf_recv(test, &read_set) < 0)
637 goto cleanup_and_fail;
638 } else if (test->mode == SENDER) {
639 // Regular mode. Client sends.
640 if (iperf_send(test, &write_set) < 0)
641 goto cleanup_and_fail;
642 } else {
643 // Reverse mode. Client receives.
644 if (iperf_recv(test, &read_set) < 0)
645 goto cleanup_and_fail;
646 }
647
648
649 /* Run the timers. */
650 iperf_time_now(&now);
651 tmr_run(&now);
652
653 /*
654 * Is the test done yet? We have to be out of omitting
655 * mode, and then we have to have fulfilled one of the
656 * ending criteria, either by times, bytes, or blocks.
657 * The bytes and blocks tests needs to handle both the
658 * cases of the client being the sender and the client
659 * being the receiver.
660 */
661 if ((!test->omitting) &&
662 (test->done ||
663 (test->settings->bytes != 0 && (test->bytes_sent >= test->settings->bytes ||
664 test->bytes_received >= test->settings->bytes)) ||
665 (test->settings->blocks != 0 && (test->blocks_sent >= test->settings->blocks ||
666 test->blocks_received >= test->settings->blocks)))) {
667
668 // Unset non-blocking for non-UDP tests
669 if (test->protocol->id != Pudp) {
670 SLIST_FOREACH(sp, &test->streams, streams) {
671 setnonblocking(sp->socket, 0);
672 }
673 }
674
675 /* Yes, done! Send TEST_END. */
676 test->done = 1;
677 cpu_util(test->cpu_util);
678 test->stats_callback(test);
679 if (iperf_set_send_state(test, TEST_END) != 0)
680 goto cleanup_and_fail;
681 }
682 }
683 // If we're in reverse mode, continue draining the data
684 // connection(s) even if test is over. This prevents a
685 // deadlock where the server side fills up its pipe(s)
686 // and gets blocked, so it can't receive state changes
687 // from the client side.
688 else if (test->mode == RECEIVER && test->state == TEST_END) {
689 if (iperf_recv(test, &read_set) < 0)
690 goto cleanup_and_fail;
691 }
692 }
693
694 if (test->json_output) {
695 if (iperf_json_finish(test) < 0)
696 return -1;
697 } else {
698 iperf_printf(test, "\n");
699 iperf_printf(test, "%s", report_done);
700 }
701
702 iflush(test);
703
704 return 0;
705
706 cleanup_and_fail:
707 iperf_client_end(test);
708 if (test->json_output) {
709 cJSON_AddStringToObject(test->json_top, "error", iperf_strerror(i_errno));
710 iperf_json_finish(test);
711 iflush(test);
712 // Return 0 and not -1 since all terminating function were done here.
713 // Also prevents error message logging outside the already closed JSON output.
714 return 0;
715 }
716 iflush(test);
717 return -1;
718 }
719