Annotation of embedaddon/iperf/src/iperf_client_api.c, revision 1.1.1.3
1.1 misho 1: /*
1.1.1.3 ! misho 2: * iperf, Copyright (c) 2014-2022, The Regents of the University of
1.1 misho 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 <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>
1.1.1.2 misho 35: #include <netinet/in.h>
1.1 misho 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"
1.1.1.2 misho 44: #include "iperf_time.h"
1.1 misho 45: #include "net.h"
46: #include "timer.h"
47:
1.1.1.2 misho 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 */
1.1 misho 53:
54: int
1.1.1.2 misho 55: iperf_create_streams(struct iperf_test *test, int sender)
1.1 misho 56: {
1.1.1.3 ! misho 57: if (NULL == test)
! 58: {
! 59: iperf_err(NULL, "No test\n");
! 60: return -1;
! 61: }
1.1 misho 62: int i, s;
1.1.1.2 misho 63: #if defined(HAVE_TCP_CONGESTION)
64: int saved_errno;
65: #endif /* HAVE_TCP_CONGESTION */
1.1 misho 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;
1.1.1.3 ! misho 72: if (orig_bind_port) {
1.1 misho 73: test->bind_port += i;
1.1.1.3 ! misho 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)
1.1 misho 81: return -1;
82:
1.1.1.2 misho 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;
1.1.1.3 ! misho 92: }
1.1.1.2 misho 93: }
94: {
95: socklen_t len = TCP_CA_NAME_MAX;
96: char ca[TCP_CA_NAME_MAX + 1];
1.1.1.3 ! misho 97: int rc;
! 98: rc = getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len);
! 99: if (rc < 0 && test->congestion) {
1.1.1.2 misho 100: saved_errno = errno;
101: close(s);
102: errno = saved_errno;
103: i_errno = IESETCONGESTION;
104: return -1;
105: }
1.1.1.3 ! misho 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);
1.1.1.2 misho 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)
1.1 misho 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:
1.1.1.2 misho 124: sp = iperf_new_stream(test, s, sender);
1.1 misho 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
1.1.1.2 misho 137: test_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
1.1 misho 138: {
139: struct iperf_test *test = client_data.p;
140:
141: test->timer = NULL;
142: test->done = 1;
143: }
144:
145: static void
1.1.1.2 misho 146: client_stats_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
1.1 misho 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
1.1.1.2 misho 157: client_reporter_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
1.1 misho 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
168: create_client_timers(struct iperf_test * test)
169: {
1.1.1.2 misho 170: struct iperf_time now;
1.1 misho 171: TimerClientData cd;
1.1.1.3 ! misho 172: if (NULL == test)
! 173: {
! 174: iperf_err(NULL, "No test\n");
! 175: i_errno = IEINITTEST;
! 176: return -1;
! 177: }
1.1 misho 178:
1.1.1.2 misho 179: if (iperf_time_now(&now) < 0) {
1.1 misho 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: }
1.1.1.3 ! misho 192: }
1.1 misho 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
1.1.1.2 misho 211: client_omit_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
1.1 misho 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)
1.1.1.2 misho 219: iperf_printf(test, "%s", report_omit_done);
1.1 misho 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
229: create_client_omit_timer(struct iperf_test * test)
230: {
1.1.1.2 misho 231: struct iperf_time now;
1.1 misho 232: TimerClientData cd;
1.1.1.3 ! misho 233: if (NULL == test)
! 234: {
! 235: iperf_err(NULL, "No test\n");
! 236: return -1;
! 237: }
1.1 misho 238:
239: if (test->omit == 0) {
240: test->omit_timer = NULL;
241: test->omitting = 0;
242: } else {
1.1.1.2 misho 243: if (iperf_time_now(&now) < 0) {
1.1 misho 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
259: iperf_handle_message_client(struct iperf_test *test)
260: {
261: int rval;
262: int32_t err;
263:
1.1.1.3 ! misho 264: if (NULL == test)
! 265: {
! 266: iperf_err(NULL, "No test\n");
! 267: i_errno = IEINITTEST;
! 268: return -1;
! 269: }
1.1 misho 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:
1.1.1.2 misho 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)
1.1 misho 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;
1.1.1.2 misho 306: if (test->mode)
1.1 misho 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
363: iperf_connect(struct iperf_test *test)
364: {
1.1.1.3 ! misho 365: int opt;
! 366: socklen_t len;
! 367:
! 368: if (NULL == test)
! 369: {
! 370: iperf_err(NULL, "No test\n");
! 371: return -1;
! 372: }
1.1 misho 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
1.1.1.3 ! misho 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);
1.1 misho 382: if (test->ctrl_sck < 0) {
383: i_errno = IECONNECT;
384: return -1;
385: }
386:
1.1.1.3 ! misho 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:
1.1 misho 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:
1.1.1.2 misho 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 {
1.1.1.3 ! misho 420: char str[WARN_STR_LEN];
1.1.1.2 misho 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) {
1.1.1.3 ! misho 467: char str[WARN_STR_LEN];
1.1.1.2 misho 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:
1.1 misho 474: return 0;
475: }
476:
477:
478: int
479: iperf_client_end(struct iperf_test *test)
480: {
1.1.1.3 ! misho 481: if (NULL == test)
! 482: {
! 483: iperf_err(NULL, "No test\n");
! 484: return -1;
! 485: }
1.1 misho 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:
1.1.1.3 ! misho 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: }
1.1 misho 501:
1.1.1.2 misho 502: /* Close control socket */
1.1.1.3 ! misho 503: if (test->ctrl_sck >= 0)
1.1.1.2 misho 504: close(test->ctrl_sck);
505:
1.1 misho 506: return 0;
507: }
508:
509:
510: int
511: iperf_run_client(struct iperf_test * test)
512: {
513: int startup;
514: int result = 0;
515: fd_set read_set, write_set;
1.1.1.2 misho 516: struct iperf_time now;
1.1 misho 517: struct timeval* timeout = NULL;
518: struct iperf_stream *sp;
1.1.1.3 ! misho 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: }
1.1 misho 531:
1.1.1.2 misho 532: if (test->logfile)
533: if (iperf_open_logfile(test) < 0)
534: return -1;
535:
1.1 misho 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) {
1.1.1.2 misho 548: iperf_printf(test, "%s\n", version);
549: iperf_printf(test, "%s", "");
550: iperf_printf(test, "%s\n", get_system_info());
1.1 misho 551: iflush(test);
552: }
553:
554: /* Start the client and connect to the server */
555: if (iperf_connect(test) < 0)
1.1.1.2 misho 556: goto cleanup_and_fail;
1.1 misho 557:
558: /* Begin calculating CPU utilization */
559: cpu_util(NULL);
1.1.1.3 ! misho 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;
1.1 misho 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));
1.1.1.2 misho 569: iperf_time_now(&now);
1.1 misho 570: timeout = tmr_timeout(&now);
1.1.1.3 ! misho 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:
1.1 misho 587: result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
588: if (result < 0 && errno != EINTR) {
589: i_errno = IESELECT;
1.1.1.2 misho 590: goto cleanup_and_fail;
1.1.1.3 ! misho 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:
1.1 misho 605: if (result > 0) {
1.1.1.3 ! misho 606: if (rcv_timeout_us > 0) {
! 607: iperf_time_now(&last_receive_time);
! 608: }
1.1 misho 609: if (FD_ISSET(test->ctrl_sck, &read_set)) {
610: if (iperf_handle_message_client(test) < 0) {
1.1.1.2 misho 611: goto cleanup_and_fail;
1.1 misho 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:
1.1.1.2 misho 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;
1.1 misho 642: } else {
1.1.1.2 misho 643: // Reverse mode. Client receives.
644: if (iperf_recv(test, &read_set) < 0)
645: goto cleanup_and_fail;
1.1 misho 646: }
647:
1.1.1.2 misho 648:
1.1 misho 649: /* Run the timers. */
1.1.1.2 misho 650: iperf_time_now(&now);
1.1 misho 651: tmr_run(&now);
652:
1.1.1.3 ! misho 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: */
1.1 misho 661: if ((!test->omitting) &&
1.1.1.3 ! misho 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)))) {
1.1 misho 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)
1.1.1.2 misho 680: goto cleanup_and_fail;
1.1 misho 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.
1.1.1.2 misho 688: else if (test->mode == RECEIVER && test->state == TEST_END) {
1.1 misho 689: if (iperf_recv(test, &read_set) < 0)
1.1.1.2 misho 690: goto cleanup_and_fail;
1.1 misho 691: }
692: }
693:
694: if (test->json_output) {
695: if (iperf_json_finish(test) < 0)
696: return -1;
697: } else {
1.1.1.2 misho 698: iperf_printf(test, "\n");
699: iperf_printf(test, "%s", report_done);
1.1 misho 700: }
701:
702: iflush(test);
703:
704: return 0;
1.1.1.2 misho 705:
706: cleanup_and_fail:
707: iperf_client_end(test);
1.1.1.3 ! misho 708: if (test->json_output) {
! 709: cJSON_AddStringToObject(test->json_top, "error", iperf_strerror(i_errno));
! 710: iperf_json_finish(test);
! 711: }
1.1.1.2 misho 712: iflush(test);
713: return -1;
1.1 misho 714: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>