Annotation of embedaddon/iperf/src/iperf_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 file
25: * for complete information.
26: */
1.1.1.2 misho 27: #ifndef _GNU_SOURCE
28: # define _GNU_SOURCE
29: #endif
1.1 misho 30: #define __USE_GNU
31:
32: #include "iperf_config.h"
33:
34: #include <stdio.h>
35: #include <stdlib.h>
36: #include <string.h>
1.1.1.2 misho 37: #include <time.h>
1.1 misho 38: #include <getopt.h>
39: #include <errno.h>
40: #include <signal.h>
41: #include <unistd.h>
42: #include <assert.h>
43: #include <fcntl.h>
44: #include <sys/socket.h>
45: #include <sys/types.h>
46: #include <netinet/in.h>
47: #include <arpa/inet.h>
48: #include <netdb.h>
49: #ifdef HAVE_STDINT_H
50: #include <stdint.h>
51: #endif
52: #include <sys/time.h>
53: #include <sys/resource.h>
54: #include <sys/mman.h>
55: #include <sys/stat.h>
56: #include <sched.h>
57: #include <setjmp.h>
58: #include <stdarg.h>
1.1.1.2 misho 59: #include <math.h>
1.1 misho 60:
61: #if defined(HAVE_CPUSET_SETAFFINITY)
62: #include <sys/param.h>
63: #include <sys/cpuset.h>
64: #endif /* HAVE_CPUSET_SETAFFINITY */
65:
1.1.1.2 misho 66: #if defined(__CYGWIN__) || defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
67: #define CPU_SETSIZE __CPU_SETSIZE
68: #endif /* __CYGWIN__, _WIN32, _WIN64, __WINDOWS__ */
69:
70: #if defined(HAVE_SETPROCESSAFFINITYMASK)
71: #include <Windows.h>
72: #endif /* HAVE_SETPROCESSAFFINITYMASK */
73:
1.1 misho 74: #include "net.h"
75: #include "iperf.h"
76: #include "iperf_api.h"
77: #include "iperf_udp.h"
78: #include "iperf_tcp.h"
1.1.1.2 misho 79: #if defined(HAVE_SCTP_H)
1.1 misho 80: #include "iperf_sctp.h"
1.1.1.2 misho 81: #endif /* HAVE_SCTP_H */
1.1 misho 82: #include "timer.h"
83:
84: #include "cjson.h"
85: #include "units.h"
86: #include "iperf_util.h"
87: #include "iperf_locale.h"
88: #include "version.h"
1.1.1.2 misho 89: #if defined(HAVE_SSL)
90: #include <openssl/bio.h>
1.1.1.3 ! misho 91: #include <openssl/err.h>
1.1.1.2 misho 92: #include "iperf_auth.h"
93: #endif /* HAVE_SSL */
1.1 misho 94:
95: /* Forwards. */
96: static int send_parameters(struct iperf_test *test);
97: static int get_parameters(struct iperf_test *test);
98: static int send_results(struct iperf_test *test);
99: static int get_results(struct iperf_test *test);
100: static int diskfile_send(struct iperf_stream *sp);
101: static int diskfile_recv(struct iperf_stream *sp);
102: static int JSON_write(int fd, cJSON *json);
103: static void print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *json_interval_streams);
104: static cJSON *JSON_read(int fd);
105:
106:
107: /*************************** Print usage functions ****************************/
108:
109: void
110: usage()
111: {
112: fputs(usage_shortstr, stderr);
113: }
114:
115:
116: void
1.1.1.2 misho 117: usage_long(FILE *f)
1.1 misho 118: {
1.1.1.3 ! misho 119: fprintf(f, usage_longstr, DEFAULT_NO_MSG_RCVD_TIMEOUT, UDP_RATE / (1024*1024), DEFAULT_PACING_TIMER, DURATION, DEFAULT_TCP_BLKSIZE / 1024, DEFAULT_UDP_BLKSIZE);
1.1 misho 120: }
121:
122:
1.1.1.2 misho 123: void warning(const char *str)
1.1 misho 124: {
125: fprintf(stderr, "warning: %s\n", str);
126: }
127:
128:
129: /************** Getter routines for some fields inside iperf_test *************/
130:
131: int
132: iperf_get_verbose(struct iperf_test *ipt)
133: {
134: return ipt->verbose;
135: }
136:
137: int
138: iperf_get_control_socket(struct iperf_test *ipt)
139: {
140: return ipt->ctrl_sck;
141: }
142:
143: int
1.1.1.2 misho 144: iperf_get_control_socket_mss(struct iperf_test *ipt)
145: {
146: return ipt->ctrl_sck_mss;
147: }
148:
149: int
1.1 misho 150: iperf_get_test_omit(struct iperf_test *ipt)
151: {
152: return ipt->omit;
153: }
154:
155: int
156: iperf_get_test_duration(struct iperf_test *ipt)
157: {
158: return ipt->duration;
159: }
160:
161: uint64_t
162: iperf_get_test_rate(struct iperf_test *ipt)
163: {
164: return ipt->settings->rate;
165: }
166:
1.1.1.2 misho 167: uint64_t
168: iperf_get_test_bitrate_limit(struct iperf_test *ipt)
169: {
170: return ipt->settings->bitrate_limit;
171: }
172:
173: double
174: iperf_get_test_bitrate_limit_interval(struct iperf_test *ipt)
175: {
176: return ipt->settings->bitrate_limit_interval;
177: }
178:
179: int
180: iperf_get_test_bitrate_limit_stats_per_interval(struct iperf_test *ipt)
181: {
182: return ipt->settings->bitrate_limit_stats_per_interval;
183: }
184:
185: uint64_t
186: iperf_get_test_fqrate(struct iperf_test *ipt)
187: {
188: return ipt->settings->fqrate;
189: }
190:
191: int
192: iperf_get_test_pacing_timer(struct iperf_test *ipt)
193: {
194: return ipt->settings->pacing_timer;
195: }
196:
197: uint64_t
198: iperf_get_test_bytes(struct iperf_test *ipt)
199: {
200: return (uint64_t) ipt->settings->bytes;
201: }
202:
203: uint64_t
204: iperf_get_test_blocks(struct iperf_test *ipt)
205: {
206: return (uint64_t) ipt->settings->blocks;
207: }
208:
1.1 misho 209: int
210: iperf_get_test_burst(struct iperf_test *ipt)
211: {
212: return ipt->settings->burst;
213: }
214:
215: char
216: iperf_get_test_role(struct iperf_test *ipt)
217: {
218: return ipt->role;
219: }
220:
221: int
222: iperf_get_test_reverse(struct iperf_test *ipt)
223: {
224: return ipt->reverse;
225: }
226:
227: int
1.1.1.3 ! misho 228: iperf_get_test_bidirectional(struct iperf_test *ipt)
! 229: {
! 230: return ipt->bidirectional;
! 231: }
! 232:
! 233: int
1.1 misho 234: iperf_get_test_blksize(struct iperf_test *ipt)
235: {
236: return ipt->settings->blksize;
237: }
238:
239: FILE *
240: iperf_get_test_outfile (struct iperf_test *ipt)
241: {
242: return ipt->outfile;
243: }
244:
245: int
246: iperf_get_test_socket_bufsize(struct iperf_test *ipt)
247: {
248: return ipt->settings->socket_bufsize;
249: }
250:
251: double
252: iperf_get_test_reporter_interval(struct iperf_test *ipt)
253: {
254: return ipt->reporter_interval;
255: }
256:
257: double
258: iperf_get_test_stats_interval(struct iperf_test *ipt)
259: {
260: return ipt->stats_interval;
261: }
262:
263: int
264: iperf_get_test_num_streams(struct iperf_test *ipt)
265: {
266: return ipt->num_streams;
267: }
268:
269: int
1.1.1.2 misho 270: iperf_get_test_timestamps(struct iperf_test *ipt)
271: {
272: return ipt->timestamps;
273: }
274:
275: const char *
276: iperf_get_test_timestamp_format(struct iperf_test *ipt)
277: {
278: return ipt->timestamp_format;
279: }
280:
281: int
282: iperf_get_test_repeating_payload(struct iperf_test *ipt)
283: {
284: return ipt->repeating_payload;
285: }
286:
287: int
1.1.1.3 ! misho 288: iperf_get_test_bind_port(struct iperf_test *ipt)
! 289: {
! 290: return ipt->bind_port;
! 291: }
! 292:
! 293: int
1.1 misho 294: iperf_get_test_server_port(struct iperf_test *ipt)
295: {
296: return ipt->server_port;
297: }
298:
299: char*
300: iperf_get_test_server_hostname(struct iperf_test *ipt)
301: {
302: return ipt->server_hostname;
303: }
304:
305: char*
306: iperf_get_test_template(struct iperf_test *ipt)
307: {
308: return ipt->tmp_template;
309: }
310:
311: int
312: iperf_get_test_protocol_id(struct iperf_test *ipt)
313: {
314: return ipt->protocol->id;
315: }
316:
317: int
318: iperf_get_test_json_output(struct iperf_test *ipt)
319: {
320: return ipt->json_output;
321: }
322:
323: char *
324: iperf_get_test_json_output_string(struct iperf_test *ipt)
325: {
326: return ipt->json_output_string;
327: }
328:
329: int
330: iperf_get_test_zerocopy(struct iperf_test *ipt)
331: {
332: return ipt->zerocopy;
333: }
334:
335: int
336: iperf_get_test_get_server_output(struct iperf_test *ipt)
337: {
338: return ipt->get_server_output;
339: }
340:
341: char
342: iperf_get_test_unit_format(struct iperf_test *ipt)
343: {
344: return ipt->settings->unit_format;
345: }
346:
347: char *
348: iperf_get_test_bind_address(struct iperf_test *ipt)
349: {
350: return ipt->bind_address;
351: }
352:
1.1.1.3 ! misho 353: char *
! 354: iperf_get_test_bind_dev(struct iperf_test *ipt)
! 355: {
! 356: return ipt->bind_dev;
! 357: }
! 358:
1.1 misho 359: int
360: iperf_get_test_udp_counters_64bit(struct iperf_test *ipt)
361: {
362: return ipt->udp_counters_64bit;
363: }
364:
365: int
366: iperf_get_test_one_off(struct iperf_test *ipt)
367: {
368: return ipt->one_off;
369: }
370:
371: int
1.1.1.2 misho 372: iperf_get_test_tos(struct iperf_test *ipt)
373: {
374: return ipt->settings->tos;
375: }
376:
377: char *
378: iperf_get_test_extra_data(struct iperf_test *ipt)
379: {
380: return ipt->extra_data;
381: }
382:
383: static const char iperf_version[] = IPERF_VERSION;
384: char *
385: iperf_get_iperf_version(void)
386: {
387: return (char*)iperf_version;
388: }
389:
390: int
391: iperf_get_test_no_delay(struct iperf_test *ipt)
1.1 misho 392: {
1.1.1.2 misho 393: return ipt->no_delay;
394: }
395:
396: int
397: iperf_get_test_connect_timeout(struct iperf_test *ipt)
398: {
399: return ipt->settings->connect_timeout;
1.1 misho 400: }
401:
1.1.1.3 ! misho 402: int
! 403: iperf_get_test_idle_timeout(struct iperf_test *ipt)
! 404: {
! 405: return ipt->settings->idle_timeout;
! 406: }
! 407:
! 408: int
! 409: iperf_get_dont_fragment(struct iperf_test *ipt)
! 410: {
! 411: return ipt->settings->dont_fragment;
! 412: }
! 413:
! 414: struct iperf_time*
! 415: iperf_get_test_rcv_timeout(struct iperf_test *ipt)
! 416: {
! 417: return &ipt->settings->rcv_timeout;
! 418: }
! 419:
! 420: char*
! 421: iperf_get_test_congestion_control(struct iperf_test* ipt)
! 422: {
! 423: return ipt->congestion;
! 424: }
! 425:
! 426: int
! 427: iperf_get_test_mss(struct iperf_test *ipt)
! 428: {
! 429: return ipt->settings->mss;
! 430: }
! 431:
! 432: int
! 433: iperf_get_mapped_v4(struct iperf_test* ipt)
! 434: {
! 435: return ipt->mapped_v4;
! 436: }
! 437:
1.1 misho 438: /************** Setter routines for some fields inside iperf_test *************/
439:
440: void
441: iperf_set_verbose(struct iperf_test *ipt, int verbose)
442: {
443: ipt->verbose = verbose;
444: }
445:
446: void
447: iperf_set_control_socket(struct iperf_test *ipt, int ctrl_sck)
448: {
449: ipt->ctrl_sck = ctrl_sck;
450: }
451:
452: void
453: iperf_set_test_omit(struct iperf_test *ipt, int omit)
454: {
455: ipt->omit = omit;
456: }
457:
458: void
459: iperf_set_test_duration(struct iperf_test *ipt, int duration)
460: {
461: ipt->duration = duration;
462: }
463:
464: void
465: iperf_set_test_reporter_interval(struct iperf_test *ipt, double reporter_interval)
466: {
467: ipt->reporter_interval = reporter_interval;
468: }
469:
470: void
471: iperf_set_test_stats_interval(struct iperf_test *ipt, double stats_interval)
472: {
473: ipt->stats_interval = stats_interval;
474: }
475:
476: void
477: iperf_set_test_state(struct iperf_test *ipt, signed char state)
478: {
479: ipt->state = state;
480: }
481:
482: void
483: iperf_set_test_blksize(struct iperf_test *ipt, int blksize)
484: {
485: ipt->settings->blksize = blksize;
486: }
487:
488: void
1.1.1.2 misho 489: iperf_set_test_logfile(struct iperf_test *ipt, const char *logfile)
490: {
491: ipt->logfile = strdup(logfile);
492: }
493:
494: void
1.1 misho 495: iperf_set_test_rate(struct iperf_test *ipt, uint64_t rate)
496: {
497: ipt->settings->rate = rate;
498: }
499:
500: void
1.1.1.2 misho 501: iperf_set_test_bitrate_limit_maximum(struct iperf_test *ipt, uint64_t total_rate)
502: {
503: ipt->settings->bitrate_limit = total_rate;
504: }
505:
506: void
507: iperf_set_test_bitrate_limit_interval(struct iperf_test *ipt, uint64_t bitrate_limit_interval)
508: {
509: ipt->settings->bitrate_limit_interval = bitrate_limit_interval;
510: }
511:
512: void
513: iperf_set_test_bitrate_limit_stats_per_interval(struct iperf_test *ipt, uint64_t bitrate_limit_stats_per_interval)
514: {
515: ipt->settings->bitrate_limit_stats_per_interval = bitrate_limit_stats_per_interval;
516: }
517:
518: void
519: iperf_set_test_fqrate(struct iperf_test *ipt, uint64_t fqrate)
520: {
521: ipt->settings->fqrate = fqrate;
522: }
523:
524: void
525: iperf_set_test_pacing_timer(struct iperf_test *ipt, int pacing_timer)
526: {
527: ipt->settings->pacing_timer = pacing_timer;
528: }
529:
530: void
531: iperf_set_test_bytes(struct iperf_test *ipt, uint64_t bytes)
532: {
533: ipt->settings->bytes = (iperf_size_t) bytes;
534: }
535:
536: void
537: iperf_set_test_blocks(struct iperf_test *ipt, uint64_t blocks)
538: {
539: ipt->settings->blocks = (iperf_size_t) blocks;
540: }
541:
542: void
1.1 misho 543: iperf_set_test_burst(struct iperf_test *ipt, int burst)
544: {
545: ipt->settings->burst = burst;
546: }
547:
548: void
1.1.1.3 ! misho 549: iperf_set_test_bind_port(struct iperf_test *ipt, int bind_port)
! 550: {
! 551: ipt->bind_port = bind_port;
! 552: }
! 553:
! 554: void
1.1.1.2 misho 555: iperf_set_test_server_port(struct iperf_test *ipt, int srv_port)
1.1 misho 556: {
1.1.1.2 misho 557: ipt->server_port = srv_port;
1.1 misho 558: }
559:
560: void
561: iperf_set_test_socket_bufsize(struct iperf_test *ipt, int socket_bufsize)
562: {
563: ipt->settings->socket_bufsize = socket_bufsize;
564: }
565:
566: void
567: iperf_set_test_num_streams(struct iperf_test *ipt, int num_streams)
568: {
569: ipt->num_streams = num_streams;
570: }
571:
1.1.1.2 misho 572: void
573: iperf_set_test_repeating_payload(struct iperf_test *ipt, int repeating_payload)
574: {
575: ipt->repeating_payload = repeating_payload;
576: }
577:
578: void
579: iperf_set_test_timestamps(struct iperf_test *ipt, int timestamps)
580: {
581: ipt->timestamps = timestamps;
582: }
583:
584: void
585: iperf_set_test_timestamp_format(struct iperf_test *ipt, const char *tf)
586: {
587: ipt->timestamp_format = strdup(tf);
588: }
589:
1.1.1.3 ! misho 590: void
! 591: iperf_set_mapped_v4(struct iperf_test *ipt, const int val)
! 592: {
! 593: ipt->mapped_v4 = val;
! 594: }
! 595:
! 596: void
! 597: iperf_set_on_new_stream_callback(struct iperf_test* ipt, void (*callback)())
! 598: {
! 599: ipt->on_new_stream = callback;
! 600: }
! 601:
! 602: void
! 603: iperf_set_on_test_start_callback(struct iperf_test* ipt, void (*callback)())
! 604: {
! 605: ipt->on_test_start = callback;
! 606: }
! 607:
! 608: void
! 609: iperf_set_on_test_connect_callback(struct iperf_test* ipt, void (*callback)())
! 610: {
! 611: ipt->on_connect = callback;
! 612: }
! 613:
! 614: void
! 615: iperf_set_on_test_finish_callback(struct iperf_test* ipt, void (*callback)())
! 616: {
! 617: ipt->on_test_finish = callback;
! 618: }
! 619:
1.1 misho 620: static void
621: check_sender_has_retransmits(struct iperf_test *ipt)
622: {
1.1.1.2 misho 623: if (ipt->mode != RECEIVER && ipt->protocol->id == Ptcp && has_tcpinfo_retransmits())
1.1 misho 624: ipt->sender_has_retransmits = 1;
625: else
626: ipt->sender_has_retransmits = 0;
627: }
628:
629: void
630: iperf_set_test_role(struct iperf_test *ipt, char role)
631: {
632: ipt->role = role;
1.1.1.2 misho 633: if (!ipt->reverse) {
634: if (ipt->bidirectional)
635: ipt->mode = BIDIRECTIONAL;
636: else if (role == 'c')
637: ipt->mode = SENDER;
638: else if (role == 's')
639: ipt->mode = RECEIVER;
640: } else {
641: if (role == 'c')
642: ipt->mode = RECEIVER;
643: else if (role == 's')
644: ipt->mode = SENDER;
645: }
1.1 misho 646: check_sender_has_retransmits(ipt);
647: }
648:
649: void
1.1.1.2 misho 650: iperf_set_test_server_hostname(struct iperf_test *ipt, const char *server_hostname)
1.1 misho 651: {
652: ipt->server_hostname = strdup(server_hostname);
653: }
654:
655: void
1.1.1.2 misho 656: iperf_set_test_template(struct iperf_test *ipt, const char *tmp_template)
1.1 misho 657: {
658: ipt->tmp_template = strdup(tmp_template);
659: }
660:
661: void
662: iperf_set_test_reverse(struct iperf_test *ipt, int reverse)
663: {
664: ipt->reverse = reverse;
1.1.1.2 misho 665: if (!ipt->reverse) {
666: if (ipt->role == 'c')
667: ipt->mode = SENDER;
668: else if (ipt->role == 's')
669: ipt->mode = RECEIVER;
670: } else {
671: if (ipt->role == 'c')
672: ipt->mode = RECEIVER;
673: else if (ipt->role == 's')
674: ipt->mode = SENDER;
675: }
1.1 misho 676: check_sender_has_retransmits(ipt);
677: }
678:
679: void
680: iperf_set_test_json_output(struct iperf_test *ipt, int json_output)
681: {
682: ipt->json_output = json_output;
683: }
684:
685: int
686: iperf_has_zerocopy( void )
687: {
688: return has_sendfile();
689: }
690:
691: void
692: iperf_set_test_zerocopy(struct iperf_test *ipt, int zerocopy)
693: {
694: ipt->zerocopy = (zerocopy && has_sendfile());
695: }
696:
697: void
698: iperf_set_test_get_server_output(struct iperf_test *ipt, int get_server_output)
699: {
700: ipt->get_server_output = get_server_output;
701: }
702:
703: void
704: iperf_set_test_unit_format(struct iperf_test *ipt, char unit_format)
705: {
706: ipt->settings->unit_format = unit_format;
707: }
708:
1.1.1.2 misho 709: #if defined(HAVE_SSL)
710: void
711: iperf_set_test_client_username(struct iperf_test *ipt, const char *client_username)
712: {
713: ipt->settings->client_username = strdup(client_username);
714: }
715:
1.1 misho 716: void
1.1.1.2 misho 717: iperf_set_test_client_password(struct iperf_test *ipt, const char *client_password)
1.1 misho 718: {
1.1.1.2 misho 719: ipt->settings->client_password = strdup(client_password);
720: }
721:
722: void
723: iperf_set_test_client_rsa_pubkey(struct iperf_test *ipt, const char *client_rsa_pubkey_base64)
724: {
725: ipt->settings->client_rsa_pubkey = load_pubkey_from_base64(client_rsa_pubkey_base64);
726: }
727:
728: void
729: iperf_set_test_server_authorized_users(struct iperf_test *ipt, const char *server_authorized_users)
730: {
731: ipt->server_authorized_users = strdup(server_authorized_users);
732: }
733:
734: void
1.1.1.3 ! misho 735: iperf_set_test_server_skew_threshold(struct iperf_test *ipt, int server_skew_threshold)
! 736: {
! 737: ipt->server_skew_threshold = server_skew_threshold;
! 738: }
! 739:
! 740: void
1.1.1.2 misho 741: iperf_set_test_server_rsa_privkey(struct iperf_test *ipt, const char *server_rsa_privkey_base64)
742: {
743: ipt->server_rsa_private_key = load_privkey_from_base64(server_rsa_privkey_base64);
744: }
745: #endif // HAVE_SSL
746:
747: void
748: iperf_set_test_bind_address(struct iperf_test *ipt, const char *bnd_address)
749: {
750: ipt->bind_address = strdup(bnd_address);
1.1 misho 751: }
752:
753: void
1.1.1.3 ! misho 754: iperf_set_test_bind_dev(struct iperf_test *ipt, const char *bnd_dev)
! 755: {
! 756: ipt->bind_dev = strdup(bnd_dev);
! 757: }
! 758:
! 759: void
1.1 misho 760: iperf_set_test_udp_counters_64bit(struct iperf_test *ipt, int udp_counters_64bit)
761: {
762: ipt->udp_counters_64bit = udp_counters_64bit;
763: }
764:
765: void
766: iperf_set_test_one_off(struct iperf_test *ipt, int one_off)
767: {
768: ipt->one_off = one_off;
769: }
770:
771: void
1.1.1.2 misho 772: iperf_set_test_tos(struct iperf_test *ipt, int tos)
1.1 misho 773: {
1.1.1.2 misho 774: ipt->settings->tos = tos;
1.1 misho 775: }
776:
1.1.1.2 misho 777: void
778: iperf_set_test_extra_data(struct iperf_test *ipt, const char *dat)
779: {
780: ipt->extra_data = strdup(dat);
781: }
782:
783: void
784: iperf_set_test_bidirectional(struct iperf_test* ipt, int bidirectional)
785: {
786: ipt->bidirectional = bidirectional;
787: if (bidirectional)
788: ipt->mode = BIDIRECTIONAL;
789: else
790: iperf_set_test_reverse(ipt, ipt->reverse);
791: }
792:
793: void
794: iperf_set_test_no_delay(struct iperf_test* ipt, int no_delay)
795: {
796: ipt->no_delay = no_delay;
797: }
798:
799: void
800: iperf_set_test_connect_timeout(struct iperf_test* ipt, int ct)
801: {
802: ipt->settings->connect_timeout = ct;
803: }
804:
1.1.1.3 ! misho 805: void
! 806: iperf_set_test_idle_timeout(struct iperf_test* ipt, int to)
! 807: {
! 808: ipt->settings->idle_timeout = to;
! 809: }
! 810:
! 811: void
! 812: iperf_set_dont_fragment(struct iperf_test* ipt, int dnf)
! 813: {
! 814: ipt->settings->dont_fragment = dnf;
! 815: }
! 816:
! 817: void
! 818: iperf_set_test_rcv_timeout(struct iperf_test* ipt, struct iperf_time* to)
! 819: {
! 820: ipt->settings->rcv_timeout.secs = to->secs;
! 821: ipt->settings->rcv_timeout.usecs = to->usecs;
! 822: }
! 823:
! 824: void
! 825: iperf_set_test_congestion_control(struct iperf_test* ipt, char* cc)
! 826: {
! 827: ipt->congestion = strdup(cc);
! 828: }
! 829:
! 830: void
! 831: iperf_set_test_mss(struct iperf_test *ipt, int mss)
! 832: {
! 833: ipt->settings->mss = mss;
! 834: }
1.1.1.2 misho 835:
1.1 misho 836: /********************** Get/set test protocol structure ***********************/
837:
838: struct protocol *
839: get_protocol(struct iperf_test *test, int prot_id)
840: {
841: struct protocol *prot;
842:
843: SLIST_FOREACH(prot, &test->protocols, protocols) {
844: if (prot->id == prot_id)
845: break;
846: }
847:
848: if (prot == NULL)
849: i_errno = IEPROTOCOL;
850:
851: return prot;
852: }
853:
854: int
855: set_protocol(struct iperf_test *test, int prot_id)
856: {
857: struct protocol *prot = NULL;
858:
859: SLIST_FOREACH(prot, &test->protocols, protocols) {
860: if (prot->id == prot_id) {
861: test->protocol = prot;
862: check_sender_has_retransmits(test);
863: return 0;
864: }
865: }
866:
867: i_errno = IEPROTOCOL;
868: return -1;
869: }
870:
871:
872: /************************** Iperf callback functions **************************/
873:
874: void
875: iperf_on_new_stream(struct iperf_stream *sp)
876: {
877: connect_msg(sp);
878: }
879:
880: void
881: iperf_on_test_start(struct iperf_test *test)
882: {
883: if (test->json_output) {
1.1.1.3 ! misho 884: cJSON_AddItemToObject(test->json_start, "test_start", iperf_json_printf("protocol: %s num_streams: %d blksize: %d omit: %d duration: %d bytes: %d blocks: %d reverse: %d tos: %d target_bitrate: %d bidir: %d fqrate: %d", test->protocol->name, (int64_t) test->num_streams, (int64_t) test->settings->blksize, (int64_t) test->omit, (int64_t) test->duration, (int64_t) test->settings->bytes, (int64_t) test->settings->blocks, test->reverse?(int64_t)1:(int64_t)0, (int64_t) test->settings->tos, (int64_t) test->settings->rate, (int64_t) test->bidirectional, (uint64_t) test->settings->fqrate));
1.1 misho 885: } else {
886: if (test->verbose) {
887: if (test->settings->bytes)
1.1.1.2 misho 888: iperf_printf(test, test_start_bytes, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->settings->bytes, test->settings->tos);
1.1 misho 889: else if (test->settings->blocks)
1.1.1.2 misho 890: iperf_printf(test, test_start_blocks, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->settings->blocks, test->settings->tos);
1.1 misho 891: else
1.1.1.2 misho 892: iperf_printf(test, test_start_time, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->duration, test->settings->tos);
1.1 misho 893: }
894: }
895: }
896:
897: /* This converts an IPv6 string address from IPv4-mapped format into regular
898: ** old IPv4 format, which is easier on the eyes of network veterans.
899: **
900: ** If the v6 address is not v4-mapped it is left alone.
1.1.1.3 ! misho 901: **
! 902: ** Returns 1 if the v6 address is v4-mapped, 0 otherwise.
1.1 misho 903: */
1.1.1.3 ! misho 904: static int
1.1 misho 905: mapped_v4_to_regular_v4(char *str)
906: {
907: char *prefix = "::ffff:";
908: int prefix_len;
909:
910: prefix_len = strlen(prefix);
911: if (strncmp(str, prefix, prefix_len) == 0) {
912: int str_len = strlen(str);
913: memmove(str, str + prefix_len, str_len - prefix_len + 1);
1.1.1.3 ! misho 914: return 1;
1.1 misho 915: }
1.1.1.3 ! misho 916: return 0;
1.1 misho 917: }
918:
919: void
920: iperf_on_connect(struct iperf_test *test)
921: {
922: time_t now_secs;
1.1.1.2 misho 923: const char* rfc1123_fmt = "%a, %d %b %Y %H:%M:%S %Z";
1.1 misho 924: char now_str[100];
925: char ipr[INET6_ADDRSTRLEN];
926: int port;
927: struct sockaddr_storage sa;
928: struct sockaddr_in *sa_inP;
929: struct sockaddr_in6 *sa_in6P;
930: socklen_t len;
931:
932: now_secs = time((time_t*) 0);
933: (void) strftime(now_str, sizeof(now_str), rfc1123_fmt, gmtime(&now_secs));
934: if (test->json_output)
935: cJSON_AddItemToObject(test->json_start, "timestamp", iperf_json_printf("time: %s timesecs: %d", now_str, (int64_t) now_secs));
936: else if (test->verbose)
1.1.1.2 misho 937: iperf_printf(test, report_time, now_str);
1.1 misho 938:
939: if (test->role == 'c') {
940: if (test->json_output)
941: cJSON_AddItemToObject(test->json_start, "connecting_to", iperf_json_printf("host: %s port: %d", test->server_hostname, (int64_t) test->server_port));
942: else {
1.1.1.2 misho 943: iperf_printf(test, report_connecting, test->server_hostname, test->server_port);
1.1 misho 944: if (test->reverse)
1.1.1.2 misho 945: iperf_printf(test, report_reverse, test->server_hostname);
1.1 misho 946: }
947: } else {
948: len = sizeof(sa);
949: getpeername(test->ctrl_sck, (struct sockaddr *) &sa, &len);
950: if (getsockdomain(test->ctrl_sck) == AF_INET) {
951: sa_inP = (struct sockaddr_in *) &sa;
952: inet_ntop(AF_INET, &sa_inP->sin_addr, ipr, sizeof(ipr));
953: port = ntohs(sa_inP->sin_port);
954: } else {
955: sa_in6P = (struct sockaddr_in6 *) &sa;
956: inet_ntop(AF_INET6, &sa_in6P->sin6_addr, ipr, sizeof(ipr));
957: port = ntohs(sa_in6P->sin6_port);
958: }
1.1.1.3 ! misho 959: if (mapped_v4_to_regular_v4(ipr)) {
! 960: iperf_set_mapped_v4(test, 1);
! 961: }
1.1 misho 962: if (test->json_output)
963: cJSON_AddItemToObject(test->json_start, "accepted_connection", iperf_json_printf("host: %s port: %d", ipr, (int64_t) port));
964: else
1.1.1.2 misho 965: iperf_printf(test, report_accepted, ipr, port);
1.1 misho 966: }
967: if (test->json_output) {
968: cJSON_AddStringToObject(test->json_start, "cookie", test->cookie);
969: if (test->protocol->id == SOCK_STREAM) {
970: if (test->settings->mss)
971: cJSON_AddNumberToObject(test->json_start, "tcp_mss", test->settings->mss);
972: else {
1.1.1.2 misho 973: cJSON_AddNumberToObject(test->json_start, "tcp_mss_default", test->ctrl_sck_mss);
1.1 misho 974: }
1.1.1.2 misho 975: }
1.1.1.3 ! misho 976: // Duplicate to make sure it appears on all output
! 977: cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);
! 978: cJSON_AddNumberToObject(test->json_start, "fq_rate", test->settings->fqrate);
1.1 misho 979: } else if (test->verbose) {
1.1.1.2 misho 980: iperf_printf(test, report_cookie, test->cookie);
1.1 misho 981: if (test->protocol->id == SOCK_STREAM) {
982: if (test->settings->mss)
1.1.1.2 misho 983: iperf_printf(test, " TCP MSS: %d\n", test->settings->mss);
1.1 misho 984: else {
1.1.1.2 misho 985: iperf_printf(test, " TCP MSS: %d (default)\n", test->ctrl_sck_mss);
1.1 misho 986: }
987: }
1.1.1.2 misho 988: if (test->settings->rate)
989: iperf_printf(test, " Target Bitrate: %"PRIu64"\n", test->settings->rate);
1.1 misho 990: }
991: }
992:
993: void
994: iperf_on_test_finish(struct iperf_test *test)
995: {
996: }
997:
998:
999: /******************************************************************************/
1000:
1.1.1.3 ! misho 1001: /*
! 1002: * iperf_parse_hostname tries to split apart a string into hostname %
! 1003: * interface parts, which are returned in **p and **p1, if they
! 1004: * exist. If the %interface part is detected, and it's not an IPv6
! 1005: * link local address, then returns 1, else returns 0.
! 1006: *
! 1007: * Modifies the string pointed to by spec in-place due to the use of
! 1008: * strtok(3). The caller should strdup(3) or otherwise copy the string
! 1009: * if an unmodified copy is needed.
! 1010: */
! 1011: int
! 1012: iperf_parse_hostname(struct iperf_test *test, char *spec, char **p, char **p1) {
! 1013: struct in6_addr ipv6_addr;
! 1014:
! 1015: // Format is <addr>[%<device>]
! 1016: if ((*p = strtok(spec, "%")) != NULL &&
! 1017: (*p1 = strtok(NULL, "%")) != NULL) {
! 1018:
! 1019: /*
! 1020: * If an IPv6 literal for a link-local address, then
! 1021: * tell the caller to leave the "%" in the hostname.
! 1022: */
! 1023: if (inet_pton(AF_INET6, *p, &ipv6_addr) == 1 &&
! 1024: IN6_IS_ADDR_LINKLOCAL(&ipv6_addr)) {
! 1025: if (test->debug) {
! 1026: iperf_printf(test, "IPv6 link-local address literal detected\n");
! 1027: }
! 1028: return 0;
! 1029: }
! 1030: /*
! 1031: * Other kind of address or FQDN. The interface name after
! 1032: * "%" is a shorthand for --bind-dev.
! 1033: */
! 1034: else {
! 1035: if (test->debug) {
! 1036: iperf_printf(test, "p %s p1 %s\n", *p, *p1);
! 1037: }
! 1038: return 1;
! 1039: }
! 1040: }
! 1041: else {
! 1042: if (test->debug) {
! 1043: iperf_printf(test, "noparse\n");
! 1044: }
! 1045: return 0;
! 1046: }
! 1047: }
! 1048:
1.1 misho 1049: int
1050: iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
1051: {
1052: static struct option longopts[] =
1053: {
1054: {"port", required_argument, NULL, 'p'},
1055: {"format", required_argument, NULL, 'f'},
1056: {"interval", required_argument, NULL, 'i'},
1057: {"daemon", no_argument, NULL, 'D'},
1058: {"one-off", no_argument, NULL, '1'},
1059: {"verbose", no_argument, NULL, 'V'},
1060: {"json", no_argument, NULL, 'J'},
1061: {"version", no_argument, NULL, 'v'},
1062: {"server", no_argument, NULL, 's'},
1063: {"client", required_argument, NULL, 'c'},
1064: {"udp", no_argument, NULL, 'u'},
1.1.1.2 misho 1065: {"bitrate", required_argument, NULL, 'b'},
1.1 misho 1066: {"bandwidth", required_argument, NULL, 'b'},
1.1.1.2 misho 1067: {"server-bitrate-limit", required_argument, NULL, OPT_SERVER_BITRATE_LIMIT},
1.1 misho 1068: {"time", required_argument, NULL, 't'},
1069: {"bytes", required_argument, NULL, 'n'},
1070: {"blockcount", required_argument, NULL, 'k'},
1071: {"length", required_argument, NULL, 'l'},
1072: {"parallel", required_argument, NULL, 'P'},
1073: {"reverse", no_argument, NULL, 'R'},
1.1.1.2 misho 1074: {"bidir", no_argument, NULL, OPT_BIDIRECTIONAL},
1.1 misho 1075: {"window", required_argument, NULL, 'w'},
1076: {"bind", required_argument, NULL, 'B'},
1.1.1.3 ! misho 1077: #if defined(HAVE_SO_BINDTODEVICE)
! 1078: {"bind-dev", required_argument, NULL, OPT_BIND_DEV},
! 1079: #endif /* HAVE_SO_BINDTODEVICE */
1.1 misho 1080: {"cport", required_argument, NULL, OPT_CLIENT_PORT},
1081: {"set-mss", required_argument, NULL, 'M'},
1082: {"no-delay", no_argument, NULL, 'N'},
1083: {"version4", no_argument, NULL, '4'},
1084: {"version6", no_argument, NULL, '6'},
1085: {"tos", required_argument, NULL, 'S'},
1.1.1.2 misho 1086: {"dscp", required_argument, NULL, OPT_DSCP},
1087: {"extra-data", required_argument, NULL, OPT_EXTRA_DATA},
1.1 misho 1088: #if defined(HAVE_FLOWLABEL)
1089: {"flowlabel", required_argument, NULL, 'L'},
1090: #endif /* HAVE_FLOWLABEL */
1091: {"zerocopy", no_argument, NULL, 'Z'},
1092: {"omit", required_argument, NULL, 'O'},
1093: {"file", required_argument, NULL, 'F'},
1.1.1.2 misho 1094: {"repeating-payload", no_argument, NULL, OPT_REPEATING_PAYLOAD},
1095: {"timestamps", optional_argument, NULL, OPT_TIMESTAMPS},
1.1 misho 1096: #if defined(HAVE_CPU_AFFINITY)
1097: {"affinity", required_argument, NULL, 'A'},
1098: #endif /* HAVE_CPU_AFFINITY */
1099: {"title", required_argument, NULL, 'T'},
1100: #if defined(HAVE_TCP_CONGESTION)
1101: {"congestion", required_argument, NULL, 'C'},
1102: {"linux-congestion", required_argument, NULL, 'C'},
1103: #endif /* HAVE_TCP_CONGESTION */
1.1.1.2 misho 1104: #if defined(HAVE_SCTP_H)
1.1 misho 1105: {"sctp", no_argument, NULL, OPT_SCTP},
1106: {"nstreams", required_argument, NULL, OPT_NUMSTREAMS},
1107: {"xbind", required_argument, NULL, 'X'},
1108: #endif
1109: {"pidfile", required_argument, NULL, 'I'},
1110: {"logfile", required_argument, NULL, OPT_LOGFILE},
1.1.1.2 misho 1111: {"forceflush", no_argument, NULL, OPT_FORCEFLUSH},
1.1 misho 1112: {"get-server-output", no_argument, NULL, OPT_GET_SERVER_OUTPUT},
1113: {"udp-counters-64bit", no_argument, NULL, OPT_UDP_COUNTERS_64BIT},
1.1.1.2 misho 1114: {"no-fq-socket-pacing", no_argument, NULL, OPT_NO_FQ_SOCKET_PACING},
1.1.1.3 ! misho 1115: #if defined(HAVE_DONT_FRAGMENT)
! 1116: {"dont-fragment", no_argument, NULL, OPT_DONT_FRAGMENT},
! 1117: #endif /* HAVE_DONT_FRAGMENT */
1.1.1.2 misho 1118: #if defined(HAVE_SSL)
1119: {"username", required_argument, NULL, OPT_CLIENT_USERNAME},
1120: {"rsa-public-key-path", required_argument, NULL, OPT_CLIENT_RSA_PUBLIC_KEY},
1121: {"rsa-private-key-path", required_argument, NULL, OPT_SERVER_RSA_PRIVATE_KEY},
1122: {"authorized-users-path", required_argument, NULL, OPT_SERVER_AUTHORIZED_USERS},
1.1.1.3 ! misho 1123: {"time-skew-threshold", required_argument, NULL, OPT_SERVER_SKEW_THRESHOLD},
1.1.1.2 misho 1124: #endif /* HAVE_SSL */
1125: {"fq-rate", required_argument, NULL, OPT_FQ_RATE},
1126: {"pacing-timer", required_argument, NULL, OPT_PACING_TIMER},
1127: {"connect-timeout", required_argument, NULL, OPT_CONNECT_TIMEOUT},
1.1.1.3 ! misho 1128: {"idle-timeout", required_argument, NULL, OPT_IDLE_TIMEOUT},
! 1129: {"rcv-timeout", required_argument, NULL, OPT_RCV_TIMEOUT},
! 1130: {"snd-timeout", required_argument, NULL, OPT_SND_TIMEOUT},
! 1131: {"debug", optional_argument, NULL, 'd'},
1.1 misho 1132: {"help", no_argument, NULL, 'h'},
1133: {NULL, 0, NULL, 0}
1134: };
1135: int flag;
1.1.1.2 misho 1136: int portno;
1.1 misho 1137: int blksize;
1.1.1.3 ! misho 1138: int server_flag, client_flag, rate_flag, duration_flag, rcv_timeout_flag, snd_timeout_flag;
1.1 misho 1139: char *endptr;
1140: #if defined(HAVE_CPU_AFFINITY)
1141: char* comma;
1142: #endif /* HAVE_CPU_AFFINITY */
1143: char* slash;
1.1.1.3 ! misho 1144: char *p, *p1;
1.1 misho 1145: struct xbind_entry *xbe;
1.1.1.2 misho 1146: double farg;
1.1.1.3 ! misho 1147: int rcv_timeout_in = 0;
1.1 misho 1148:
1149: blksize = 0;
1.1.1.3 ! misho 1150: server_flag = client_flag = rate_flag = duration_flag = rcv_timeout_flag = snd_timeout_flag =0;
1.1.1.2 misho 1151: #if defined(HAVE_SSL)
1152: char *client_username = NULL, *client_rsa_public_key = NULL, *server_rsa_private_key = NULL;
1153: #endif /* HAVE_SSL */
1154:
1.1 misho 1155: while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) {
1156: switch (flag) {
1157: case 'p':
1.1.1.2 misho 1158: portno = atoi(optarg);
1159: if (portno < 1 || portno > 65535) {
1160: i_errno = IEBADPORT;
1161: return -1;
1162: }
1163: test->server_port = portno;
1.1 misho 1164: break;
1165: case 'f':
1.1.1.2 misho 1166: if (!optarg) {
1167: i_errno = IEBADFORMAT;
1168: return -1;
1169: }
1170: test->settings->unit_format = *optarg;
1171: if (test->settings->unit_format == 'k' ||
1172: test->settings->unit_format == 'K' ||
1173: test->settings->unit_format == 'm' ||
1174: test->settings->unit_format == 'M' ||
1175: test->settings->unit_format == 'g' ||
1176: test->settings->unit_format == 'G' ||
1177: test->settings->unit_format == 't' ||
1178: test->settings->unit_format == 'T') {
1179: break;
1180: }
1181: else {
1182: i_errno = IEBADFORMAT;
1183: return -1;
1184: }
1.1 misho 1185: break;
1186: case 'i':
1187: /* XXX: could potentially want separate stat collection and reporting intervals,
1188: but just set them to be the same for now */
1189: test->stats_interval = test->reporter_interval = atof(optarg);
1190: if ((test->stats_interval < MIN_INTERVAL || test->stats_interval > MAX_INTERVAL) && test->stats_interval != 0) {
1191: i_errno = IEINTERVAL;
1192: return -1;
1193: }
1194: break;
1195: case 'D':
1196: test->daemon = 1;
1197: server_flag = 1;
1198: break;
1199: case '1':
1200: test->one_off = 1;
1201: server_flag = 1;
1202: break;
1203: case 'V':
1204: test->verbose = 1;
1205: break;
1206: case 'J':
1207: test->json_output = 1;
1208: break;
1209: case 'v':
1.1.1.2 misho 1210: printf("%s (cJSON %s)\n%s\n%s\n", version, cJSON_Version(), get_system_info(),
1.1 misho 1211: get_optional_features());
1212: exit(0);
1213: case 's':
1214: if (test->role == 'c') {
1215: i_errno = IESERVCLIENT;
1216: return -1;
1217: }
1218: iperf_set_test_role(test, 's');
1219: break;
1220: case 'c':
1221: if (test->role == 's') {
1222: i_errno = IESERVCLIENT;
1223: return -1;
1224: }
1225: iperf_set_test_role(test, 'c');
1226: iperf_set_test_server_hostname(test, optarg);
1.1.1.3 ! misho 1227:
! 1228: if (iperf_parse_hostname(test, optarg, &p, &p1)) {
! 1229: #if defined(HAVE_SO_BINDTODEVICE)
! 1230: /* Get rid of the hostname we saved earlier. */
! 1231: free(iperf_get_test_server_hostname(test));
! 1232: iperf_set_test_server_hostname(test, p);
! 1233: iperf_set_test_bind_dev(test, p1);
! 1234: #else /* HAVE_SO_BINDTODEVICE */
! 1235: i_errno = IEBINDDEVNOSUPPORT;
! 1236: return -1;
! 1237: #endif /* HAVE_SO_BINDTODEVICE */
! 1238: }
1.1 misho 1239: break;
1240: case 'u':
1241: set_protocol(test, Pudp);
1242: client_flag = 1;
1243: break;
1244: case OPT_SCTP:
1.1.1.2 misho 1245: #if defined(HAVE_SCTP_H)
1.1 misho 1246: set_protocol(test, Psctp);
1247: client_flag = 1;
1.1.1.2 misho 1248: break;
1249: #else /* HAVE_SCTP_H */
1.1 misho 1250: i_errno = IEUNIMP;
1251: return -1;
1.1.1.2 misho 1252: #endif /* HAVE_SCTP_H */
1.1 misho 1253:
1254: case OPT_NUMSTREAMS:
1255: #if defined(linux) || defined(__FreeBSD__)
1256: test->settings->num_ostreams = unit_atoi(optarg);
1257: client_flag = 1;
1258: #else /* linux */
1259: i_errno = IEUNIMP;
1260: return -1;
1261: #endif /* linux */
1262: case 'b':
1263: slash = strchr(optarg, '/');
1264: if (slash) {
1265: *slash = '\0';
1266: ++slash;
1267: test->settings->burst = atoi(slash);
1268: if (test->settings->burst <= 0 ||
1269: test->settings->burst > MAX_BURST) {
1270: i_errno = IEBURST;
1271: return -1;
1272: }
1273: }
1274: test->settings->rate = unit_atof_rate(optarg);
1275: rate_flag = 1;
1276: client_flag = 1;
1277: break;
1.1.1.2 misho 1278: case OPT_SERVER_BITRATE_LIMIT:
1279: slash = strchr(optarg, '/');
1280: if (slash) {
1281: *slash = '\0';
1282: ++slash;
1283: test->settings->bitrate_limit_interval = atof(slash);
1284: if (test->settings->bitrate_limit_interval != 0 && /* Using same Max/Min limits as for Stats Interval */
1285: (test->settings->bitrate_limit_interval < MIN_INTERVAL || test->settings->bitrate_limit_interval > MAX_INTERVAL) ) {
1286: i_errno = IETOTALINTERVAL;
1287: return -1;
1288: }
1289: }
1290: test->settings->bitrate_limit = unit_atof_rate(optarg);
1291: server_flag = 1;
1292: break;
1.1 misho 1293: case 't':
1294: test->duration = atoi(optarg);
1295: if (test->duration > MAX_TIME) {
1296: i_errno = IEDURATION;
1297: return -1;
1298: }
1299: duration_flag = 1;
1300: client_flag = 1;
1301: break;
1302: case 'n':
1303: test->settings->bytes = unit_atoi(optarg);
1304: client_flag = 1;
1305: break;
1306: case 'k':
1307: test->settings->blocks = unit_atoi(optarg);
1308: client_flag = 1;
1309: break;
1310: case 'l':
1311: blksize = unit_atoi(optarg);
1312: client_flag = 1;
1313: break;
1314: case 'P':
1315: test->num_streams = atoi(optarg);
1316: if (test->num_streams > MAX_STREAMS) {
1317: i_errno = IENUMSTREAMS;
1318: return -1;
1319: }
1320: client_flag = 1;
1321: break;
1322: case 'R':
1.1.1.2 misho 1323: if (test->bidirectional) {
1324: i_errno = IEREVERSEBIDIR;
1325: return -1;
1326: }
1.1 misho 1327: iperf_set_test_reverse(test, 1);
1328: client_flag = 1;
1329: break;
1.1.1.2 misho 1330: case OPT_BIDIRECTIONAL:
1331: if (test->reverse) {
1332: i_errno = IEREVERSEBIDIR;
1333: return -1;
1334: }
1335: iperf_set_test_bidirectional(test, 1);
1336: client_flag = 1;
1337: break;
1.1 misho 1338: case 'w':
1339: // XXX: This is a socket buffer, not specific to TCP
1.1.1.3 ! misho 1340: // Do sanity checks as double-precision floating point
1.1.1.2 misho 1341: // to avoid possible integer overflows.
1342: farg = unit_atof(optarg);
1343: if (farg > (double) MAX_TCP_BUFFER) {
1.1 misho 1344: i_errno = IEBUFSIZE;
1345: return -1;
1346: }
1.1.1.2 misho 1347: test->settings->socket_bufsize = (int) farg;
1.1 misho 1348: client_flag = 1;
1349: break;
1.1.1.3 ! misho 1350:
1.1 misho 1351: case 'B':
1.1.1.3 ! misho 1352: iperf_set_test_bind_address(test, optarg);
! 1353:
! 1354: if (iperf_parse_hostname(test, optarg, &p, &p1)) {
! 1355: #if defined(HAVE_SO_BINDTODEVICE)
! 1356: /* Get rid of the hostname we saved earlier. */
! 1357: free(iperf_get_test_bind_address(test));
! 1358: iperf_set_test_bind_address(test, p);
! 1359: iperf_set_test_bind_dev(test, p1);
! 1360: #else /* HAVE_SO_BINDTODEVICE */
! 1361: i_errno = IEBINDDEVNOSUPPORT;
! 1362: return -1;
! 1363: #endif /* HAVE_SO_BINDTODEVICE */
! 1364: }
! 1365: break;
! 1366: #if defined (HAVE_SO_BINDTODEVICE)
! 1367: case OPT_BIND_DEV:
! 1368: iperf_set_test_bind_dev(test, optarg);
1.1 misho 1369: break;
1.1.1.3 ! misho 1370: #endif /* HAVE_SO_BINDTODEVICE */
1.1 misho 1371: case OPT_CLIENT_PORT:
1.1.1.2 misho 1372: portno = atoi(optarg);
1373: if (portno < 1 || portno > 65535) {
1374: i_errno = IEBADPORT;
1375: return -1;
1376: }
1377: test->bind_port = portno;
1.1 misho 1378: break;
1379: case 'M':
1380: test->settings->mss = atoi(optarg);
1381: if (test->settings->mss > MAX_MSS) {
1382: i_errno = IEMSS;
1383: return -1;
1384: }
1385: client_flag = 1;
1386: break;
1387: case 'N':
1388: test->no_delay = 1;
1389: client_flag = 1;
1390: break;
1391: case '4':
1392: test->settings->domain = AF_INET;
1393: break;
1394: case '6':
1395: test->settings->domain = AF_INET6;
1396: break;
1397: case 'S':
1398: test->settings->tos = strtol(optarg, &endptr, 0);
1399: if (endptr == optarg ||
1400: test->settings->tos < 0 ||
1401: test->settings->tos > 255) {
1402: i_errno = IEBADTOS;
1403: return -1;
1404: }
1405: client_flag = 1;
1406: break;
1.1.1.2 misho 1407: case OPT_DSCP:
1408: test->settings->tos = parse_qos(optarg);
1409: if(test->settings->tos < 0) {
1410: i_errno = IEBADTOS;
1411: return -1;
1412: }
1413: client_flag = 1;
1414: break;
1415: case OPT_EXTRA_DATA:
1416: test->extra_data = strdup(optarg);
1417: client_flag = 1;
1418: break;
1.1 misho 1419: case 'L':
1420: #if defined(HAVE_FLOWLABEL)
1421: test->settings->flowlabel = strtol(optarg, &endptr, 0);
1422: if (endptr == optarg ||
1423: test->settings->flowlabel < 1 || test->settings->flowlabel > 0xfffff) {
1424: i_errno = IESETFLOW;
1425: return -1;
1426: }
1427: client_flag = 1;
1428: #else /* HAVE_FLOWLABEL */
1429: i_errno = IEUNIMP;
1430: return -1;
1431: #endif /* HAVE_FLOWLABEL */
1432: break;
1433: case 'X':
1434: xbe = (struct xbind_entry *)malloc(sizeof(struct xbind_entry));
1435: if (!xbe) {
1436: i_errno = IESETSCTPBINDX;
1437: return -1;
1438: }
1439: memset(xbe, 0, sizeof(*xbe));
1440: xbe->name = strdup(optarg);
1441: if (!xbe->name) {
1442: i_errno = IESETSCTPBINDX;
1443: return -1;
1444: }
1445: TAILQ_INSERT_TAIL(&test->xbind_addrs, xbe, link);
1446: break;
1447: case 'Z':
1448: if (!has_sendfile()) {
1449: i_errno = IENOSENDFILE;
1450: return -1;
1451: }
1452: test->zerocopy = 1;
1453: client_flag = 1;
1454: break;
1.1.1.2 misho 1455: case OPT_REPEATING_PAYLOAD:
1456: test->repeating_payload = 1;
1457: client_flag = 1;
1458: break;
1459: case OPT_TIMESTAMPS:
1460: iperf_set_test_timestamps(test, 1);
1461: if (optarg) {
1462: iperf_set_test_timestamp_format(test, optarg);
1463: }
1464: else {
1465: iperf_set_test_timestamp_format(test, TIMESTAMP_FORMAT);
1466: }
1467: break;
1.1 misho 1468: case 'O':
1469: test->omit = atoi(optarg);
1470: if (test->omit < 0 || test->omit > 60) {
1471: i_errno = IEOMIT;
1472: return -1;
1473: }
1474: client_flag = 1;
1475: break;
1476: case 'F':
1477: test->diskfile_name = optarg;
1478: break;
1.1.1.3 ! misho 1479: case OPT_IDLE_TIMEOUT:
! 1480: test->settings->idle_timeout = atoi(optarg);
! 1481: if (test->settings->idle_timeout < 1 || test->settings->idle_timeout > MAX_TIME) {
! 1482: i_errno = IEIDLETIMEOUT;
! 1483: return -1;
! 1484: }
! 1485: server_flag = 1;
! 1486: break;
! 1487: case OPT_RCV_TIMEOUT:
! 1488: rcv_timeout_in = atoi(optarg);
! 1489: if (rcv_timeout_in < MIN_NO_MSG_RCVD_TIMEOUT || rcv_timeout_in > MAX_TIME * SEC_TO_mS) {
! 1490: i_errno = IERCVTIMEOUT;
! 1491: return -1;
! 1492: }
! 1493: test->settings->rcv_timeout.secs = rcv_timeout_in / SEC_TO_mS;
! 1494: test->settings->rcv_timeout.usecs = (rcv_timeout_in % SEC_TO_mS) * mS_TO_US;
! 1495: rcv_timeout_flag = 1;
! 1496: break;
! 1497: #if defined(HAVE_TCP_USER_TIMEOUT)
! 1498: case OPT_SND_TIMEOUT:
! 1499: test->settings->snd_timeout = atoi(optarg);
! 1500: if (test->settings->snd_timeout < 0 || test->settings->snd_timeout > MAX_TIME * SEC_TO_mS) {
! 1501: i_errno = IESNDTIMEOUT;
! 1502: return -1;
! 1503: }
! 1504: snd_timeout_flag = 1;
! 1505: break;
! 1506: #endif /* HAVE_TCP_USER_TIMEOUT */
1.1 misho 1507: case 'A':
1508: #if defined(HAVE_CPU_AFFINITY)
1509: test->affinity = strtol(optarg, &endptr, 0);
1.1.1.3 ! misho 1510: if (endptr == optarg ||
1.1 misho 1511: test->affinity < 0 || test->affinity > 1024) {
1512: i_errno = IEAFFINITY;
1513: return -1;
1514: }
1515: comma = strchr(optarg, ',');
1516: if (comma != NULL) {
1517: test->server_affinity = atoi(comma+1);
1518: if (test->server_affinity < 0 || test->server_affinity > 1024) {
1519: i_errno = IEAFFINITY;
1520: return -1;
1521: }
1522: client_flag = 1;
1523: }
1524: #else /* HAVE_CPU_AFFINITY */
1525: i_errno = IEUNIMP;
1526: return -1;
1527: #endif /* HAVE_CPU_AFFINITY */
1528: break;
1529: case 'T':
1530: test->title = strdup(optarg);
1531: client_flag = 1;
1532: break;
1533: case 'C':
1534: #if defined(HAVE_TCP_CONGESTION)
1535: test->congestion = strdup(optarg);
1536: client_flag = 1;
1537: #else /* HAVE_TCP_CONGESTION */
1538: i_errno = IEUNIMP;
1539: return -1;
1540: #endif /* HAVE_TCP_CONGESTION */
1541: break;
1542: case 'd':
1543: test->debug = 1;
1.1.1.3 ! misho 1544: test->debug_level = DEBUG_LEVEL_MAX;
! 1545: if (optarg) {
! 1546: test->debug_level = atoi(optarg);
! 1547: if (test->debug_level < 0)
! 1548: test->debug_level = DEBUG_LEVEL_MAX;
! 1549: }
1.1 misho 1550: break;
1551: case 'I':
1552: test->pidfile = strdup(optarg);
1553: break;
1554: case OPT_LOGFILE:
1555: test->logfile = strdup(optarg);
1556: break;
1.1.1.2 misho 1557: case OPT_FORCEFLUSH:
1558: test->forceflush = 1;
1559: break;
1.1 misho 1560: case OPT_GET_SERVER_OUTPUT:
1561: test->get_server_output = 1;
1562: client_flag = 1;
1563: break;
1564: case OPT_UDP_COUNTERS_64BIT:
1565: test->udp_counters_64bit = 1;
1566: break;
1567: case OPT_NO_FQ_SOCKET_PACING:
1568: #if defined(HAVE_SO_MAX_PACING_RATE)
1.1.1.2 misho 1569: printf("Warning: --no-fq-socket-pacing is deprecated\n");
1570: test->settings->fqrate = 0;
1571: client_flag = 1;
1.1 misho 1572: #else /* HAVE_SO_MAX_PACING_RATE */
1573: i_errno = IEUNIMP;
1574: return -1;
1575: #endif
1576: break;
1.1.1.2 misho 1577: case OPT_FQ_RATE:
1578: #if defined(HAVE_SO_MAX_PACING_RATE)
1579: test->settings->fqrate = unit_atof_rate(optarg);
1580: client_flag = 1;
1581: #else /* HAVE_SO_MAX_PACING_RATE */
1582: i_errno = IEUNIMP;
1583: return -1;
1584: #endif
1585: break;
1.1.1.3 ! misho 1586: #if defined(HAVE_DONT_FRAGMENT)
! 1587: case OPT_DONT_FRAGMENT:
! 1588: test->settings->dont_fragment = 1;
! 1589: client_flag = 1;
! 1590: break;
! 1591: #endif /* HAVE_DONT_FRAGMENT */
1.1.1.2 misho 1592: #if defined(HAVE_SSL)
1593: case OPT_CLIENT_USERNAME:
1594: client_username = strdup(optarg);
1595: break;
1596: case OPT_CLIENT_RSA_PUBLIC_KEY:
1597: client_rsa_public_key = strdup(optarg);
1598: break;
1599: case OPT_SERVER_RSA_PRIVATE_KEY:
1600: server_rsa_private_key = strdup(optarg);
1601: break;
1602: case OPT_SERVER_AUTHORIZED_USERS:
1603: test->server_authorized_users = strdup(optarg);
1604: break;
1.1.1.3 ! misho 1605: case OPT_SERVER_SKEW_THRESHOLD:
! 1606: test->server_skew_threshold = atoi(optarg);
! 1607: if(test->server_skew_threshold <= 0){
! 1608: i_errno = IESKEWTHRESHOLD;
! 1609: return -1;
! 1610: }
! 1611: break;
1.1.1.2 misho 1612: #endif /* HAVE_SSL */
1613: case OPT_PACING_TIMER:
1614: test->settings->pacing_timer = unit_atoi(optarg);
1615: client_flag = 1;
1616: break;
1617: case OPT_CONNECT_TIMEOUT:
1618: test->settings->connect_timeout = unit_atoi(optarg);
1619: client_flag = 1;
1620: break;
1621: case 'h':
1622: usage_long(stdout);
1623: exit(0);
1.1 misho 1624: default:
1.1.1.3 ! misho 1625: fprintf(stderr, "\n");
! 1626: usage();
1.1 misho 1627: exit(1);
1628: }
1629: }
1630:
1631: /* Check flag / role compatibility. */
1632: if (test->role == 'c' && server_flag) {
1.1.1.2 misho 1633: i_errno = IESERVERONLY;
1634: return -1;
1.1 misho 1635: }
1636: if (test->role == 's' && client_flag) {
1.1.1.2 misho 1637: i_errno = IECLIENTONLY;
1638: return -1;
1639: }
1640:
1641: #if defined(HAVE_SSL)
1642:
1643: if (test->role == 's' && (client_username || client_rsa_public_key)){
1644: i_errno = IECLIENTONLY;
1645: return -1;
1.1.1.3 ! misho 1646: } else if (test->role == 'c' && (client_username || client_rsa_public_key) &&
1.1.1.2 misho 1647: !(client_username && client_rsa_public_key)) {
1648: i_errno = IESETCLIENTAUTH;
1649: return -1;
1650: } else if (test->role == 'c' && (client_username && client_rsa_public_key)){
1651:
1652: char *client_password = NULL;
1653: size_t s;
1.1.1.3 ! misho 1654: if (test_load_pubkey_from_file(client_rsa_public_key) < 0){
! 1655: iperf_err(test, "%s\n", ERR_error_string(ERR_get_error(), NULL));
! 1656: i_errno = IESETCLIENTAUTH;
! 1657: return -1;
! 1658: }
1.1.1.2 misho 1659: /* Need to copy env var, so we can do a common free */
1660: if ((client_password = getenv("IPERF3_PASSWORD")) != NULL)
1661: client_password = strdup(client_password);
1662: else if (iperf_getpass(&client_password, &s, stdin) < 0){
1663: i_errno = IESETCLIENTAUTH;
1664: return -1;
1665: }
1666:
1667: test->settings->client_username = client_username;
1668: test->settings->client_password = client_password;
1669: test->settings->client_rsa_pubkey = load_pubkey_from_file(client_rsa_public_key);
1670: free(client_rsa_public_key);
1671: client_rsa_public_key = NULL;
1.1 misho 1672: }
1673:
1.1.1.2 misho 1674: if (test->role == 'c' && (server_rsa_private_key || test->server_authorized_users)){
1675: i_errno = IESERVERONLY;
1.1 misho 1676: return -1;
1.1.1.3 ! misho 1677: } else if (test->role == 'c' && (test->server_skew_threshold != 0)){
! 1678: i_errno = IESERVERONLY;
! 1679: return -1;
! 1680: } else if (test->role == 'c' && rcv_timeout_flag && test->mode == SENDER){
! 1681: i_errno = IERVRSONLYRCVTIMEOUT;
! 1682: return -1;
! 1683: } else if (test->role == 's' && (server_rsa_private_key || test->server_authorized_users) &&
1.1.1.2 misho 1684: !(server_rsa_private_key && test->server_authorized_users)) {
1685: i_errno = IESETSERVERAUTH;
1686: return -1;
1687: } else if (test->role == 's' && server_rsa_private_key) {
1688: test->server_rsa_private_key = load_privkey_from_file(server_rsa_private_key);
1689: if (test->server_rsa_private_key == NULL){
1.1.1.3 ! misho 1690: iperf_err(test, "%s\n", ERR_error_string(ERR_get_error(), NULL));
1.1.1.2 misho 1691: i_errno = IESETSERVERAUTH;
1692: return -1;
1693: }
1.1.1.3 ! misho 1694: free(server_rsa_private_key);
! 1695: server_rsa_private_key = NULL;
! 1696:
! 1697: if(test->server_skew_threshold == 0){
! 1698: // Set default value for time skew threshold
! 1699: test->server_skew_threshold=10;
! 1700: }
1.1 misho 1701: }
1.1.1.2 misho 1702:
1703: #endif //HAVE_SSL
1.1.1.3 ! misho 1704:
! 1705: // File cannot be transferred using UDP because of the UDP packets header (packet number, etc.)
! 1706: if(test->role == 'c' && test->diskfile_name != (char*) 0 && test->protocol->id == Pudp) {
! 1707: i_errno = IEUDPFILETRANSFER;
! 1708: return -1;
! 1709: }
! 1710:
1.1 misho 1711: if (blksize == 0) {
1712: if (test->protocol->id == Pudp)
1.1.1.2 misho 1713: blksize = 0; /* try to dynamically determine from MSS */
1.1 misho 1714: else if (test->protocol->id == Psctp)
1715: blksize = DEFAULT_SCTP_BLKSIZE;
1716: else
1717: blksize = DEFAULT_TCP_BLKSIZE;
1718: }
1.1.1.3 ! misho 1719: if ((test->protocol->id != Pudp && blksize <= 0)
1.1.1.2 misho 1720: || blksize > MAX_BLOCKSIZE) {
1.1 misho 1721: i_errno = IEBLOCKSIZE;
1722: return -1;
1723: }
1724: if (test->protocol->id == Pudp &&
1.1.1.2 misho 1725: (blksize > 0 &&
1726: (blksize < MIN_UDP_BLOCKSIZE || blksize > MAX_UDP_BLOCKSIZE))) {
1.1 misho 1727: i_errno = IEUDPBLOCKSIZE;
1728: return -1;
1729: }
1730: test->settings->blksize = blksize;
1731:
1732: if (!rate_flag)
1733: test->settings->rate = test->protocol->id == Pudp ? UDP_RATE : 0;
1734:
1.1.1.3 ! misho 1735: /* if no bytes or blocks specified, nor a duration_flag, and we have -F,
! 1736: ** get the file-size as the bytes count to be transferred
! 1737: */
! 1738: if (test->settings->bytes == 0 &&
! 1739: test->settings->blocks == 0 &&
! 1740: ! duration_flag &&
! 1741: test->diskfile_name != (char*) 0 &&
! 1742: test->role == 'c'
! 1743: ){
! 1744: struct stat st;
! 1745: if( stat(test->diskfile_name, &st) == 0 ){
! 1746: iperf_size_t file_bytes = st.st_size;
! 1747: test->settings->bytes = file_bytes;
! 1748: if (test->debug)
! 1749: printf("End condition set to file-size: %"PRIu64" bytes\n", test->settings->bytes);
! 1750: }
! 1751: // if failing to read file stat, it should fallback to default duration mode
! 1752: }
! 1753:
1.1 misho 1754: if ((test->settings->bytes != 0 || test->settings->blocks != 0) && ! duration_flag)
1755: test->duration = 0;
1756:
1757: /* Disallow specifying multiple test end conditions. The code actually
1758: ** works just fine without this prohibition. As soon as any one of the
1759: ** three possible end conditions is met, the test ends. So this check
1760: ** could be removed if desired.
1761: */
1762: if ((duration_flag && test->settings->bytes != 0) ||
1763: (duration_flag && test->settings->blocks != 0) ||
1764: (test->settings->bytes != 0 && test->settings->blocks != 0)) {
1765: i_errno = IEENDCONDITIONS;
1766: return -1;
1767: }
1768:
1769: /* For subsequent calls to getopt */
1770: #ifdef __APPLE__
1771: optreset = 1;
1772: #endif
1773: optind = 0;
1774:
1775: if ((test->role != 'c') && (test->role != 's')) {
1776: i_errno = IENOROLE;
1777: return -1;
1778: }
1779:
1.1.1.2 misho 1780: /* Set Total-rate average interval to multiplicity of State interval */
1781: if (test->settings->bitrate_limit_interval != 0) {
1782: test->settings->bitrate_limit_stats_per_interval =
1783: (test->settings->bitrate_limit_interval <= test->stats_interval ?
1784: 1 : round(test->settings->bitrate_limit_interval/test->stats_interval) );
1785: }
1786:
1787: /* Show warning if JSON output is used with explicit report format */
1788: if ((test->json_output) && (test->settings->unit_format != 'a')) {
1789: warning("Report format (-f) flag ignored with JSON output (-J)");
1790: }
1791:
1792: /* Show warning if JSON output is used with verbose or debug flags */
1793: if (test->json_output && test->verbose) {
1794: warning("Verbose output (-v) may interfere with JSON output (-J)");
1795: }
1796: if (test->json_output && test->debug) {
1797: warning("Debug output (-d) may interfere with JSON output (-J)");
1798: }
1799:
1800: return 0;
1801: }
1802:
1803: /*
1804: * Open the file specified by test->logfile and set test->outfile to its' FD.
1805: */
1806: int iperf_open_logfile(struct iperf_test *test)
1807: {
1808: test->outfile = fopen(test->logfile, "a+");
1809: if (test->outfile == NULL) {
1810: i_errno = IELOGFILE;
1811: return -1;
1812: }
1813:
1.1 misho 1814: return 0;
1815: }
1816:
1.1.1.3 ! misho 1817: void iperf_close_logfile(struct iperf_test *test)
! 1818: {
! 1819: if (test->outfile && test->outfile != stdout) {
! 1820: fclose(test->outfile);
! 1821: test->outfile = NULL;
! 1822: }
! 1823: }
! 1824:
1.1 misho 1825: int
1826: iperf_set_send_state(struct iperf_test *test, signed char state)
1827: {
1.1.1.3 ! misho 1828: if (test->ctrl_sck >= 0) {
! 1829: test->state = state;
! 1830: if (Nwrite(test->ctrl_sck, (char*) &state, sizeof(state), Ptcp) < 0) {
! 1831: i_errno = IESENDMESSAGE;
! 1832: return -1;
! 1833: }
1.1 misho 1834: }
1835: return 0;
1836: }
1837:
1838: void
1.1.1.2 misho 1839: iperf_check_throttle(struct iperf_stream *sp, struct iperf_time *nowP)
1.1 misho 1840: {
1.1.1.2 misho 1841: struct iperf_time temp_time;
1.1 misho 1842: double seconds;
1843: uint64_t bits_per_second;
1844:
1.1.1.3 ! misho 1845: if (sp->test->done || sp->test->settings->rate == 0)
1.1 misho 1846: return;
1.1.1.2 misho 1847: iperf_time_diff(&sp->result->start_time_fixed, nowP, &temp_time);
1848: seconds = iperf_time_in_secs(&temp_time);
1.1 misho 1849: bits_per_second = sp->result->bytes_sent * 8 / seconds;
1850: if (bits_per_second < sp->test->settings->rate) {
1851: sp->green_light = 1;
1852: FD_SET(sp->socket, &sp->test->write_set);
1853: } else {
1854: sp->green_light = 0;
1855: FD_CLR(sp->socket, &sp->test->write_set);
1856: }
1857: }
1858:
1.1.1.3 ! misho 1859: /* Verify that average traffic is not greater than the specified limit */
1.1.1.2 misho 1860: void
1861: iperf_check_total_rate(struct iperf_test *test, iperf_size_t last_interval_bytes_transferred)
1862: {
1863: double seconds;
1864: uint64_t bits_per_second;
1865: iperf_size_t total_bytes;
1866: int i;
1867:
1868: if (test->done || test->settings->bitrate_limit == 0) // Continue only if check should be done
1869: return;
1.1.1.3 ! misho 1870:
! 1871: /* Add last inetrval's transferred bytes to the array */
1.1.1.2 misho 1872: if (++test->bitrate_limit_last_interval_index >= test->settings->bitrate_limit_stats_per_interval)
1873: test->bitrate_limit_last_interval_index = 0;
1874: test->bitrate_limit_intervals_traffic_bytes[test->bitrate_limit_last_interval_index] = last_interval_bytes_transferred;
1875:
1876: /* Ensure that enough stats periods passed to allow averaging throughput */
1877: test->bitrate_limit_stats_count += 1;
1878: if (test->bitrate_limit_stats_count < test->settings->bitrate_limit_stats_per_interval)
1879: return;
1.1.1.3 ! misho 1880:
1.1.1.2 misho 1881: /* Calculating total bytes traffic to be averaged */
1882: for (total_bytes = 0, i = 0; i < test->settings->bitrate_limit_stats_per_interval; i++) {
1883: total_bytes += test->bitrate_limit_intervals_traffic_bytes[i];
1884: }
1885:
1886: seconds = test->stats_interval * test->settings->bitrate_limit_stats_per_interval;
1887: bits_per_second = total_bytes * 8 / seconds;
1888: if (test->debug) {
1889: iperf_printf(test,"Interval %" PRIu64 " - throughput %" PRIu64 " bps (limit %" PRIu64 ")\n", test->bitrate_limit_stats_count, bits_per_second, test->settings->bitrate_limit);
1890: }
1891:
1892: if (bits_per_second > test->settings->bitrate_limit) {
1.1.1.3 ! misho 1893: if (iperf_get_verbose(test))
! 1894: iperf_err(test, "Total throughput of %" PRIu64 " bps exceeded %" PRIu64 " bps limit", bits_per_second, test->settings->bitrate_limit);
1.1.1.2 misho 1895: test->bitrate_limit_exceeded = 1;
1896: }
1897: }
1898:
1.1 misho 1899: int
1900: iperf_send(struct iperf_test *test, fd_set *write_setP)
1901: {
1902: register int multisend, r, streams_active;
1903: register struct iperf_stream *sp;
1.1.1.2 misho 1904: struct iperf_time now;
1.1.1.3 ! misho 1905: int no_throttle_check;
1.1 misho 1906:
1907: /* Can we do multisend mode? */
1908: if (test->settings->burst != 0)
1909: multisend = test->settings->burst;
1910: else if (test->settings->rate == 0)
1911: multisend = test->multisend;
1912: else
1913: multisend = 1; /* nope */
1914:
1.1.1.3 ! misho 1915: /* Should bitrate throttle be checked for every send */
! 1916: no_throttle_check = test->settings->rate != 0 && test->settings->burst == 0;
! 1917:
1.1 misho 1918: for (; multisend > 0; --multisend) {
1.1.1.3 ! misho 1919: if (no_throttle_check)
1.1.1.2 misho 1920: iperf_time_now(&now);
1.1 misho 1921: streams_active = 0;
1922: SLIST_FOREACH(sp, &test->streams, streams) {
1.1.1.2 misho 1923: if ((sp->green_light && sp->sender &&
1.1 misho 1924: (write_setP == NULL || FD_ISSET(sp->socket, write_setP)))) {
1.1.1.3 ! misho 1925: if (multisend > 1 && test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes)
! 1926: break;
! 1927: if (multisend > 1 && test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks)
! 1928: break;
1.1 misho 1929: if ((r = sp->snd(sp)) < 0) {
1930: if (r == NET_SOFTERROR)
1931: break;
1932: i_errno = IESTREAMWRITE;
1933: return r;
1934: }
1935: streams_active = 1;
1936: test->bytes_sent += r;
1.1.1.3 ! misho 1937: if (!sp->pending_size)
! 1938: ++test->blocks_sent;
! 1939: if (no_throttle_check)
! 1940: iperf_check_throttle(sp, &now);
1.1 misho 1941: }
1942: }
1943: if (!streams_active)
1944: break;
1945: }
1.1.1.3 ! misho 1946: if (!no_throttle_check) { /* Throttle check if was not checked for each send */
1.1.1.2 misho 1947: iperf_time_now(&now);
1.1 misho 1948: SLIST_FOREACH(sp, &test->streams, streams)
1.1.1.2 misho 1949: if (sp->sender)
1950: iperf_check_throttle(sp, &now);
1.1 misho 1951: }
1952: if (write_setP != NULL)
1953: SLIST_FOREACH(sp, &test->streams, streams)
1954: if (FD_ISSET(sp->socket, write_setP))
1955: FD_CLR(sp->socket, write_setP);
1956:
1957: return 0;
1958: }
1959:
1960: int
1961: iperf_recv(struct iperf_test *test, fd_set *read_setP)
1962: {
1963: int r;
1964: struct iperf_stream *sp;
1965:
1966: SLIST_FOREACH(sp, &test->streams, streams) {
1.1.1.2 misho 1967: if (FD_ISSET(sp->socket, read_setP) && !sp->sender) {
1.1 misho 1968: if ((r = sp->rcv(sp)) < 0) {
1969: i_errno = IESTREAMREAD;
1970: return r;
1971: }
1.1.1.2 misho 1972: test->bytes_received += r;
1973: ++test->blocks_received;
1.1 misho 1974: FD_CLR(sp->socket, read_setP);
1975: }
1976: }
1977:
1978: return 0;
1979: }
1980:
1981: int
1982: iperf_init_test(struct iperf_test *test)
1983: {
1.1.1.2 misho 1984: struct iperf_time now;
1.1 misho 1985: struct iperf_stream *sp;
1986:
1987: if (test->protocol->init) {
1988: if (test->protocol->init(test) < 0)
1989: return -1;
1990: }
1991:
1992: /* Init each stream. */
1.1.1.2 misho 1993: if (iperf_time_now(&now) < 0) {
1.1 misho 1994: i_errno = IEINITTEST;
1995: return -1;
1996: }
1997: SLIST_FOREACH(sp, &test->streams, streams) {
1998: sp->result->start_time = sp->result->start_time_fixed = now;
1999: }
2000:
2001: if (test->on_test_start)
2002: test->on_test_start(test);
2003:
2004: return 0;
2005: }
2006:
2007: static void
1.1.1.2 misho 2008: send_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
1.1 misho 2009: {
2010: struct iperf_stream *sp = client_data.p;
2011:
2012: /* All we do here is set or clear the flag saying that this stream may
2013: ** be sent to. The actual sending gets done in the send proc, after
2014: ** checking the flag.
2015: */
2016: iperf_check_throttle(sp, nowP);
2017: }
2018:
2019: int
2020: iperf_create_send_timers(struct iperf_test * test)
2021: {
1.1.1.2 misho 2022: struct iperf_time now;
1.1 misho 2023: struct iperf_stream *sp;
2024: TimerClientData cd;
2025:
1.1.1.2 misho 2026: if (iperf_time_now(&now) < 0) {
1.1 misho 2027: i_errno = IEINITTEST;
2028: return -1;
2029: }
2030: SLIST_FOREACH(sp, &test->streams, streams) {
2031: sp->green_light = 1;
1.1.1.2 misho 2032: if (test->settings->rate != 0 && sp->sender) {
1.1 misho 2033: cd.p = sp;
1.1.1.2 misho 2034: sp->send_timer = tmr_create(NULL, send_timer_proc, cd, test->settings->pacing_timer, 1);
1.1 misho 2035: if (sp->send_timer == NULL) {
2036: i_errno = IEINITTEST;
2037: return -1;
2038: }
2039: }
2040: }
2041: return 0;
2042: }
2043:
1.1.1.2 misho 2044: #if defined(HAVE_SSL)
2045: int test_is_authorized(struct iperf_test *test){
2046: if ( !(test->server_rsa_private_key && test->server_authorized_users)) {
2047: return 0;
2048: }
2049:
2050: if (test->settings->authtoken){
2051: char *username = NULL, *password = NULL;
2052: time_t ts;
2053: int rc = decode_auth_setting(test->debug, test->settings->authtoken, test->server_rsa_private_key, &username, &password, &ts);
2054: if (rc) {
2055: return -1;
2056: }
1.1.1.3 ! misho 2057: int ret = check_authentication(username, password, ts, test->server_authorized_users, test->server_skew_threshold);
1.1.1.2 misho 2058: if (ret == 0){
1.1.1.3 ! misho 2059: if (test->debug) {
! 2060: iperf_printf(test, report_authentication_succeeded, username, ts);
! 2061: }
1.1.1.2 misho 2062: free(username);
2063: free(password);
2064: return 0;
2065: } else {
1.1.1.3 ! misho 2066: if (test->debug) {
! 2067: iperf_printf(test, report_authentication_failed, ret, username, ts);
! 2068: }
1.1.1.2 misho 2069: free(username);
2070: free(password);
2071: return -1;
2072: }
2073: }
2074: return -1;
2075: }
2076: #endif //HAVE_SSL
2077:
1.1 misho 2078: /**
2079: * iperf_exchange_parameters - handles the param_Exchange part for client
2080: *
2081: */
2082:
2083: int
2084: iperf_exchange_parameters(struct iperf_test *test)
2085: {
2086: int s;
2087: int32_t err;
2088:
2089: if (test->role == 'c') {
2090:
2091: if (send_parameters(test) < 0)
2092: return -1;
2093:
2094: } else {
2095:
2096: if (get_parameters(test) < 0)
2097: return -1;
2098:
1.1.1.2 misho 2099: #if defined(HAVE_SSL)
2100: if (test_is_authorized(test) < 0){
2101: if (iperf_set_send_state(test, SERVER_ERROR) != 0)
2102: return -1;
2103: i_errno = IEAUTHTEST;
2104: err = htonl(i_errno);
2105: if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
2106: i_errno = IECTRLWRITE;
2107: return -1;
2108: }
2109: return -1;
2110: }
2111: #endif //HAVE_SSL
2112:
1.1 misho 2113: if ((s = test->protocol->listen(test)) < 0) {
1.1.1.2 misho 2114: if (iperf_set_send_state(test, SERVER_ERROR) != 0)
1.1 misho 2115: return -1;
2116: err = htonl(i_errno);
2117: if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
2118: i_errno = IECTRLWRITE;
2119: return -1;
2120: }
2121: err = htonl(errno);
2122: if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
2123: i_errno = IECTRLWRITE;
2124: return -1;
2125: }
2126: return -1;
2127: }
1.1.1.2 misho 2128:
1.1 misho 2129: FD_SET(s, &test->read_set);
2130: test->max_fd = (s > test->max_fd) ? s : test->max_fd;
2131: test->prot_listener = s;
2132:
2133: // Send the control message to create streams and start the test
2134: if (iperf_set_send_state(test, CREATE_STREAMS) != 0)
2135: return -1;
2136:
2137: }
2138:
2139: return 0;
2140: }
2141:
2142: /*************************************************************/
2143:
2144: int
2145: iperf_exchange_results(struct iperf_test *test)
2146: {
2147: if (test->role == 'c') {
2148: /* Send results to server. */
2149: if (send_results(test) < 0)
2150: return -1;
2151: /* Get server results. */
2152: if (get_results(test) < 0)
2153: return -1;
2154: } else {
2155: /* Get client results. */
2156: if (get_results(test) < 0)
2157: return -1;
2158: /* Send results to client. */
2159: if (send_results(test) < 0)
2160: return -1;
2161: }
2162: return 0;
2163: }
2164:
2165: /*************************************************************/
2166:
2167: static int
2168: send_parameters(struct iperf_test *test)
2169: {
2170: int r = 0;
2171: cJSON *j;
2172:
2173: j = cJSON_CreateObject();
2174: if (j == NULL) {
2175: i_errno = IESENDPARAMS;
2176: r = -1;
2177: } else {
2178: if (test->protocol->id == Ptcp)
2179: cJSON_AddTrueToObject(j, "tcp");
2180: else if (test->protocol->id == Pudp)
2181: cJSON_AddTrueToObject(j, "udp");
2182: else if (test->protocol->id == Psctp)
2183: cJSON_AddTrueToObject(j, "sctp");
2184: cJSON_AddNumberToObject(j, "omit", test->omit);
2185: if (test->server_affinity != -1)
2186: cJSON_AddNumberToObject(j, "server_affinity", test->server_affinity);
1.1.1.2 misho 2187: cJSON_AddNumberToObject(j, "time", test->duration);
1.1.1.3 ! misho 2188: cJSON_AddNumberToObject(j, "num", test->settings->bytes);
! 2189: cJSON_AddNumberToObject(j, "blockcount", test->settings->blocks);
1.1 misho 2190: if (test->settings->mss)
2191: cJSON_AddNumberToObject(j, "MSS", test->settings->mss);
2192: if (test->no_delay)
2193: cJSON_AddTrueToObject(j, "nodelay");
2194: cJSON_AddNumberToObject(j, "parallel", test->num_streams);
2195: if (test->reverse)
2196: cJSON_AddTrueToObject(j, "reverse");
1.1.1.2 misho 2197: if (test->bidirectional)
2198: cJSON_AddTrueToObject(j, "bidirectional");
1.1 misho 2199: if (test->settings->socket_bufsize)
2200: cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);
2201: if (test->settings->blksize)
2202: cJSON_AddNumberToObject(j, "len", test->settings->blksize);
2203: if (test->settings->rate)
2204: cJSON_AddNumberToObject(j, "bandwidth", test->settings->rate);
1.1.1.2 misho 2205: if (test->settings->fqrate)
2206: cJSON_AddNumberToObject(j, "fqrate", test->settings->fqrate);
2207: if (test->settings->pacing_timer)
2208: cJSON_AddNumberToObject(j, "pacing_timer", test->settings->pacing_timer);
1.1 misho 2209: if (test->settings->burst)
2210: cJSON_AddNumberToObject(j, "burst", test->settings->burst);
2211: if (test->settings->tos)
2212: cJSON_AddNumberToObject(j, "TOS", test->settings->tos);
2213: if (test->settings->flowlabel)
2214: cJSON_AddNumberToObject(j, "flowlabel", test->settings->flowlabel);
2215: if (test->title)
2216: cJSON_AddStringToObject(j, "title", test->title);
1.1.1.2 misho 2217: if (test->extra_data)
2218: cJSON_AddStringToObject(j, "extra_data", test->extra_data);
1.1 misho 2219: if (test->congestion)
2220: cJSON_AddStringToObject(j, "congestion", test->congestion);
1.1.1.2 misho 2221: if (test->congestion_used)
2222: cJSON_AddStringToObject(j, "congestion_used", test->congestion_used);
1.1 misho 2223: if (test->get_server_output)
2224: cJSON_AddNumberToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
2225: if (test->udp_counters_64bit)
2226: cJSON_AddNumberToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));
1.1.1.2 misho 2227: if (test->repeating_payload)
2228: cJSON_AddNumberToObject(j, "repeating_payload", test->repeating_payload);
1.1.1.3 ! misho 2229: if (test->zerocopy)
! 2230: cJSON_AddNumberToObject(j, "zerocopy", test->zerocopy);
! 2231: #if defined(HAVE_DONT_FRAGMENT)
! 2232: if (test->settings->dont_fragment)
! 2233: cJSON_AddNumberToObject(j, "dont_fragment", test->settings->dont_fragment);
! 2234: #endif /* HAVE_DONT_FRAGMENT */
1.1.1.2 misho 2235: #if defined(HAVE_SSL)
2236: /* Send authentication parameters */
2237: if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){
2238: int rc = encode_auth_setting(test->settings->client_username, test->settings->client_password, test->settings->client_rsa_pubkey, &test->settings->authtoken);
2239:
2240: if (rc) {
2241: cJSON_Delete(j);
2242: i_errno = IESENDPARAMS;
2243: return -1;
2244: }
1.1.1.3 ! misho 2245:
1.1.1.2 misho 2246: cJSON_AddStringToObject(j, "authtoken", test->settings->authtoken);
2247: }
2248: #endif // HAVE_SSL
1.1 misho 2249: cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);
2250:
2251: if (test->debug) {
1.1.1.2 misho 2252: char *str = cJSON_Print(j);
2253: printf("send_parameters:\n%s\n", str);
2254: cJSON_free(str);
1.1 misho 2255: }
2256:
2257: if (JSON_write(test->ctrl_sck, j) < 0) {
2258: i_errno = IESENDPARAMS;
2259: r = -1;
2260: }
2261: cJSON_Delete(j);
2262: }
2263: return r;
2264: }
2265:
2266: /*************************************************************/
2267:
2268: static int
2269: get_parameters(struct iperf_test *test)
2270: {
2271: int r = 0;
2272: cJSON *j;
2273: cJSON *j_p;
2274:
2275: j = JSON_read(test->ctrl_sck);
2276: if (j == NULL) {
2277: i_errno = IERECVPARAMS;
2278: r = -1;
2279: } else {
2280: if (test->debug) {
1.1.1.2 misho 2281: char *str;
2282: str = cJSON_Print(j);
2283: printf("get_parameters:\n%s\n", str );
2284: cJSON_free(str);
1.1 misho 2285: }
2286:
2287: if ((j_p = cJSON_GetObjectItem(j, "tcp")) != NULL)
2288: set_protocol(test, Ptcp);
2289: if ((j_p = cJSON_GetObjectItem(j, "udp")) != NULL)
2290: set_protocol(test, Pudp);
2291: if ((j_p = cJSON_GetObjectItem(j, "sctp")) != NULL)
2292: set_protocol(test, Psctp);
2293: if ((j_p = cJSON_GetObjectItem(j, "omit")) != NULL)
2294: test->omit = j_p->valueint;
2295: if ((j_p = cJSON_GetObjectItem(j, "server_affinity")) != NULL)
2296: test->server_affinity = j_p->valueint;
2297: if ((j_p = cJSON_GetObjectItem(j, "time")) != NULL)
2298: test->duration = j_p->valueint;
1.1.1.3 ! misho 2299: test->settings->bytes = 0;
1.1 misho 2300: if ((j_p = cJSON_GetObjectItem(j, "num")) != NULL)
2301: test->settings->bytes = j_p->valueint;
1.1.1.3 ! misho 2302: test->settings->blocks = 0;
1.1 misho 2303: if ((j_p = cJSON_GetObjectItem(j, "blockcount")) != NULL)
2304: test->settings->blocks = j_p->valueint;
2305: if ((j_p = cJSON_GetObjectItem(j, "MSS")) != NULL)
2306: test->settings->mss = j_p->valueint;
2307: if ((j_p = cJSON_GetObjectItem(j, "nodelay")) != NULL)
2308: test->no_delay = 1;
2309: if ((j_p = cJSON_GetObjectItem(j, "parallel")) != NULL)
2310: test->num_streams = j_p->valueint;
2311: if ((j_p = cJSON_GetObjectItem(j, "reverse")) != NULL)
2312: iperf_set_test_reverse(test, 1);
1.1.1.2 misho 2313: if ((j_p = cJSON_GetObjectItem(j, "bidirectional")) != NULL)
2314: iperf_set_test_bidirectional(test, 1);
1.1 misho 2315: if ((j_p = cJSON_GetObjectItem(j, "window")) != NULL)
2316: test->settings->socket_bufsize = j_p->valueint;
2317: if ((j_p = cJSON_GetObjectItem(j, "len")) != NULL)
2318: test->settings->blksize = j_p->valueint;
2319: if ((j_p = cJSON_GetObjectItem(j, "bandwidth")) != NULL)
2320: test->settings->rate = j_p->valueint;
1.1.1.2 misho 2321: if ((j_p = cJSON_GetObjectItem(j, "fqrate")) != NULL)
2322: test->settings->fqrate = j_p->valueint;
2323: if ((j_p = cJSON_GetObjectItem(j, "pacing_timer")) != NULL)
2324: test->settings->pacing_timer = j_p->valueint;
1.1 misho 2325: if ((j_p = cJSON_GetObjectItem(j, "burst")) != NULL)
2326: test->settings->burst = j_p->valueint;
2327: if ((j_p = cJSON_GetObjectItem(j, "TOS")) != NULL)
2328: test->settings->tos = j_p->valueint;
2329: if ((j_p = cJSON_GetObjectItem(j, "flowlabel")) != NULL)
2330: test->settings->flowlabel = j_p->valueint;
2331: if ((j_p = cJSON_GetObjectItem(j, "title")) != NULL)
2332: test->title = strdup(j_p->valuestring);
1.1.1.2 misho 2333: if ((j_p = cJSON_GetObjectItem(j, "extra_data")) != NULL)
2334: test->extra_data = strdup(j_p->valuestring);
1.1 misho 2335: if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL)
2336: test->congestion = strdup(j_p->valuestring);
1.1.1.2 misho 2337: if ((j_p = cJSON_GetObjectItem(j, "congestion_used")) != NULL)
2338: test->congestion_used = strdup(j_p->valuestring);
1.1 misho 2339: if ((j_p = cJSON_GetObjectItem(j, "get_server_output")) != NULL)
2340: iperf_set_test_get_server_output(test, 1);
2341: if ((j_p = cJSON_GetObjectItem(j, "udp_counters_64bit")) != NULL)
2342: iperf_set_test_udp_counters_64bit(test, 1);
1.1.1.2 misho 2343: if ((j_p = cJSON_GetObjectItem(j, "repeating_payload")) != NULL)
2344: test->repeating_payload = 1;
1.1.1.3 ! misho 2345: if ((j_p = cJSON_GetObjectItem(j, "zerocopy")) != NULL)
! 2346: test->zerocopy = j_p->valueint;
! 2347: #if defined(HAVE_DONT_FRAGMENT)
! 2348: if ((j_p = cJSON_GetObjectItem(j, "dont_fragment")) != NULL)
! 2349: test->settings->dont_fragment = j_p->valueint;
! 2350: #endif /* HAVE_DONT_FRAGMENT */
1.1.1.2 misho 2351: #if defined(HAVE_SSL)
2352: if ((j_p = cJSON_GetObjectItem(j, "authtoken")) != NULL)
2353: test->settings->authtoken = strdup(j_p->valuestring);
2354: #endif //HAVE_SSL
2355: if (test->mode && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
1.1 misho 2356: test->sender_has_retransmits = 1;
1.1.1.2 misho 2357: if (test->settings->rate)
2358: cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);
1.1 misho 2359: cJSON_Delete(j);
2360: }
2361: return r;
2362: }
2363:
2364: /*************************************************************/
2365:
2366: static int
2367: send_results(struct iperf_test *test)
2368: {
2369: int r = 0;
2370: cJSON *j;
2371: cJSON *j_streams;
2372: struct iperf_stream *sp;
2373: cJSON *j_stream;
2374: int sender_has_retransmits;
2375: iperf_size_t bytes_transferred;
2376: int retransmits;
1.1.1.2 misho 2377: struct iperf_time temp_time;
2378: double start_time, end_time;
1.1 misho 2379:
2380: j = cJSON_CreateObject();
2381: if (j == NULL) {
2382: i_errno = IEPACKAGERESULTS;
2383: r = -1;
2384: } else {
2385: cJSON_AddNumberToObject(j, "cpu_util_total", test->cpu_util[0]);
2386: cJSON_AddNumberToObject(j, "cpu_util_user", test->cpu_util[1]);
2387: cJSON_AddNumberToObject(j, "cpu_util_system", test->cpu_util[2]);
1.1.1.2 misho 2388: if ( test->mode == RECEIVER )
1.1 misho 2389: sender_has_retransmits = -1;
2390: else
2391: sender_has_retransmits = test->sender_has_retransmits;
2392: cJSON_AddNumberToObject(j, "sender_has_retransmits", sender_has_retransmits);
1.1.1.2 misho 2393: if ( test->congestion_used ) {
2394: cJSON_AddStringToObject(j, "congestion_used", test->congestion_used);
2395: }
1.1 misho 2396:
2397: /* If on the server and sending server output, then do this */
2398: if (test->role == 's' && test->get_server_output) {
2399: if (test->json_output) {
2400: /* Add JSON output */
2401: cJSON_AddItemReferenceToObject(j, "server_output_json", test->json_top);
2402: }
2403: else {
2404: /* Add textual output */
2405: size_t buflen = 0;
2406:
2407: /* Figure out how much room we need to hold the complete output string */
2408: struct iperf_textline *t;
2409: TAILQ_FOREACH(t, &(test->server_output_list), textlineentries) {
2410: buflen += strlen(t->line);
2411: }
2412:
2413: /* Allocate and build it up from the component lines */
2414: char *output = calloc(buflen + 1, 1);
2415: TAILQ_FOREACH(t, &(test->server_output_list), textlineentries) {
2416: strncat(output, t->line, buflen);
2417: buflen -= strlen(t->line);
2418: }
2419:
2420: cJSON_AddStringToObject(j, "server_output_text", output);
1.1.1.2 misho 2421: free(output);
1.1 misho 2422: }
2423: }
2424:
2425: j_streams = cJSON_CreateArray();
2426: if (j_streams == NULL) {
2427: i_errno = IEPACKAGERESULTS;
2428: r = -1;
2429: } else {
2430: cJSON_AddItemToObject(j, "streams", j_streams);
2431: SLIST_FOREACH(sp, &test->streams, streams) {
2432: j_stream = cJSON_CreateObject();
2433: if (j_stream == NULL) {
2434: i_errno = IEPACKAGERESULTS;
2435: r = -1;
2436: } else {
2437: cJSON_AddItemToArray(j_streams, j_stream);
1.1.1.2 misho 2438: bytes_transferred = sp->sender ? (sp->result->bytes_sent - sp->result->bytes_sent_omit) : sp->result->bytes_received;
2439: retransmits = (sp->sender && test->sender_has_retransmits) ? sp->result->stream_retrans : -1;
1.1 misho 2440: cJSON_AddNumberToObject(j_stream, "id", sp->id);
2441: cJSON_AddNumberToObject(j_stream, "bytes", bytes_transferred);
2442: cJSON_AddNumberToObject(j_stream, "retransmits", retransmits);
2443: cJSON_AddNumberToObject(j_stream, "jitter", sp->jitter);
2444: cJSON_AddNumberToObject(j_stream, "errors", sp->cnt_error);
1.1.1.3 ! misho 2445: cJSON_AddNumberToObject(j_stream, "omitted_errors", sp->omitted_cnt_error);
1.1 misho 2446: cJSON_AddNumberToObject(j_stream, "packets", sp->packet_count);
1.1.1.3 ! misho 2447: cJSON_AddNumberToObject(j_stream, "omitted_packets", sp->omitted_packet_count);
1.1.1.2 misho 2448:
2449: iperf_time_diff(&sp->result->start_time, &sp->result->start_time, &temp_time);
2450: start_time = iperf_time_in_secs(&temp_time);
2451: iperf_time_diff(&sp->result->start_time, &sp->result->end_time, &temp_time);
2452: end_time = iperf_time_in_secs(&temp_time);
2453: cJSON_AddNumberToObject(j_stream, "start_time", start_time);
2454: cJSON_AddNumberToObject(j_stream, "end_time", end_time);
2455:
1.1 misho 2456: }
2457: }
2458: if (r == 0 && test->debug) {
1.1.1.2 misho 2459: char *str = cJSON_Print(j);
2460: printf("send_results\n%s\n", str);
2461: cJSON_free(str);
1.1 misho 2462: }
2463: if (r == 0 && JSON_write(test->ctrl_sck, j) < 0) {
2464: i_errno = IESENDRESULTS;
2465: r = -1;
2466: }
2467: }
2468: cJSON_Delete(j);
2469: }
2470: return r;
2471: }
2472:
2473: /*************************************************************/
2474:
2475: static int
2476: get_results(struct iperf_test *test)
2477: {
2478: int r = 0;
2479: cJSON *j;
2480: cJSON *j_cpu_util_total;
2481: cJSON *j_cpu_util_user;
2482: cJSON *j_cpu_util_system;
1.1.1.2 misho 2483: cJSON *j_remote_congestion_used;
1.1 misho 2484: cJSON *j_sender_has_retransmits;
2485: int result_has_retransmits;
2486: cJSON *j_streams;
2487: int n, i;
2488: cJSON *j_stream;
2489: cJSON *j_id;
2490: cJSON *j_bytes;
2491: cJSON *j_retransmits;
2492: cJSON *j_jitter;
2493: cJSON *j_errors;
1.1.1.3 ! misho 2494: cJSON *j_omitted_errors;
1.1 misho 2495: cJSON *j_packets;
1.1.1.3 ! misho 2496: cJSON *j_omitted_packets;
1.1 misho 2497: cJSON *j_server_output;
1.1.1.2 misho 2498: cJSON *j_start_time, *j_end_time;
1.1.1.3 ! misho 2499: int sid;
! 2500: int64_t cerror, pcount, omitted_cerror, omitted_pcount;
1.1 misho 2501: double jitter;
2502: iperf_size_t bytes_transferred;
2503: int retransmits;
2504: struct iperf_stream *sp;
2505:
2506: j = JSON_read(test->ctrl_sck);
2507: if (j == NULL) {
2508: i_errno = IERECVRESULTS;
2509: r = -1;
2510: } else {
2511: j_cpu_util_total = cJSON_GetObjectItem(j, "cpu_util_total");
2512: j_cpu_util_user = cJSON_GetObjectItem(j, "cpu_util_user");
2513: j_cpu_util_system = cJSON_GetObjectItem(j, "cpu_util_system");
2514: j_sender_has_retransmits = cJSON_GetObjectItem(j, "sender_has_retransmits");
2515: if (j_cpu_util_total == NULL || j_cpu_util_user == NULL || j_cpu_util_system == NULL || j_sender_has_retransmits == NULL) {
2516: i_errno = IERECVRESULTS;
2517: r = -1;
2518: } else {
2519: if (test->debug) {
1.1.1.2 misho 2520: char *str = cJSON_Print(j);
2521: printf("get_results\n%s\n", str);
2522: cJSON_free(str);
1.1 misho 2523: }
2524:
2525: test->remote_cpu_util[0] = j_cpu_util_total->valuedouble;
2526: test->remote_cpu_util[1] = j_cpu_util_user->valuedouble;
2527: test->remote_cpu_util[2] = j_cpu_util_system->valuedouble;
2528: result_has_retransmits = j_sender_has_retransmits->valueint;
1.1.1.2 misho 2529: if ( test->mode == RECEIVER ) {
2530: test->sender_has_retransmits = result_has_retransmits;
2531: test->other_side_has_retransmits = 0;
2532: }
2533: else if ( test->mode == BIDIRECTIONAL )
2534: test->other_side_has_retransmits = result_has_retransmits;
2535:
1.1 misho 2536: j_streams = cJSON_GetObjectItem(j, "streams");
2537: if (j_streams == NULL) {
2538: i_errno = IERECVRESULTS;
2539: r = -1;
2540: } else {
2541: n = cJSON_GetArraySize(j_streams);
2542: for (i=0; i<n; ++i) {
2543: j_stream = cJSON_GetArrayItem(j_streams, i);
2544: if (j_stream == NULL) {
2545: i_errno = IERECVRESULTS;
2546: r = -1;
2547: } else {
2548: j_id = cJSON_GetObjectItem(j_stream, "id");
2549: j_bytes = cJSON_GetObjectItem(j_stream, "bytes");
2550: j_retransmits = cJSON_GetObjectItem(j_stream, "retransmits");
2551: j_jitter = cJSON_GetObjectItem(j_stream, "jitter");
2552: j_errors = cJSON_GetObjectItem(j_stream, "errors");
1.1.1.3 ! misho 2553: j_omitted_errors = cJSON_GetObjectItem(j_stream, "omitted_errors");
1.1 misho 2554: j_packets = cJSON_GetObjectItem(j_stream, "packets");
1.1.1.3 ! misho 2555: j_omitted_packets = cJSON_GetObjectItem(j_stream, "omitted_packets");
1.1.1.2 misho 2556: j_start_time = cJSON_GetObjectItem(j_stream, "start_time");
2557: j_end_time = cJSON_GetObjectItem(j_stream, "end_time");
1.1 misho 2558: if (j_id == NULL || j_bytes == NULL || j_retransmits == NULL || j_jitter == NULL || j_errors == NULL || j_packets == NULL) {
2559: i_errno = IERECVRESULTS;
2560: r = -1;
1.1.1.3 ! misho 2561: } else if ( (j_omitted_errors == NULL && j_omitted_packets != NULL) || (j_omitted_errors != NULL && j_omitted_packets == NULL) ) {
! 2562: /* For backward compatibility allow to not receive "omitted" statistcs */
! 2563: i_errno = IERECVRESULTS;
! 2564: r = -1;
1.1 misho 2565: } else {
2566: sid = j_id->valueint;
2567: bytes_transferred = j_bytes->valueint;
2568: retransmits = j_retransmits->valueint;
2569: jitter = j_jitter->valuedouble;
2570: cerror = j_errors->valueint;
2571: pcount = j_packets->valueint;
1.1.1.3 ! misho 2572: if (j_omitted_packets != NULL) {
! 2573: omitted_cerror = j_omitted_errors->valueint;
! 2574: omitted_pcount = j_omitted_packets->valueint;
! 2575: }
1.1 misho 2576: SLIST_FOREACH(sp, &test->streams, streams)
2577: if (sp->id == sid) break;
2578: if (sp == NULL) {
2579: i_errno = IESTREAMID;
2580: r = -1;
2581: } else {
1.1.1.2 misho 2582: if (sp->sender) {
1.1 misho 2583: sp->jitter = jitter;
2584: sp->cnt_error = cerror;
1.1.1.2 misho 2585: sp->peer_packet_count = pcount;
1.1 misho 2586: sp->result->bytes_received = bytes_transferred;
1.1.1.3 ! misho 2587: if (j_omitted_packets != NULL) {
! 2588: sp->omitted_cnt_error = omitted_cerror;
! 2589: sp->peer_omitted_packet_count = omitted_pcount;
! 2590: } else {
! 2591: sp->peer_omitted_packet_count = sp->omitted_packet_count;
! 2592: if (sp->peer_omitted_packet_count > 0) {
! 2593: /* -1 indicates unknown error count since it includes the omitted count */
! 2594: sp->omitted_cnt_error = (sp->cnt_error > 0) ? -1 : 0;
! 2595: } else {
! 2596: sp->omitted_cnt_error = sp->cnt_error;
! 2597: }
! 2598: }
1.1.1.2 misho 2599: /*
1.1.1.3 ! misho 2600: * We have to handle the possibility that
1.1.1.2 misho 2601: * start_time and end_time might not be
2602: * available; this is the case for older (pre-3.2)
2603: * servers.
2604: *
2605: * We need to have result structure members to hold
2606: * the both sides' start_time and end_time.
2607: */
2608: if (j_start_time && j_end_time) {
2609: sp->result->receiver_time = j_end_time->valuedouble - j_start_time->valuedouble;
2610: }
2611: else {
2612: sp->result->receiver_time = 0.0;
2613: }
1.1 misho 2614: } else {
1.1.1.2 misho 2615: sp->peer_packet_count = pcount;
1.1 misho 2616: sp->result->bytes_sent = bytes_transferred;
2617: sp->result->stream_retrans = retransmits;
1.1.1.3 ! misho 2618: if (j_omitted_packets != NULL) {
! 2619: sp->peer_omitted_packet_count = omitted_pcount;
! 2620: } else {
! 2621: sp->peer_omitted_packet_count = sp->peer_packet_count;
! 2622: }
1.1.1.2 misho 2623: if (j_start_time && j_end_time) {
2624: sp->result->sender_time = j_end_time->valuedouble - j_start_time->valuedouble;
2625: }
2626: else {
2627: sp->result->sender_time = 0.0;
2628: }
1.1 misho 2629: }
2630: }
2631: }
2632: }
2633: }
2634: /*
2635: * If we're the client and we're supposed to get remote results,
2636: * look them up and process accordingly.
2637: */
2638: if (test->role == 'c' && iperf_get_test_get_server_output(test)) {
2639: /* Look for JSON. If we find it, grab the object so it doesn't get deleted. */
2640: j_server_output = cJSON_DetachItemFromObject(j, "server_output_json");
2641: if (j_server_output != NULL) {
2642: test->json_server_output = j_server_output;
2643: }
2644: else {
2645: /* No JSON, look for textual output. Make a copy of the text for later. */
2646: j_server_output = cJSON_GetObjectItem(j, "server_output_text");
2647: if (j_server_output != NULL) {
2648: test->server_output_text = strdup(j_server_output->valuestring);
2649: }
2650: }
2651: }
2652: }
2653: }
1.1.1.2 misho 2654:
2655: j_remote_congestion_used = cJSON_GetObjectItem(j, "congestion_used");
2656: if (j_remote_congestion_used != NULL) {
2657: test->remote_congestion_used = strdup(j_remote_congestion_used->valuestring);
2658: }
2659:
1.1 misho 2660: cJSON_Delete(j);
2661: }
2662: return r;
2663: }
2664:
2665: /*************************************************************/
2666:
2667: static int
2668: JSON_write(int fd, cJSON *json)
2669: {
2670: uint32_t hsize, nsize;
2671: char *str;
2672: int r = 0;
2673:
2674: str = cJSON_PrintUnformatted(json);
2675: if (str == NULL)
2676: r = -1;
2677: else {
2678: hsize = strlen(str);
2679: nsize = htonl(hsize);
2680: if (Nwrite(fd, (char*) &nsize, sizeof(nsize), Ptcp) < 0)
2681: r = -1;
2682: else {
2683: if (Nwrite(fd, str, hsize, Ptcp) < 0)
2684: r = -1;
2685: }
1.1.1.2 misho 2686: cJSON_free(str);
1.1 misho 2687: }
2688: return r;
2689: }
2690:
2691: /*************************************************************/
2692:
2693: static cJSON *
2694: JSON_read(int fd)
2695: {
2696: uint32_t hsize, nsize;
1.1.1.3 ! misho 2697: size_t strsize;
1.1 misho 2698: char *str;
2699: cJSON *json = NULL;
2700: int rc;
2701:
2702: /*
2703: * Read a four-byte integer, which is the length of the JSON to follow.
2704: * Then read the JSON into a buffer and parse it. Return a parsed JSON
2705: * structure, NULL if there was an error.
2706: */
2707: if (Nread(fd, (char*) &nsize, sizeof(nsize), Ptcp) >= 0) {
2708: hsize = ntohl(nsize);
2709: /* Allocate a buffer to hold the JSON */
1.1.1.3 ! misho 2710: strsize = hsize + 1; /* +1 for trailing NULL */
! 2711: if (strsize) {
! 2712: str = (char *) calloc(sizeof(char), strsize);
1.1 misho 2713: if (str != NULL) {
2714: rc = Nread(fd, str, hsize, Ptcp);
2715: if (rc >= 0) {
2716: /*
2717: * We should be reading in the number of bytes corresponding to the
2718: * length in that 4-byte integer. If we don't the socket might have
2719: * prematurely closed. Only do the JSON parsing if we got the
2720: * correct number of bytes.
2721: */
2722: if (rc == hsize) {
2723: json = cJSON_Parse(str);
2724: }
2725: else {
2726: printf("WARNING: Size of data read does not correspond to offered length\n");
2727: }
2728: }
2729: }
2730: free(str);
1.1.1.3 ! misho 2731: }
! 2732: else {
! 2733: printf("WARNING: Data length overflow\n");
! 2734: }
1.1 misho 2735: }
2736: return json;
2737: }
2738:
2739: /*************************************************************/
2740: /**
2741: * add_to_interval_list -- adds new interval to the interval_list
2742: */
2743:
2744: void
2745: add_to_interval_list(struct iperf_stream_result * rp, struct iperf_interval_results * new)
2746: {
2747: struct iperf_interval_results *irp;
2748:
2749: irp = (struct iperf_interval_results *) malloc(sizeof(struct iperf_interval_results));
2750: memcpy(irp, new, sizeof(struct iperf_interval_results));
2751: TAILQ_INSERT_TAIL(&rp->interval_results, irp, irlistentries);
2752: }
2753:
2754:
2755: /************************************************************/
2756:
2757: /**
2758: * connect_msg -- displays connection message
2759: * denoting sender/receiver details
2760: *
2761: */
2762:
2763: void
2764: connect_msg(struct iperf_stream *sp)
2765: {
2766: char ipl[INET6_ADDRSTRLEN], ipr[INET6_ADDRSTRLEN];
2767: int lport, rport;
2768:
2769: if (getsockdomain(sp->socket) == AF_INET) {
2770: inet_ntop(AF_INET, (void *) &((struct sockaddr_in *) &sp->local_addr)->sin_addr, ipl, sizeof(ipl));
2771: mapped_v4_to_regular_v4(ipl);
2772: inet_ntop(AF_INET, (void *) &((struct sockaddr_in *) &sp->remote_addr)->sin_addr, ipr, sizeof(ipr));
2773: mapped_v4_to_regular_v4(ipr);
2774: lport = ntohs(((struct sockaddr_in *) &sp->local_addr)->sin_port);
2775: rport = ntohs(((struct sockaddr_in *) &sp->remote_addr)->sin_port);
2776: } else {
2777: inet_ntop(AF_INET6, (void *) &((struct sockaddr_in6 *) &sp->local_addr)->sin6_addr, ipl, sizeof(ipl));
2778: mapped_v4_to_regular_v4(ipl);
2779: inet_ntop(AF_INET6, (void *) &((struct sockaddr_in6 *) &sp->remote_addr)->sin6_addr, ipr, sizeof(ipr));
2780: mapped_v4_to_regular_v4(ipr);
2781: lport = ntohs(((struct sockaddr_in6 *) &sp->local_addr)->sin6_port);
2782: rport = ntohs(((struct sockaddr_in6 *) &sp->remote_addr)->sin6_port);
2783: }
2784:
2785: if (sp->test->json_output)
2786: cJSON_AddItemToArray(sp->test->json_connected, iperf_json_printf("socket: %d local_host: %s local_port: %d remote_host: %s remote_port: %d", (int64_t) sp->socket, ipl, (int64_t) lport, ipr, (int64_t) rport));
2787: else
1.1.1.2 misho 2788: iperf_printf(sp->test, report_connected, sp->socket, ipl, lport, ipr, rport);
1.1 misho 2789: }
2790:
2791:
2792: /**************************************************************************/
2793:
2794: struct iperf_test *
2795: iperf_new_test()
2796: {
2797: struct iperf_test *test;
2798:
2799: test = (struct iperf_test *) malloc(sizeof(struct iperf_test));
2800: if (!test) {
2801: i_errno = IENEWTEST;
2802: return NULL;
2803: }
2804: /* initialize everything to zero */
2805: memset(test, 0, sizeof(struct iperf_test));
2806:
2807: test->settings = (struct iperf_settings *) malloc(sizeof(struct iperf_settings));
2808: if (!test->settings) {
2809: free(test);
2810: i_errno = IENEWTEST;
2811: return NULL;
2812: }
2813: memset(test->settings, 0, sizeof(struct iperf_settings));
2814:
1.1.1.2 misho 2815: test->bitrate_limit_intervals_traffic_bytes = (iperf_size_t *) malloc(sizeof(iperf_size_t) * MAX_INTERVAL);
2816: if (!test->bitrate_limit_intervals_traffic_bytes) {
1.1.1.3 ! misho 2817: free(test->settings);
1.1.1.2 misho 2818: free(test);
2819: i_errno = IENEWTEST;
2820: return NULL;
2821: }
1.1.1.3 ! misho 2822: memset(test->bitrate_limit_intervals_traffic_bytes, 0, sizeof(sizeof(iperf_size_t) * MAX_INTERVAL));
1.1.1.2 misho 2823:
1.1 misho 2824: /* By default all output goes to stdout */
2825: test->outfile = stdout;
2826:
2827: return test;
2828: }
2829:
2830: /**************************************************************************/
2831:
2832: struct protocol *
2833: protocol_new(void)
2834: {
2835: struct protocol *proto;
2836:
2837: proto = malloc(sizeof(struct protocol));
2838: if(!proto) {
2839: return NULL;
2840: }
2841: memset(proto, 0, sizeof(struct protocol));
2842:
2843: return proto;
2844: }
2845:
2846: void
2847: protocol_free(struct protocol *proto)
2848: {
1.1.1.3 ! misho 2849: free(proto);
1.1 misho 2850: }
2851:
2852: /**************************************************************************/
2853: int
2854: iperf_defaults(struct iperf_test *testp)
2855: {
2856: struct protocol *tcp, *udp;
1.1.1.2 misho 2857: #if defined(HAVE_SCTP_H)
1.1 misho 2858: struct protocol *sctp;
1.1.1.2 misho 2859: #endif /* HAVE_SCTP_H */
1.1 misho 2860:
2861: testp->omit = OMIT;
2862: testp->duration = DURATION;
2863: testp->diskfile_name = (char*) 0;
2864: testp->affinity = -1;
2865: testp->server_affinity = -1;
2866: TAILQ_INIT(&testp->xbind_addrs);
2867: #if defined(HAVE_CPUSET_SETAFFINITY)
2868: CPU_ZERO(&testp->cpumask);
2869: #endif /* HAVE_CPUSET_SETAFFINITY */
2870: testp->title = NULL;
1.1.1.2 misho 2871: testp->extra_data = NULL;
1.1 misho 2872: testp->congestion = NULL;
1.1.1.2 misho 2873: testp->congestion_used = NULL;
2874: testp->remote_congestion_used = NULL;
1.1 misho 2875: testp->server_port = PORT;
2876: testp->ctrl_sck = -1;
1.1.1.3 ! misho 2877: testp->listener = -1;
1.1 misho 2878: testp->prot_listener = -1;
1.1.1.2 misho 2879: testp->other_side_has_retransmits = 0;
1.1 misho 2880:
2881: testp->stats_callback = iperf_stats_callback;
2882: testp->reporter_callback = iperf_reporter_callback;
2883:
2884: testp->stats_interval = testp->reporter_interval = 1;
2885: testp->num_streams = 1;
2886:
2887: testp->settings->domain = AF_UNSPEC;
2888: testp->settings->unit_format = 'a';
2889: testp->settings->socket_bufsize = 0; /* use autotuning */
2890: testp->settings->blksize = DEFAULT_TCP_BLKSIZE;
2891: testp->settings->rate = 0;
1.1.1.2 misho 2892: testp->settings->bitrate_limit = 0;
2893: testp->settings->bitrate_limit_interval = 5;
2894: testp->settings->bitrate_limit_stats_per_interval = 0;
2895: testp->settings->fqrate = 0;
1.1.1.3 ! misho 2896: testp->settings->pacing_timer = DEFAULT_PACING_TIMER;
1.1 misho 2897: testp->settings->burst = 0;
2898: testp->settings->mss = 0;
2899: testp->settings->bytes = 0;
2900: testp->settings->blocks = 0;
1.1.1.2 misho 2901: testp->settings->connect_timeout = -1;
1.1.1.3 ! misho 2902: testp->settings->rcv_timeout.secs = DEFAULT_NO_MSG_RCVD_TIMEOUT / SEC_TO_mS;
! 2903: testp->settings->rcv_timeout.usecs = (DEFAULT_NO_MSG_RCVD_TIMEOUT % SEC_TO_mS) * mS_TO_US;
! 2904: testp->zerocopy = 0;
! 2905:
1.1 misho 2906: memset(testp->cookie, 0, COOKIE_SIZE);
2907:
2908: testp->multisend = 10; /* arbitrary */
2909:
2910: /* Set up protocol list */
2911: SLIST_INIT(&testp->streams);
2912: SLIST_INIT(&testp->protocols);
2913:
2914: tcp = protocol_new();
2915: if (!tcp)
2916: return -1;
2917:
2918: tcp->id = Ptcp;
2919: tcp->name = "TCP";
2920: tcp->accept = iperf_tcp_accept;
2921: tcp->listen = iperf_tcp_listen;
2922: tcp->connect = iperf_tcp_connect;
2923: tcp->send = iperf_tcp_send;
2924: tcp->recv = iperf_tcp_recv;
2925: tcp->init = NULL;
2926: SLIST_INSERT_HEAD(&testp->protocols, tcp, protocols);
2927:
2928: udp = protocol_new();
2929: if (!udp) {
2930: protocol_free(tcp);
2931: return -1;
2932: }
2933:
2934: udp->id = Pudp;
2935: udp->name = "UDP";
2936: udp->accept = iperf_udp_accept;
2937: udp->listen = iperf_udp_listen;
2938: udp->connect = iperf_udp_connect;
2939: udp->send = iperf_udp_send;
2940: udp->recv = iperf_udp_recv;
2941: udp->init = iperf_udp_init;
2942: SLIST_INSERT_AFTER(tcp, udp, protocols);
2943:
2944: set_protocol(testp, Ptcp);
2945:
1.1.1.2 misho 2946: #if defined(HAVE_SCTP_H)
1.1 misho 2947: sctp = protocol_new();
2948: if (!sctp) {
2949: protocol_free(tcp);
2950: protocol_free(udp);
2951: return -1;
2952: }
2953:
2954: sctp->id = Psctp;
2955: sctp->name = "SCTP";
2956: sctp->accept = iperf_sctp_accept;
2957: sctp->listen = iperf_sctp_listen;
2958: sctp->connect = iperf_sctp_connect;
2959: sctp->send = iperf_sctp_send;
2960: sctp->recv = iperf_sctp_recv;
2961: sctp->init = iperf_sctp_init;
2962:
2963: SLIST_INSERT_AFTER(udp, sctp, protocols);
1.1.1.2 misho 2964: #endif /* HAVE_SCTP_H */
1.1 misho 2965:
2966: testp->on_new_stream = iperf_on_new_stream;
2967: testp->on_test_start = iperf_on_test_start;
2968: testp->on_connect = iperf_on_connect;
2969: testp->on_test_finish = iperf_on_test_finish;
2970:
2971: TAILQ_INIT(&testp->server_output_list);
2972:
2973: return 0;
2974: }
2975:
2976:
2977: /**************************************************************************/
2978: void
2979: iperf_free_test(struct iperf_test *test)
2980: {
2981: struct protocol *prot;
2982: struct iperf_stream *sp;
2983:
2984: /* Free streams */
2985: while (!SLIST_EMPTY(&test->streams)) {
2986: sp = SLIST_FIRST(&test->streams);
2987: SLIST_REMOVE_HEAD(&test->streams, streams);
2988: iperf_free_stream(sp);
2989: }
2990: if (test->server_hostname)
2991: free(test->server_hostname);
2992: if (test->tmp_template)
2993: free(test->tmp_template);
2994: if (test->bind_address)
2995: free(test->bind_address);
1.1.1.3 ! misho 2996: if (test->bind_dev)
! 2997: free(test->bind_dev);
1.1 misho 2998: if (!TAILQ_EMPTY(&test->xbind_addrs)) {
2999: struct xbind_entry *xbe;
3000:
3001: while (!TAILQ_EMPTY(&test->xbind_addrs)) {
3002: xbe = TAILQ_FIRST(&test->xbind_addrs);
3003: TAILQ_REMOVE(&test->xbind_addrs, xbe, link);
3004: if (xbe->ai)
3005: freeaddrinfo(xbe->ai);
3006: free(xbe->name);
3007: free(xbe);
3008: }
3009: }
1.1.1.2 misho 3010: #if defined(HAVE_SSL)
3011:
3012: if (test->server_rsa_private_key)
3013: EVP_PKEY_free(test->server_rsa_private_key);
3014: test->server_rsa_private_key = NULL;
3015:
3016: free(test->settings->authtoken);
3017: test->settings->authtoken = NULL;
3018:
3019: free(test->settings->client_username);
3020: test->settings->client_username = NULL;
3021:
3022: free(test->settings->client_password);
3023: test->settings->client_password = NULL;
3024:
3025: if (test->settings->client_rsa_pubkey)
3026: EVP_PKEY_free(test->settings->client_rsa_pubkey);
3027: test->settings->client_rsa_pubkey = NULL;
3028: #endif /* HAVE_SSL */
3029:
1.1 misho 3030: if (test->settings)
3031: free(test->settings);
3032: if (test->title)
3033: free(test->title);
1.1.1.2 misho 3034: if (test->extra_data)
3035: free(test->extra_data);
1.1 misho 3036: if (test->congestion)
3037: free(test->congestion);
1.1.1.2 misho 3038: if (test->congestion_used)
3039: free(test->congestion_used);
3040: if (test->remote_congestion_used)
3041: free(test->remote_congestion_used);
3042: if (test->timestamp_format)
3043: free(test->timestamp_format);
1.1 misho 3044: if (test->omit_timer != NULL)
3045: tmr_cancel(test->omit_timer);
3046: if (test->timer != NULL)
3047: tmr_cancel(test->timer);
3048: if (test->stats_timer != NULL)
3049: tmr_cancel(test->stats_timer);
3050: if (test->reporter_timer != NULL)
3051: tmr_cancel(test->reporter_timer);
3052:
3053: /* Free protocol list */
3054: while (!SLIST_EMPTY(&test->protocols)) {
3055: prot = SLIST_FIRST(&test->protocols);
1.1.1.3 ! misho 3056: SLIST_REMOVE_HEAD(&test->protocols, protocols);
1.1 misho 3057: free(prot);
3058: }
3059:
1.1.1.2 misho 3060: if (test->logfile) {
3061: free(test->logfile);
3062: test->logfile = NULL;
1.1.1.3 ! misho 3063: iperf_close_logfile(test);
1.1.1.2 misho 3064: }
3065:
1.1 misho 3066: if (test->server_output_text) {
3067: free(test->server_output_text);
3068: test->server_output_text = NULL;
3069: }
3070:
3071: if (test->json_output_string) {
3072: free(test->json_output_string);
3073: test->json_output_string = NULL;
3074: }
3075:
3076: /* Free output line buffers, if any (on the server only) */
3077: struct iperf_textline *t;
3078: while (!TAILQ_EMPTY(&test->server_output_list)) {
3079: t = TAILQ_FIRST(&test->server_output_list);
3080: TAILQ_REMOVE(&test->server_output_list, t, textlineentries);
3081: free(t->line);
3082: free(t);
3083: }
3084:
3085: /* sctp_bindx: do not free the arguments, only the resolver results */
3086: if (!TAILQ_EMPTY(&test->xbind_addrs)) {
3087: struct xbind_entry *xbe;
3088:
3089: TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
3090: if (xbe->ai) {
3091: freeaddrinfo(xbe->ai);
3092: xbe->ai = NULL;
3093: }
3094: }
3095: }
3096:
1.1.1.3 ! misho 3097: /* Free interval's traffic array for average rate calculations */
1.1.1.2 misho 3098: if (test->bitrate_limit_intervals_traffic_bytes != NULL)
3099: free(test->bitrate_limit_intervals_traffic_bytes);
3100:
1.1 misho 3101: /* XXX: Why are we setting these values to NULL? */
3102: // test->streams = NULL;
3103: test->stats_callback = NULL;
3104: test->reporter_callback = NULL;
3105: free(test);
3106: }
3107:
3108:
3109: void
3110: iperf_reset_test(struct iperf_test *test)
3111: {
3112: struct iperf_stream *sp;
1.1.1.2 misho 3113: int i;
1.1 misho 3114:
1.1.1.3 ! misho 3115: iperf_close_logfile(test);
! 3116:
1.1 misho 3117: /* Free streams */
3118: while (!SLIST_EMPTY(&test->streams)) {
3119: sp = SLIST_FIRST(&test->streams);
3120: SLIST_REMOVE_HEAD(&test->streams, streams);
3121: iperf_free_stream(sp);
3122: }
3123: if (test->omit_timer != NULL) {
3124: tmr_cancel(test->omit_timer);
3125: test->omit_timer = NULL;
3126: }
3127: if (test->timer != NULL) {
3128: tmr_cancel(test->timer);
3129: test->timer = NULL;
3130: }
3131: if (test->stats_timer != NULL) {
3132: tmr_cancel(test->stats_timer);
3133: test->stats_timer = NULL;
3134: }
3135: if (test->reporter_timer != NULL) {
3136: tmr_cancel(test->reporter_timer);
3137: test->reporter_timer = NULL;
3138: }
3139: test->done = 0;
3140:
3141: SLIST_INIT(&test->streams);
3142:
1.1.1.2 misho 3143: if (test->remote_congestion_used)
3144: free(test->remote_congestion_used);
3145: test->remote_congestion_used = NULL;
1.1 misho 3146: test->role = 's';
1.1.1.2 misho 3147: test->mode = RECEIVER;
1.1 misho 3148: test->sender_has_retransmits = 0;
3149: set_protocol(test, Ptcp);
3150: test->omit = OMIT;
3151: test->duration = DURATION;
3152: test->server_affinity = -1;
3153: #if defined(HAVE_CPUSET_SETAFFINITY)
3154: CPU_ZERO(&test->cpumask);
3155: #endif /* HAVE_CPUSET_SETAFFINITY */
3156: test->state = 0;
1.1.1.3 ! misho 3157:
1.1 misho 3158: test->ctrl_sck = -1;
1.1.1.3 ! misho 3159: test->listener = -1;
1.1 misho 3160: test->prot_listener = -1;
3161:
3162: test->bytes_sent = 0;
3163: test->blocks_sent = 0;
3164:
1.1.1.2 misho 3165: test->bytes_received = 0;
3166: test->blocks_received = 0;
3167:
3168: test->other_side_has_retransmits = 0;
3169:
3170: test->bitrate_limit_stats_count = 0;
3171: test->bitrate_limit_last_interval_index = 0;
3172: test->bitrate_limit_exceeded = 0;
3173:
3174: for (i = 0; i < MAX_INTERVAL; i++)
3175: test->bitrate_limit_intervals_traffic_bytes[i] = 0;
3176:
1.1 misho 3177: test->reverse = 0;
1.1.1.2 misho 3178: test->bidirectional = 0;
1.1 misho 3179: test->no_delay = 0;
3180:
3181: FD_ZERO(&test->read_set);
3182: FD_ZERO(&test->write_set);
1.1.1.3 ! misho 3183:
1.1 misho 3184: test->num_streams = 1;
3185: test->settings->socket_bufsize = 0;
3186: test->settings->blksize = DEFAULT_TCP_BLKSIZE;
3187: test->settings->rate = 0;
3188: test->settings->burst = 0;
3189: test->settings->mss = 0;
1.1.1.2 misho 3190: test->settings->tos = 0;
1.1.1.3 ! misho 3191: test->settings->dont_fragment = 0;
! 3192: test->zerocopy = 0;
1.1.1.2 misho 3193:
3194: #if defined(HAVE_SSL)
3195: if (test->settings->authtoken) {
3196: free(test->settings->authtoken);
3197: test->settings->authtoken = NULL;
3198: }
3199: if (test->settings->client_username) {
3200: free(test->settings->client_username);
3201: test->settings->client_username = NULL;
3202: }
3203: if (test->settings->client_password) {
3204: free(test->settings->client_password);
3205: test->settings->client_password = NULL;
3206: }
3207: if (test->settings->client_rsa_pubkey) {
3208: EVP_PKEY_free(test->settings->client_rsa_pubkey);
3209: test->settings->client_rsa_pubkey = NULL;
3210: }
3211: #endif /* HAVE_SSL */
3212:
1.1 misho 3213: memset(test->cookie, 0, COOKIE_SIZE);
3214: test->multisend = 10; /* arbitrary */
3215: test->udp_counters_64bit = 0;
1.1.1.2 misho 3216: if (test->title) {
3217: free(test->title);
3218: test->title = NULL;
3219: }
3220: if (test->extra_data) {
3221: free(test->extra_data);
3222: test->extra_data = NULL;
3223: }
1.1 misho 3224:
3225: /* Free output line buffers, if any (on the server only) */
3226: struct iperf_textline *t;
3227: while (!TAILQ_EMPTY(&test->server_output_list)) {
3228: t = TAILQ_FIRST(&test->server_output_list);
3229: TAILQ_REMOVE(&test->server_output_list, t, textlineentries);
3230: free(t->line);
3231: free(t);
3232: }
3233: }
3234:
3235:
3236: /* Reset all of a test's stats back to zero. Called when the omitting
3237: ** period is over.
3238: */
3239: void
3240: iperf_reset_stats(struct iperf_test *test)
3241: {
1.1.1.2 misho 3242: struct iperf_time now;
1.1 misho 3243: struct iperf_stream *sp;
3244: struct iperf_stream_result *rp;
3245:
3246: test->bytes_sent = 0;
3247: test->blocks_sent = 0;
1.1.1.2 misho 3248: iperf_time_now(&now);
1.1 misho 3249: SLIST_FOREACH(sp, &test->streams, streams) {
3250: sp->omitted_packet_count = sp->packet_count;
3251: sp->omitted_cnt_error = sp->cnt_error;
3252: sp->omitted_outoforder_packets = sp->outoforder_packets;
3253: sp->jitter = 0;
3254: rp = sp->result;
3255: rp->bytes_sent_omit = rp->bytes_sent;
3256: rp->bytes_received = 0;
3257: rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
1.1.1.2 misho 3258: if (test->sender_has_retransmits == 1) {
1.1 misho 3259: struct iperf_interval_results ir; /* temporary results structure */
3260: save_tcpinfo(sp, &ir);
3261: rp->stream_prev_total_retrans = get_total_retransmits(&ir);
3262: }
3263: rp->stream_retrans = 0;
3264: rp->start_time = now;
3265: }
3266: }
3267:
3268:
3269: /**************************************************************************/
3270:
3271: /**
3272: * Gather statistics during a test.
3273: * This function works for both the client and server side.
3274: */
3275: void
3276: iperf_stats_callback(struct iperf_test *test)
3277: {
3278: struct iperf_stream *sp;
3279: struct iperf_stream_result *rp = NULL;
3280: struct iperf_interval_results *irp, temp;
1.1.1.2 misho 3281: struct iperf_time temp_time;
3282: iperf_size_t total_interval_bytes_transferred = 0;
1.1 misho 3283:
3284: temp.omitted = test->omitting;
3285: SLIST_FOREACH(sp, &test->streams, streams) {
3286: rp = sp->result;
1.1.1.2 misho 3287: temp.bytes_transferred = sp->sender ? rp->bytes_sent_this_interval : rp->bytes_received_this_interval;
1.1 misho 3288:
1.1.1.2 misho 3289: // Total bytes transferred this interval
3290: total_interval_bytes_transferred += rp->bytes_sent_this_interval + rp->bytes_received_this_interval;
1.1.1.3 ! misho 3291:
1.1 misho 3292: irp = TAILQ_LAST(&rp->interval_results, irlisthead);
3293: /* result->end_time contains timestamp of previous interval */
3294: if ( irp != NULL ) /* not the 1st interval */
1.1.1.2 misho 3295: memcpy(&temp.interval_start_time, &rp->end_time, sizeof(struct iperf_time));
1.1 misho 3296: else /* or use timestamp from beginning */
1.1.1.2 misho 3297: memcpy(&temp.interval_start_time, &rp->start_time, sizeof(struct iperf_time));
1.1 misho 3298: /* now save time of end of this interval */
1.1.1.2 misho 3299: iperf_time_now(&rp->end_time);
3300: memcpy(&temp.interval_end_time, &rp->end_time, sizeof(struct iperf_time));
3301: iperf_time_diff(&temp.interval_start_time, &temp.interval_end_time, &temp_time);
3302: temp.interval_duration = iperf_time_in_secs(&temp_time);
1.1 misho 3303: if (test->protocol->id == Ptcp) {
3304: if ( has_tcpinfo()) {
3305: save_tcpinfo(sp, &temp);
1.1.1.2 misho 3306: if (test->sender_has_retransmits == 1) {
1.1 misho 3307: long total_retrans = get_total_retransmits(&temp);
3308: temp.interval_retrans = total_retrans - rp->stream_prev_total_retrans;
3309: rp->stream_retrans += temp.interval_retrans;
3310: rp->stream_prev_total_retrans = total_retrans;
3311:
3312: temp.snd_cwnd = get_snd_cwnd(&temp);
3313: if (temp.snd_cwnd > rp->stream_max_snd_cwnd) {
3314: rp->stream_max_snd_cwnd = temp.snd_cwnd;
3315: }
1.1.1.3 ! misho 3316:
! 3317: temp.snd_wnd = get_snd_wnd(&temp);
! 3318: if (temp.snd_wnd > rp->stream_max_snd_wnd) {
! 3319: rp->stream_max_snd_wnd = temp.snd_wnd;
! 3320: }
! 3321:
1.1 misho 3322: temp.rtt = get_rtt(&temp);
3323: if (temp.rtt > rp->stream_max_rtt) {
3324: rp->stream_max_rtt = temp.rtt;
3325: }
3326: if (rp->stream_min_rtt == 0 ||
3327: temp.rtt < rp->stream_min_rtt) {
3328: rp->stream_min_rtt = temp.rtt;
3329: }
3330: rp->stream_sum_rtt += temp.rtt;
3331: rp->stream_count_rtt++;
1.1.1.2 misho 3332:
3333: temp.rttvar = get_rttvar(&temp);
3334: temp.pmtu = get_pmtu(&temp);
1.1 misho 3335: }
3336: }
3337: } else {
3338: if (irp == NULL) {
3339: temp.interval_packet_count = sp->packet_count;
3340: temp.interval_outoforder_packets = sp->outoforder_packets;
3341: temp.interval_cnt_error = sp->cnt_error;
3342: } else {
3343: temp.interval_packet_count = sp->packet_count - irp->packet_count;
3344: temp.interval_outoforder_packets = sp->outoforder_packets - irp->outoforder_packets;
3345: temp.interval_cnt_error = sp->cnt_error - irp->cnt_error;
3346: }
3347: temp.packet_count = sp->packet_count;
3348: temp.jitter = sp->jitter;
3349: temp.outoforder_packets = sp->outoforder_packets;
3350: temp.cnt_error = sp->cnt_error;
3351: }
3352: add_to_interval_list(rp, &temp);
3353: rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
3354: }
1.1.1.2 misho 3355:
3356: /* Verify that total server's throughput is not above specified limit */
3357: if (test->role == 's') {
3358: iperf_check_total_rate(test, total_interval_bytes_transferred);
3359: }
1.1 misho 3360: }
3361:
3362: /**
3363: * Print intermediate results during a test (interval report).
3364: * Uses print_interval_results to print the results for each stream,
3365: * then prints an interval summary for all streams in this
3366: * interval.
3367: */
3368: static void
3369: iperf_print_intermediate(struct iperf_test *test)
3370: {
3371: struct iperf_stream *sp = NULL;
3372: struct iperf_interval_results *irp;
1.1.1.2 misho 3373: struct iperf_time temp_time;
1.1 misho 3374: cJSON *json_interval;
3375: cJSON *json_interval_streams;
1.1.1.2 misho 3376:
3377: int lower_mode, upper_mode;
3378: int current_mode;
3379:
3380: /*
3381: * Due to timing oddities, there can be cases, especially on the
3382: * server side, where at the end of a test there is a fairly short
3383: * interval with no data transferred. This could caused by
3384: * the control and data flows sharing the same path in the network,
3385: * and having the control messages for stopping the test being
3386: * queued behind the data packets.
3387: *
3388: * We'd like to try to omit that last interval when it happens, to
3389: * avoid cluttering data and output with useless stuff.
3390: * So we're going to try to ignore very short intervals (less than
3391: * 10% of the interval time) that have no data.
3392: */
3393: int interval_ok = 0;
3394: SLIST_FOREACH(sp, &test->streams, streams) {
3395: irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);
3396: if (irp) {
3397: iperf_time_diff(&irp->interval_start_time, &irp->interval_end_time, &temp_time);
3398: double interval_len = iperf_time_in_secs(&temp_time);
3399: if (test->debug) {
3400: printf("interval_len %f bytes_transferred %" PRIu64 "\n", interval_len, irp->bytes_transferred);
3401: }
3402:
3403: /*
3404: * If the interval is at least 10% the normal interval
1.1.1.3 ! misho 3405: * length, or if there were actual bytes transferred,
1.1.1.2 misho 3406: * then we want to keep this interval.
3407: */
3408: if (interval_len >= test->stats_interval * 0.10 ||
3409: irp->bytes_transferred > 0) {
3410: interval_ok = 1;
3411: if (test->debug) {
3412: printf("interval forces keep\n");
3413: }
3414: }
3415: }
3416: }
3417: if (!interval_ok) {
3418: if (test->debug) {
3419: printf("ignoring short interval with no data\n");
3420: }
3421: return;
3422: }
1.1 misho 3423:
3424: if (test->json_output) {
3425: json_interval = cJSON_CreateObject();
3426: if (json_interval == NULL)
3427: return;
3428: cJSON_AddItemToArray(test->json_intervals, json_interval);
3429: json_interval_streams = cJSON_CreateArray();
3430: if (json_interval_streams == NULL)
3431: return;
3432: cJSON_AddItemToObject(json_interval, "streams", json_interval_streams);
3433: } else {
3434: json_interval = NULL;
3435: json_interval_streams = NULL;
3436: }
3437:
1.1.1.2 misho 3438: /*
3439: * We must to sum streams separately.
3440: * For bidirectional mode we must to display
3441: * information about sender and receiver streams.
3442: * For client side we must handle sender streams
3443: * firstly and receiver streams for server side.
3444: * The following design allows us to do this.
3445: */
3446:
3447: if (test->mode == BIDIRECTIONAL) {
3448: if (test->role == 'c') {
3449: lower_mode = -1;
3450: upper_mode = 0;
3451: } else {
3452: lower_mode = 0;
3453: upper_mode = 1;
3454: }
3455: } else {
3456: lower_mode = test->mode;
3457: upper_mode = lower_mode;
1.1 misho 3458: }
3459:
3460:
1.1.1.2 misho 3461: for (current_mode = lower_mode; current_mode <= upper_mode; ++current_mode) {
3462: char ubuf[UNIT_LEN];
3463: char nbuf[UNIT_LEN];
3464: char mbuf[UNIT_LEN];
3465: char zbuf[] = " ";
1.1 misho 3466:
1.1.1.2 misho 3467: iperf_size_t bytes = 0;
3468: double bandwidth;
3469: int retransmits = 0;
3470: double start_time, end_time;
3471:
1.1.1.3 ! misho 3472: int64_t total_packets = 0, lost_packets = 0;
1.1.1.2 misho 3473: double avg_jitter = 0.0, lost_percent;
3474: int stream_must_be_sender = current_mode * current_mode;
3475:
1.1.1.3 ! misho 3476: char *sum_name;
! 3477:
1.1.1.2 misho 3478: /* Print stream role just for bidirectional mode. */
3479:
3480: if (test->mode == BIDIRECTIONAL) {
3481: sprintf(mbuf, "[%s-%s]", stream_must_be_sender?"TX":"RX", test->role == 'c'?"C":"S");
3482: } else {
3483: mbuf[0] = '\0';
3484: zbuf[0] = '\0';
3485: }
3486:
3487: SLIST_FOREACH(sp, &test->streams, streams) {
3488: if (sp->sender == stream_must_be_sender) {
3489: print_interval_results(test, sp, json_interval_streams);
3490: /* sum up all streams */
3491: irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);
3492: if (irp == NULL) {
3493: iperf_err(test,
3494: "iperf_print_intermediate error: interval_results is NULL");
3495: return;
3496: }
3497: bytes += irp->bytes_transferred;
3498: if (test->protocol->id == Ptcp) {
3499: if (test->sender_has_retransmits == 1) {
3500: retransmits += irp->interval_retrans;
3501: }
3502: } else {
3503: total_packets += irp->interval_packet_count;
3504: lost_packets += irp->interval_cnt_error;
3505: avg_jitter += irp->jitter;
3506: }
3507: }
3508: }
3509:
3510: /* next build string with sum of all streams */
3511: if (test->num_streams > 1 || test->json_output) {
1.1.1.3 ! misho 3512: /*
! 3513: * With BIDIR give a different JSON object name to the one sent/receive sums.
! 3514: * The different name is given to the data sent from the server, which is
! 3515: * the "reverse" channel. This makes sure that the name reported on the server
! 3516: * and client are compatible, and the names are the same as with non-bidir,
! 3517: * except for when reverse is used.
! 3518: */
! 3519: sum_name = "sum";
! 3520: if (test->mode == BIDIRECTIONAL) {
! 3521: if ((test->role == 'c' && !stream_must_be_sender) ||
! 3522: (test->role != 'c' && stream_must_be_sender))
! 3523: {
! 3524: sum_name = "sum_bidir_reverse";
! 3525: }
! 3526: }
! 3527:
1.1.1.2 misho 3528: sp = SLIST_FIRST(&test->streams); /* reset back to 1st stream */
3529: /* Only do this of course if there was a first stream */
3530: if (sp) {
3531: irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* use 1st stream for timing info */
3532:
3533: unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A');
3534: bandwidth = (double) bytes / (double) irp->interval_duration;
3535: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
3536:
3537: iperf_time_diff(&sp->result->start_time,&irp->interval_start_time, &temp_time);
3538: start_time = iperf_time_in_secs(&temp_time);
3539: iperf_time_diff(&sp->result->start_time,&irp->interval_end_time, &temp_time);
3540: end_time = iperf_time_in_secs(&temp_time);
3541: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
3542: if (test->sender_has_retransmits == 1 && stream_must_be_sender) {
3543: /* Interval sum, TCP with retransmits. */
3544: if (test->json_output)
1.1.1.3 ! misho 3545: cJSON_AddItemToObject(json_interval, sum_name, iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) retransmits, irp->omitted, stream_must_be_sender)); /* XXX irp->omitted or test->omitting? */
1.1.1.2 misho 3546: else
3547: iperf_printf(test, report_sum_bw_retrans_format, mbuf, start_time, end_time, ubuf, nbuf, retransmits, irp->omitted?report_omitted:""); /* XXX irp->omitted or test->omitting? */
3548: } else {
3549: /* Interval sum, TCP without retransmits. */
3550: if (test->json_output)
1.1.1.3 ! misho 3551: cJSON_AddItemToObject(json_interval, sum_name, iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, test->omitting, stream_must_be_sender));
1.1.1.2 misho 3552: else
3553: iperf_printf(test, report_sum_bw_format, mbuf, start_time, end_time, ubuf, nbuf, test->omitting?report_omitted:"");
3554: }
3555: } else {
3556: /* Interval sum, UDP. */
3557: if (stream_must_be_sender) {
3558: if (test->json_output)
1.1.1.3 ! misho 3559: cJSON_AddItemToObject(json_interval, sum_name, iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f packets: %d omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) total_packets, test->omitting, stream_must_be_sender));
1.1.1.2 misho 3560: else
3561: iperf_printf(test, report_sum_bw_udp_sender_format, mbuf, start_time, end_time, ubuf, nbuf, zbuf, total_packets, test->omitting?report_omitted:"");
3562: } else {
3563: avg_jitter /= test->num_streams;
3564: if (total_packets > 0) {
3565: lost_percent = 100.0 * lost_packets / total_packets;
3566: }
3567: else {
3568: lost_percent = 0.0;
3569: }
3570: if (test->json_output)
1.1.1.3 ! misho 3571: cJSON_AddItemToObject(json_interval, sum_name, iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f omitted: %b sender: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent, test->omitting, stream_must_be_sender));
1.1.1.2 misho 3572: else
3573: iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, end_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, total_packets, lost_percent, test->omitting?report_omitted:"");
3574: }
3575: }
3576: }
3577: }
1.1 misho 3578: }
3579: }
3580:
3581: /**
3582: * Print overall summary statistics at the end of a test.
3583: */
3584: static void
3585: iperf_print_results(struct iperf_test *test)
3586: {
3587:
3588: cJSON *json_summary_streams = NULL;
1.1.1.2 misho 3589:
3590: int lower_mode, upper_mode;
3591: int current_mode;
3592:
1.1.1.3 ! misho 3593: char *sum_sent_name, *sum_received_name, *sum_name;
! 3594:
1.1.1.2 misho 3595: int tmp_sender_has_retransmits = test->sender_has_retransmits;
1.1 misho 3596:
3597: /* print final summary for all intervals */
3598:
3599: if (test->json_output) {
3600: json_summary_streams = cJSON_CreateArray();
3601: if (json_summary_streams == NULL)
3602: return;
3603: cJSON_AddItemToObject(test->json_end, "streams", json_summary_streams);
3604: } else {
1.1.1.2 misho 3605: iperf_printf(test, "%s", report_bw_separator);
1.1 misho 3606: if (test->verbose)
1.1.1.2 misho 3607: iperf_printf(test, "%s", report_summary);
1.1 misho 3608: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
1.1.1.2 misho 3609: if (test->sender_has_retransmits || test->other_side_has_retransmits) {
3610: if (test->bidirectional)
3611: iperf_printf(test, "%s", report_bw_retrans_header_bidir);
3612: else
3613: iperf_printf(test, "%s", report_bw_retrans_header);
3614: }
3615: else {
3616: if (test->bidirectional)
3617: iperf_printf(test, "%s", report_bw_header_bidir);
3618: else
3619: iperf_printf(test, "%s", report_bw_header);
3620: }
3621: } else {
3622: if (test->bidirectional)
3623: iperf_printf(test, "%s", report_bw_udp_header_bidir);
1.1 misho 3624: else
1.1.1.2 misho 3625: iperf_printf(test, "%s", report_bw_udp_header);
3626: }
1.1 misho 3627: }
3628:
1.1.1.2 misho 3629: /*
3630: * We must to sum streams separately.
3631: * For bidirectional mode we must to display
3632: * information about sender and receiver streams.
3633: * For client side we must handle sender streams
3634: * firstly and receiver streams for server side.
3635: * The following design allows us to do this.
1.1 misho 3636: */
3637:
1.1.1.2 misho 3638: if (test->mode == BIDIRECTIONAL) {
3639: if (test->role == 'c') {
3640: lower_mode = -1;
3641: upper_mode = 0;
3642: } else {
3643: lower_mode = 0;
3644: upper_mode = 1;
1.1 misho 3645: }
1.1.1.2 misho 3646: } else {
3647: lower_mode = test->mode;
3648: upper_mode = lower_mode;
3649: }
1.1 misho 3650:
3651:
1.1.1.2 misho 3652: for (current_mode = lower_mode; current_mode <= upper_mode; ++current_mode) {
3653: cJSON *json_summary_stream = NULL;
1.1.1.3 ! misho 3654: int64_t total_retransmits = 0;
! 3655: int64_t total_packets = 0, lost_packets = 0;
! 3656: int64_t sender_packet_count = 0, receiver_packet_count = 0; /* for this stream, this interval */
! 3657: int64_t sender_omitted_packet_count = 0, receiver_omitted_packet_count = 0; /* for this stream, this interval */
! 3658: int64_t sender_total_packets = 0, receiver_total_packets = 0; /* running total */
1.1.1.2 misho 3659: char ubuf[UNIT_LEN];
3660: char nbuf[UNIT_LEN];
3661: struct stat sb;
3662: char sbuf[UNIT_LEN];
3663: struct iperf_stream *sp = NULL;
3664: iperf_size_t bytes_sent, total_sent = 0;
3665: iperf_size_t bytes_received, total_received = 0;
3666: double start_time, end_time = 0.0, avg_jitter = 0.0, lost_percent = 0.0;
3667: double sender_time = 0.0, receiver_time = 0.0;
1.1.1.3 ! misho 3668: struct iperf_time temp_time;
1.1.1.2 misho 3669: double bandwidth;
1.1 misho 3670:
1.1.1.2 misho 3671: char mbuf[UNIT_LEN];
3672: int stream_must_be_sender = current_mode * current_mode;
1.1 misho 3673:
1.1.1.2 misho 3674:
3675: /* Print stream role just for bidirectional mode. */
3676:
3677: if (test->mode == BIDIRECTIONAL) {
3678: sprintf(mbuf, "[%s-%s]", stream_must_be_sender?"TX":"RX", test->role == 'c'?"C":"S");
1.1 misho 3679: } else {
1.1.1.2 misho 3680: mbuf[0] = '\0';
1.1 misho 3681: }
3682:
1.1.1.2 misho 3683: /* Get sender_has_retransmits for each sender side (client and server) */
3684: if (test->mode == BIDIRECTIONAL && stream_must_be_sender)
3685: test->sender_has_retransmits = tmp_sender_has_retransmits;
3686: else if (test->mode == BIDIRECTIONAL && !stream_must_be_sender)
3687: test->sender_has_retransmits = test->other_side_has_retransmits;
1.1 misho 3688:
1.1.1.2 misho 3689: start_time = 0.;
3690: sp = SLIST_FIRST(&test->streams);
3691:
3692: /*
3693: * If there is at least one stream, then figure out the length of time
3694: * we were running the tests and print out some statistics about
3695: * the streams. It's possible to not have any streams at all
3696: * if the client got interrupted before it got to do anything.
3697: *
1.1.1.3 ! misho 3698: * Also note that we try to keep separate values for the sender
1.1.1.2 misho 3699: * and receiver ending times. Earlier iperf (3.1 and earlier)
3700: * servers didn't send that to the clients, so in this case we fall
3701: * back to using the client's ending timestamp. The fallback is
3702: * basically emulating what iperf 3.1 did.
3703: */
3704:
3705: if (sp) {
1.1.1.3 ! misho 3706: iperf_time_diff(&sp->result->start_time, &sp->result->end_time, &temp_time);
! 3707: end_time = iperf_time_in_secs(&temp_time);
1.1.1.2 misho 3708: if (sp->sender) {
3709: sp->result->sender_time = end_time;
3710: if (sp->result->receiver_time == 0.0) {
3711: sp->result->receiver_time = sp->result->sender_time;
3712: }
3713: }
3714: else {
3715: sp->result->receiver_time = end_time;
3716: if (sp->result->sender_time == 0.0) {
3717: sp->result->sender_time = sp->result->receiver_time;
3718: }
3719: }
3720: sender_time = sp->result->sender_time;
3721: receiver_time = sp->result->receiver_time;
3722: SLIST_FOREACH(sp, &test->streams, streams) {
3723: if (sp->sender == stream_must_be_sender) {
3724: if (test->json_output) {
3725: json_summary_stream = cJSON_CreateObject();
3726: if (json_summary_stream == NULL)
3727: return;
3728: cJSON_AddItemToArray(json_summary_streams, json_summary_stream);
3729: }
3730:
3731: bytes_sent = sp->result->bytes_sent - sp->result->bytes_sent_omit;
3732: bytes_received = sp->result->bytes_received;
3733: total_sent += bytes_sent;
3734: total_received += bytes_received;
3735:
3736: if (sp->sender) {
3737: sender_packet_count = sp->packet_count;
1.1.1.3 ! misho 3738: sender_omitted_packet_count = sp->omitted_packet_count;
1.1.1.2 misho 3739: receiver_packet_count = sp->peer_packet_count;
1.1.1.3 ! misho 3740: receiver_omitted_packet_count = sp->peer_omitted_packet_count;
1.1.1.2 misho 3741: }
3742: else {
3743: sender_packet_count = sp->peer_packet_count;
1.1.1.3 ! misho 3744: sender_omitted_packet_count = sp->peer_omitted_packet_count;
1.1.1.2 misho 3745: receiver_packet_count = sp->packet_count;
1.1.1.3 ! misho 3746: receiver_omitted_packet_count = sp->omitted_packet_count;
1.1.1.2 misho 3747: }
3748:
3749: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
3750: if (test->sender_has_retransmits) {
3751: total_retransmits += sp->result->stream_retrans;
3752: }
3753: } else {
3754: /*
3755: * Running total of the total number of packets. Use the sender packet count if we
3756: * have it, otherwise use the receiver packet count.
3757: */
1.1.1.3 ! misho 3758: int64_t packet_count = sender_packet_count ? sender_packet_count : receiver_packet_count;
1.1.1.2 misho 3759: total_packets += (packet_count - sp->omitted_packet_count);
1.1.1.3 ! misho 3760: sender_total_packets += (sender_packet_count - sender_omitted_packet_count);
! 3761: receiver_total_packets += (receiver_packet_count - receiver_omitted_packet_count);
! 3762: lost_packets += sp->cnt_error;
! 3763: if (sp->omitted_cnt_error > -1)
! 3764: lost_packets -= sp->omitted_cnt_error;
1.1.1.2 misho 3765: avg_jitter += sp->jitter;
3766: }
3767:
3768: unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A');
3769: if (sender_time > 0.0) {
3770: bandwidth = (double) bytes_sent / (double) sender_time;
3771: }
3772: else {
3773: bandwidth = 0.0;
3774: }
3775: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
3776: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
3777: if (test->sender_has_retransmits) {
3778: /* Sender summary, TCP and SCTP with retransmits. */
3779: if (test->json_output)
1.1.1.3 ! misho 3780: cJSON_AddItemToObject(json_summary_stream, report_sender, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d max_snd_cwnd: %d max_snd_wnd: %d max_rtt: %d min_rtt: %d mean_rtt: %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (int64_t) sp->result->stream_retrans, (int64_t) sp->result->stream_max_snd_cwnd, (int64_t) sp->result->stream_max_snd_wnd, (int64_t) sp->result->stream_max_rtt, (int64_t) sp->result->stream_min_rtt, (int64_t) ((sp->result->stream_count_rtt == 0) ? 0 : sp->result->stream_sum_rtt / sp->result->stream_count_rtt), stream_must_be_sender));
1.1.1.2 misho 3781: else
3782: if (test->role == 's' && !sp->sender) {
3783: if (test->verbose)
3784: iperf_printf(test, report_sender_not_available_format, sp->socket);
3785: }
3786: else {
3787: iperf_printf(test, report_bw_retrans_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, sp->result->stream_retrans, report_sender);
3788: }
3789: } else {
3790: /* Sender summary, TCP and SCTP without retransmits. */
3791: if (test->json_output)
1.1.1.3 ! misho 3792: cJSON_AddItemToObject(json_summary_stream, report_sender, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, stream_must_be_sender));
1.1.1.2 misho 3793: else
3794: if (test->role == 's' && !sp->sender) {
3795: if (test->verbose)
3796: iperf_printf(test, report_sender_not_available_format, sp->socket);
3797: }
3798: else {
3799: iperf_printf(test, report_bw_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, report_sender);
3800: }
3801: }
3802: } else {
3803: /* Sender summary, UDP. */
1.1.1.3 ! misho 3804: if (sender_packet_count - sender_omitted_packet_count > 0) {
! 3805: lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (sender_packet_count - sender_omitted_packet_count);
1.1.1.2 misho 3806: }
3807: else {
3808: lost_percent = 0.0;
3809: }
3810: if (test->json_output) {
3811: /*
1.1.1.3 ! misho 3812: * For historical reasons, we only emit one JSON
1.1.1.2 misho 3813: * object for the UDP summary, and it contains
3814: * information for both the sender and receiver
3815: * side.
3816: *
3817: * The JSON format as currently defined only includes one
3818: * value for the number of packets. We usually want that
3819: * to be the sender's value (how many packets were sent
3820: * by the sender). However this value might not be
3821: * available on the receiver in certain circumstances
3822: * specifically on the server side for a normal test or
3823: * the client side for a reverse-mode test. If this
3824: * is the case, then use the receiver's count of packets
3825: * instead.
3826: */
1.1.1.3 ! misho 3827: int64_t packet_count = sender_packet_count ? sender_packet_count : receiver_packet_count;
1.1.1.2 misho 3828: cJSON_AddItemToObject(json_summary_stream, "udp", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f out_of_order: %d sender: %b", (int64_t) sp->socket, (double) start_time, (double) sender_time, (double) sender_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets), stream_must_be_sender));
3829: }
3830: else {
3831: /*
3832: * Due to ordering of messages on the control channel,
3833: * the server cannot report on client-side summary
3834: * statistics. If we're the server, omit one set of
3835: * summary statistics to avoid giving meaningless
3836: * results.
3837: */
3838: if (test->role == 's' && !sp->sender) {
3839: if (test->verbose)
3840: iperf_printf(test, report_sender_not_available_format, sp->socket);
3841: }
3842: else {
1.1.1.3 ! misho 3843: iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, (int64_t) 0, (sender_packet_count - sender_omitted_packet_count), (double) 0, report_sender);
1.1.1.2 misho 3844: }
3845: if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0)
3846: iperf_printf(test, report_sum_outoforder, mbuf, start_time, sender_time, (sp->outoforder_packets - sp->omitted_outoforder_packets));
3847: }
3848: }
3849:
3850: if (sp->diskfile_fd >= 0) {
3851: if (fstat(sp->diskfile_fd, &sb) == 0) {
3852: /* In the odd case that it's a zero-sized file, say it was all transferred. */
3853: int percent_sent = 100, percent_received = 100;
3854: if (sb.st_size > 0) {
3855: percent_sent = (int) ( ( (double) bytes_sent / (double) sb.st_size ) * 100.0 );
3856: percent_received = (int) ( ( (double) bytes_received / (double) sb.st_size ) * 100.0 );
3857: }
3858: unit_snprintf(sbuf, UNIT_LEN, (double) sb.st_size, 'A');
3859: if (test->json_output)
3860: cJSON_AddItemToObject(json_summary_stream, "diskfile", iperf_json_printf("sent: %d received: %d size: %d percent_sent: %d percent_received: %d filename: %s", (int64_t) bytes_sent, (int64_t) bytes_received, (int64_t) sb.st_size, (int64_t) percent_sent, (int64_t) percent_received, test->diskfile_name));
3861: else
3862: if (stream_must_be_sender) {
3863: iperf_printf(test, report_diskfile, ubuf, sbuf, percent_sent, test->diskfile_name);
3864: }
3865: else {
3866: unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
3867: iperf_printf(test, report_diskfile, ubuf, sbuf, percent_received, test->diskfile_name);
3868: }
3869: }
3870: }
3871:
3872: unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
3873: if (receiver_time > 0) {
3874: bandwidth = (double) bytes_received / (double) receiver_time;
3875: }
3876: else {
3877: bandwidth = 0.0;
3878: }
3879: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
3880: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
3881: /* Receiver summary, TCP and SCTP */
3882: if (test->json_output)
1.1.1.3 ! misho 3883: cJSON_AddItemToObject(json_summary_stream, report_receiver, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", (int64_t) sp->socket, (double) start_time, (double) receiver_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8, stream_must_be_sender));
1.1.1.2 misho 3884: else
3885: if (test->role == 's' && sp->sender) {
3886: if (test->verbose)
3887: iperf_printf(test, report_receiver_not_available_format, sp->socket);
3888: }
3889: else {
3890: iperf_printf(test, report_bw_format, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver);
3891: }
3892: }
3893: else {
3894: /*
3895: * Receiver summary, UDP. Note that JSON was emitted with
3896: * the sender summary, so we only deal with human-readable
3897: * data here.
3898: */
3899: if (! test->json_output) {
1.1.1.3 ! misho 3900: if (receiver_packet_count - receiver_omitted_packet_count > 0 && sp->omitted_cnt_error > -1) {
! 3901: lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (receiver_packet_count - receiver_omitted_packet_count);
1.1.1.2 misho 3902: }
3903: else {
3904: lost_percent = 0.0;
3905: }
3906:
3907: if (test->role == 's' && sp->sender) {
3908: if (test->verbose)
3909: iperf_printf(test, report_receiver_not_available_format, sp->socket);
3910: }
3911: else {
1.1.1.3 ! misho 3912: if (sp->omitted_cnt_error > -1) {
! 3913: iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (receiver_packet_count - receiver_omitted_packet_count), lost_percent, report_receiver);
! 3914: } else {
! 3915: iperf_printf(test, report_bw_udp_format_no_omitted_error, sp->socket, mbuf, start_time, receiver_time, ubuf, nbuf, sp->jitter * 1000.0, (receiver_packet_count - receiver_omitted_packet_count), report_receiver);
! 3916: }
1.1.1.2 misho 3917: }
3918: }
3919: }
3920: }
3921: }
3922: }
3923:
3924: if (test->num_streams > 1 || test->json_output) {
1.1.1.3 ! misho 3925: /*
! 3926: * With BIDIR give a different JSON object name to the one sent/receive sums.
! 3927: * The different name is given to the data sent from the server, which is
! 3928: * the "reverse" channel. This makes sure that the name reported on the server
! 3929: * and client are compatible, and the names are the same as with non-bidir,
! 3930: * except for when reverse is used.
! 3931: */
! 3932: sum_name = "sum";
! 3933: sum_sent_name = "sum_sent";
! 3934: sum_received_name = "sum_received";
! 3935: if (test->mode == BIDIRECTIONAL) {
! 3936: if ((test->role == 'c' && !stream_must_be_sender) ||
! 3937: (test->role != 'c' && stream_must_be_sender))
! 3938: {
! 3939: sum_name = "sum_bidir_reverse";
! 3940: sum_sent_name = "sum_sent_bidir_reverse";
! 3941: sum_received_name = "sum_received_bidir_reverse";
! 3942: }
! 3943:
! 3944: }
! 3945:
1.1.1.2 misho 3946: unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
3947: /* If no tests were run, arbitrarily set bandwidth to 0. */
3948: if (sender_time > 0.0) {
3949: bandwidth = (double) total_sent / (double) sender_time;
3950: }
3951: else {
3952: bandwidth = 0.0;
3953: }
3954: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
3955: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
3956: if (test->sender_has_retransmits) {
3957: /* Summary sum, TCP with retransmits. */
3958: if (test->json_output)
1.1.1.3 ! misho 3959: cJSON_AddItemToObject(test->json_end, sum_sent_name, iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, bandwidth * 8, (int64_t) total_retransmits, stream_must_be_sender));
1.1.1.2 misho 3960: else
3961: if (test->role == 's' && !stream_must_be_sender) {
3962: if (test->verbose)
3963: iperf_printf(test, report_sender_not_available_summary_format, "SUM");
3964: }
3965: else {
3966: iperf_printf(test, report_sum_bw_retrans_format, mbuf, start_time, sender_time, ubuf, nbuf, total_retransmits, report_sender);
3967: }
3968: } else {
3969: /* Summary sum, TCP without retransmits. */
3970: if (test->json_output)
1.1.1.3 ! misho 3971: cJSON_AddItemToObject(test->json_end, sum_sent_name, iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, bandwidth * 8, stream_must_be_sender));
1.1.1.2 misho 3972: else
3973: if (test->role == 's' && !stream_must_be_sender) {
3974: if (test->verbose)
3975: iperf_printf(test, report_sender_not_available_summary_format, "SUM");
3976: }
3977: else {
3978: iperf_printf(test, report_sum_bw_format, mbuf, start_time, sender_time, ubuf, nbuf, report_sender);
3979: }
3980: }
3981: unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
3982: /* If no tests were run, set received bandwidth to 0 */
3983: if (receiver_time > 0.0) {
3984: bandwidth = (double) total_received / (double) receiver_time;
3985: }
3986: else {
3987: bandwidth = 0.0;
3988: }
3989: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
3990: if (test->json_output)
1.1.1.3 ! misho 3991: cJSON_AddItemToObject(test->json_end, sum_received_name, iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_received, bandwidth * 8, stream_must_be_sender));
1.1.1.2 misho 3992: else
3993: if (test->role == 's' && stream_must_be_sender) {
3994: if (test->verbose)
3995: iperf_printf(test, report_receiver_not_available_summary_format, "SUM");
3996: }
3997: else {
3998: iperf_printf(test, report_sum_bw_format, mbuf, start_time, receiver_time, ubuf, nbuf, report_receiver);
3999: }
4000: } else {
4001: /* Summary sum, UDP. */
4002: avg_jitter /= test->num_streams;
4003: /* If no packets were sent, arbitrarily set loss percentage to 0. */
4004: if (total_packets > 0) {
4005: lost_percent = 100.0 * lost_packets / total_packets;
4006: }
4007: else {
4008: lost_percent = 0.0;
4009: }
1.1.1.3 ! misho 4010: if (test->json_output) {
! 4011: /*
! 4012: * Original, summary structure. Using this
! 4013: * structure is not recommended due to
! 4014: * ambiguities between the sender and receiver.
! 4015: */
! 4016: cJSON_AddItemToObject(test->json_end, sum_name, iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_sent, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent, stream_must_be_sender));
! 4017: /*
! 4018: * Separate sum_sent and sum_received structures.
! 4019: * Using these structures to get the most complete
! 4020: * information about UDP transfer.
! 4021: */
! 4022: cJSON_AddItemToObject(test->json_end, sum_sent_name, iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f sender: %b", (double) start_time, (double) sender_time, (double) sender_time, (int64_t) total_sent, (double) total_sent * 8 / sender_time, (double) 0.0, (int64_t) 0, (int64_t) sender_total_packets, (double) 0.0, 1));
! 4023: cJSON_AddItemToObject(test->json_end, sum_received_name, iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f sender: %b", (double) start_time, (double) receiver_time, (double) receiver_time, (int64_t) total_received, (double) total_received * 8 / receiver_time, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) receiver_total_packets, (double) lost_percent, 0));
! 4024: } else {
1.1.1.2 misho 4025: /*
4026: * On the client we have both sender and receiver overall summary
4027: * stats. On the server we have only the side that was on the
4028: * server. Output whatever we have.
4029: */
4030: if (! (test->role == 's' && !stream_must_be_sender) ) {
4031: unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
1.1.1.3 ! misho 4032: iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, sender_time, ubuf, nbuf, 0.0, (int64_t) 0, sender_total_packets, 0.0, report_sender);
1.1.1.2 misho 4033: }
4034: if (! (test->role == 's' && stream_must_be_sender) ) {
4035:
4036: unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
4037: /* Compute received bandwidth. */
4038: if (end_time > 0.0) {
4039: bandwidth = (double) total_received / (double) receiver_time;
4040: }
4041: else {
4042: bandwidth = 0.0;
4043: }
4044: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
1.1.1.3 ! misho 4045: iperf_printf(test, report_sum_bw_udp_format, mbuf, start_time, receiver_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, receiver_total_packets, lost_percent, report_receiver);
1.1.1.2 misho 4046: }
4047: }
4048: }
4049: }
4050:
4051: if (test->json_output && current_mode == upper_mode) {
4052: cJSON_AddItemToObject(test->json_end, "cpu_utilization_percent", iperf_json_printf("host_total: %f host_user: %f host_system: %f remote_total: %f remote_user: %f remote_system: %f", (double) test->cpu_util[0], (double) test->cpu_util[1], (double) test->cpu_util[2], (double) test->remote_cpu_util[0], (double) test->remote_cpu_util[1], (double) test->remote_cpu_util[2]));
4053: if (test->protocol->id == Ptcp) {
4054: char *snd_congestion = NULL, *rcv_congestion = NULL;
4055: if (stream_must_be_sender) {
4056: snd_congestion = test->congestion_used;
4057: rcv_congestion = test->remote_congestion_used;
4058: }
4059: else {
4060: snd_congestion = test->remote_congestion_used;
4061: rcv_congestion = test->congestion_used;
4062: }
4063: if (snd_congestion) {
4064: cJSON_AddStringToObject(test->json_end, "sender_tcp_congestion", snd_congestion);
4065: }
4066: if (rcv_congestion) {
4067: cJSON_AddStringToObject(test->json_end, "receiver_tcp_congestion", rcv_congestion);
4068: }
4069: }
4070: }
4071: else {
4072: if (test->verbose) {
4073: if (stream_must_be_sender) {
4074: if (test->bidirectional) {
4075: iperf_printf(test, report_cpu, report_local, stream_must_be_sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, stream_must_be_sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
4076: iperf_printf(test, report_cpu, report_local, !stream_must_be_sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, !stream_must_be_sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
4077: } else
4078: iperf_printf(test, report_cpu, report_local, stream_must_be_sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, stream_must_be_sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
4079: }
4080: if (test->protocol->id == Ptcp) {
4081: char *snd_congestion = NULL, *rcv_congestion = NULL;
4082: if (stream_must_be_sender) {
4083: snd_congestion = test->congestion_used;
4084: rcv_congestion = test->remote_congestion_used;
4085: }
4086: else {
4087: snd_congestion = test->remote_congestion_used;
4088: rcv_congestion = test->congestion_used;
4089: }
4090: if (snd_congestion) {
4091: iperf_printf(test, "snd_tcp_congestion %s\n", snd_congestion);
4092: }
4093: if (rcv_congestion) {
4094: iperf_printf(test, "rcv_tcp_congestion %s\n", rcv_congestion);
4095: }
4096: }
4097: }
4098:
4099: /* Print server output if we're on the client and it was requested/provided */
4100: if (test->role == 'c' && iperf_get_test_get_server_output(test) && !test->json_output) {
4101: if (test->json_server_output) {
4102: char *str = cJSON_Print(test->json_server_output);
4103: iperf_printf(test, "\nServer JSON output:\n%s\n", str);
4104: cJSON_free(str);
4105: cJSON_Delete(test->json_server_output);
4106: test->json_server_output = NULL;
4107: }
4108: if (test->server_output_text) {
4109: iperf_printf(test, "\nServer output:\n%s\n", test->server_output_text);
4110: test->server_output_text = NULL;
4111: }
4112: }
4113: }
1.1 misho 4114: }
1.1.1.2 misho 4115:
4116: /* Set real sender_has_retransmits for current side */
4117: if (test->mode == BIDIRECTIONAL)
4118: test->sender_has_retransmits = tmp_sender_has_retransmits;
1.1 misho 4119: }
4120:
4121: /**************************************************************************/
4122:
4123: /**
4124: * Main report-printing callback.
1.1.1.3 ! misho 4125: * Prints results either during a test (interval report only) or
! 4126: * after the entire test has been run (last interval report plus
1.1 misho 4127: * overall summary).
4128: */
4129: void
4130: iperf_reporter_callback(struct iperf_test *test)
4131: {
4132: switch (test->state) {
4133: case TEST_RUNNING:
4134: case STREAM_RUNNING:
4135: /* print interval results for each stream */
4136: iperf_print_intermediate(test);
4137: break;
4138: case TEST_END:
4139: case DISPLAY_RESULTS:
4140: iperf_print_intermediate(test);
4141: iperf_print_results(test);
4142: break;
1.1.1.3 ! misho 4143: }
1.1 misho 4144:
4145: }
4146:
4147: /**
4148: * Print the interval results for one stream.
4149: * This function needs to know about the overall test so it can determine the
4150: * context for printing headers, separators, etc.
4151: */
4152: static void
4153: print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *json_interval_streams)
4154: {
4155: char ubuf[UNIT_LEN];
4156: char nbuf[UNIT_LEN];
4157: char cbuf[UNIT_LEN];
1.1.1.2 misho 4158: char mbuf[UNIT_LEN];
4159: char zbuf[] = " ";
1.1 misho 4160: double st = 0., et = 0.;
1.1.1.2 misho 4161: struct iperf_time temp_time;
1.1 misho 4162: struct iperf_interval_results *irp = NULL;
4163: double bandwidth, lost_percent;
4164:
1.1.1.2 misho 4165: if (test->mode == BIDIRECTIONAL) {
4166: sprintf(mbuf, "[%s-%s]", sp->sender?"TX":"RX", test->role == 'c'?"C":"S");
4167: } else {
4168: mbuf[0] = '\0';
4169: zbuf[0] = '\0';
4170: }
4171:
1.1 misho 4172: irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* get last entry in linked list */
4173: if (irp == NULL) {
4174: iperf_err(test, "print_interval_results error: interval_results is NULL");
4175: return;
4176: }
4177: if (!test->json_output) {
4178: /* First stream? */
4179: if (sp == SLIST_FIRST(&test->streams)) {
4180: /* It it's the first interval, print the header;
4181: ** else if there's more than one stream, print the separator;
4182: ** else nothing.
4183: */
1.1.1.2 misho 4184: if (iperf_time_compare(&sp->result->start_time, &irp->interval_start_time) == 0) {
1.1 misho 4185: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
1.1.1.2 misho 4186: if (test->sender_has_retransmits == 1) {
4187: if (test->bidirectional)
4188: iperf_printf(test, "%s", report_bw_retrans_cwnd_header_bidir);
4189: else
4190: iperf_printf(test, "%s", report_bw_retrans_cwnd_header);
4191: }
4192: else {
4193: if (test->bidirectional)
4194: iperf_printf(test, "%s", report_bw_header_bidir);
4195: else
4196: iperf_printf(test, "%s", report_bw_header);
4197: }
1.1 misho 4198: } else {
1.1.1.2 misho 4199: if (test->mode == SENDER) {
4200: iperf_printf(test, "%s", report_bw_udp_sender_header);
4201: } else if (test->mode == RECEIVER){
4202: iperf_printf(test, "%s", report_bw_udp_header);
4203: } else {
4204: /* BIDIRECTIONAL */
4205: iperf_printf(test, "%s", report_bw_udp_header_bidir);
4206: }
1.1 misho 4207: }
4208: } else if (test->num_streams > 1)
1.1.1.2 misho 4209: iperf_printf(test, "%s", report_bw_separator);
1.1 misho 4210: }
4211: }
4212:
4213: unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A');
1.1.1.2 misho 4214: if (irp->interval_duration > 0.0) {
4215: bandwidth = (double) irp->bytes_transferred / (double) irp->interval_duration;
4216: }
4217: else {
4218: bandwidth = 0.0;
4219: }
1.1 misho 4220: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
1.1.1.3 ! misho 4221:
1.1.1.2 misho 4222: iperf_time_diff(&sp->result->start_time, &irp->interval_start_time, &temp_time);
4223: st = iperf_time_in_secs(&temp_time);
4224: iperf_time_diff(&sp->result->start_time, &irp->interval_end_time, &temp_time);
4225: et = iperf_time_in_secs(&temp_time);
1.1.1.3 ! misho 4226:
1.1 misho 4227: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
1.1.1.2 misho 4228: if (test->sender_has_retransmits == 1 && sp->sender) {
1.1 misho 4229: /* Interval, TCP with retransmits. */
4230: if (test->json_output)
1.1.1.3 ! misho 4231: cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d snd_cwnd: %d snd_wnd: %d rtt: %d rttvar: %d pmtu: %d omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_retrans, (int64_t) irp->snd_cwnd, (int64_t) irp->snd_wnd, (int64_t) irp->rtt, (int64_t) irp->rttvar, (int64_t) irp->pmtu, irp->omitted, sp->sender));
1.1 misho 4232: else {
4233: unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A');
1.1.1.2 misho 4234: iperf_printf(test, report_bw_retrans_cwnd_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:"");
1.1 misho 4235: }
4236: } else {
4237: /* Interval, TCP without retransmits. */
4238: if (test->json_output)
1.1.1.2 misho 4239: cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, irp->omitted, sp->sender));
1.1 misho 4240: else
1.1.1.2 misho 4241: iperf_printf(test, report_bw_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->omitted?report_omitted:"");
1.1 misho 4242: }
4243: } else {
4244: /* Interval, UDP. */
1.1.1.2 misho 4245: if (sp->sender) {
1.1 misho 4246: if (test->json_output)
1.1.1.2 misho 4247: cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f packets: %d omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (int64_t) irp->interval_packet_count, irp->omitted, sp->sender));
1.1 misho 4248: else
1.1.1.2 misho 4249: iperf_printf(test, report_bw_udp_sender_format, sp->socket, mbuf, st, et, ubuf, nbuf, zbuf, irp->interval_packet_count, irp->omitted?report_omitted:"");
1.1 misho 4250: } else {
4251: if (irp->interval_packet_count > 0) {
4252: lost_percent = 100.0 * irp->interval_cnt_error / irp->interval_packet_count;
4253: }
4254: else {
4255: lost_percent = 0.0;
4256: }
4257: if (test->json_output)
1.1.1.2 misho 4258: cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f jitter_ms: %f lost_packets: %d packets: %d lost_percent: %f omitted: %b sender: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, (double) irp->jitter * 1000.0, (int64_t) irp->interval_cnt_error, (int64_t) irp->interval_packet_count, (double) lost_percent, irp->omitted, sp->sender));
1.1 misho 4259: else
1.1.1.2 misho 4260: iperf_printf(test, report_bw_udp_format, sp->socket, mbuf, st, et, ubuf, nbuf, irp->jitter * 1000.0, irp->interval_cnt_error, irp->interval_packet_count, lost_percent, irp->omitted?report_omitted:"");
1.1 misho 4261: }
4262: }
4263:
1.1.1.2 misho 4264: if (test->logfile || test->forceflush)
1.1 misho 4265: iflush(test);
4266: }
4267:
4268: /**************************************************************************/
4269: void
4270: iperf_free_stream(struct iperf_stream *sp)
4271: {
4272: struct iperf_interval_results *irp, *nirp;
4273:
4274: /* XXX: need to free interval list too! */
4275: munmap(sp->buffer, sp->test->settings->blksize);
4276: close(sp->buffer_fd);
4277: if (sp->diskfile_fd >= 0)
4278: close(sp->diskfile_fd);
4279: for (irp = TAILQ_FIRST(&sp->result->interval_results); irp != NULL; irp = nirp) {
4280: nirp = TAILQ_NEXT(irp, irlistentries);
4281: free(irp);
4282: }
4283: free(sp->result);
4284: if (sp->send_timer != NULL)
4285: tmr_cancel(sp->send_timer);
4286: free(sp);
4287: }
4288:
4289: /**************************************************************************/
4290: struct iperf_stream *
1.1.1.2 misho 4291: iperf_new_stream(struct iperf_test *test, int s, int sender)
1.1 misho 4292: {
4293: struct iperf_stream *sp;
1.1.1.2 misho 4294: int ret = 0;
4295:
1.1 misho 4296: char template[1024];
4297: if (test->tmp_template) {
4298: snprintf(template, sizeof(template) / sizeof(char), "%s", test->tmp_template);
4299: } else {
1.1.1.2 misho 4300: //find the system temporary dir *unix, windows, cygwin support
4301: char* tempdir = getenv("TMPDIR");
4302: if (tempdir == 0){
4303: tempdir = getenv("TEMP");
4304: }
4305: if (tempdir == 0){
4306: tempdir = getenv("TMP");
4307: }
4308: if (tempdir == 0){
1.1.1.3 ! misho 4309: #if defined(__ANDROID__)
! 4310: tempdir = "/data/local/tmp";
! 4311: #else
1.1.1.2 misho 4312: tempdir = "/tmp";
1.1.1.3 ! misho 4313: #endif
1.1.1.2 misho 4314: }
4315: snprintf(template, sizeof(template) / sizeof(char), "%s/iperf3.XXXXXX", tempdir);
1.1 misho 4316: }
4317:
4318: sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream));
4319: if (!sp) {
4320: i_errno = IECREATESTREAM;
4321: return NULL;
4322: }
4323:
4324: memset(sp, 0, sizeof(struct iperf_stream));
4325:
1.1.1.2 misho 4326: sp->sender = sender;
1.1 misho 4327: sp->test = test;
4328: sp->settings = test->settings;
4329: sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result));
4330: if (!sp->result) {
4331: free(sp);
4332: i_errno = IECREATESTREAM;
4333: return NULL;
4334: }
4335:
4336: memset(sp->result, 0, sizeof(struct iperf_stream_result));
4337: TAILQ_INIT(&sp->result->interval_results);
1.1.1.3 ! misho 4338:
1.1 misho 4339: /* Create and randomize the buffer */
4340: sp->buffer_fd = mkstemp(template);
4341: if (sp->buffer_fd == -1) {
4342: i_errno = IECREATESTREAM;
4343: free(sp->result);
4344: free(sp);
4345: return NULL;
4346: }
4347: if (unlink(template) < 0) {
4348: i_errno = IECREATESTREAM;
4349: free(sp->result);
4350: free(sp);
4351: return NULL;
4352: }
4353: if (ftruncate(sp->buffer_fd, test->settings->blksize) < 0) {
4354: i_errno = IECREATESTREAM;
4355: free(sp->result);
4356: free(sp);
4357: return NULL;
4358: }
4359: sp->buffer = (char *) mmap(NULL, test->settings->blksize, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0);
4360: if (sp->buffer == MAP_FAILED) {
4361: i_errno = IECREATESTREAM;
4362: free(sp->result);
4363: free(sp);
4364: return NULL;
4365: }
1.1.1.3 ! misho 4366: sp->pending_size = 0;
1.1 misho 4367:
4368: /* Set socket */
4369: sp->socket = s;
4370:
4371: sp->snd = test->protocol->send;
4372: sp->rcv = test->protocol->recv;
4373:
4374: if (test->diskfile_name != (char*) 0) {
1.1.1.2 misho 4375: sp->diskfile_fd = open(test->diskfile_name, sender ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), S_IRUSR|S_IWUSR);
1.1 misho 4376: if (sp->diskfile_fd == -1) {
4377: i_errno = IEFILE;
4378: munmap(sp->buffer, sp->test->settings->blksize);
4379: free(sp->result);
4380: free(sp);
4381: return NULL;
4382: }
4383: sp->snd2 = sp->snd;
4384: sp->snd = diskfile_send;
4385: sp->rcv2 = sp->rcv;
4386: sp->rcv = diskfile_recv;
4387: } else
4388: sp->diskfile_fd = -1;
4389:
4390: /* Initialize stream */
1.1.1.2 misho 4391: if (test->repeating_payload)
4392: fill_with_repeating_pattern(sp->buffer, test->settings->blksize);
4393: else
4394: ret = readentropy(sp->buffer, test->settings->blksize);
4395:
4396: if ((ret < 0) || (iperf_init_stream(sp, test) < 0)) {
1.1 misho 4397: close(sp->buffer_fd);
4398: munmap(sp->buffer, sp->test->settings->blksize);
4399: free(sp->result);
4400: free(sp);
4401: return NULL;
4402: }
4403: iperf_add_stream(test, sp);
4404:
4405: return sp;
4406: }
4407:
4408: /**************************************************************************/
4409: int
1.1.1.3 ! misho 4410: iperf_common_sockopts(struct iperf_test *test, int s)
1.1 misho 4411: {
4412: int opt;
4413:
4414: /* Set IP TOS */
4415: if ((opt = test->settings->tos)) {
1.1.1.3 ! misho 4416: if (getsockdomain(s) == AF_INET6) {
1.1 misho 4417: #ifdef IPV6_TCLASS
1.1.1.3 ! misho 4418: if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) {
1.1 misho 4419: i_errno = IESETCOS;
4420: return -1;
4421: }
1.1.1.3 ! misho 4422:
! 4423: /* if the control connection was established with a mapped v4 address
! 4424: then set IP_TOS on v6 stream socket as well */
! 4425: if (iperf_get_mapped_v4(test)) {
! 4426: if (setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {
! 4427: /* ignore any failure of v4 TOS in IPv6 case */
! 4428: }
! 4429: }
1.1 misho 4430: #else
4431: i_errno = IESETCOS;
4432: return -1;
4433: #endif
4434: } else {
1.1.1.3 ! misho 4435: if (setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {
1.1 misho 4436: i_errno = IESETTOS;
4437: return -1;
4438: }
4439: }
4440: }
1.1.1.3 ! misho 4441: return 0;
! 4442: }
! 4443:
! 4444: /**************************************************************************/
! 4445: int
! 4446: iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
! 4447: {
! 4448: int opt;
! 4449: socklen_t len;
! 4450:
! 4451: len = sizeof(struct sockaddr_storage);
! 4452: if (getsockname(sp->socket, (struct sockaddr *) &sp->local_addr, &len) < 0) {
! 4453: i_errno = IEINITSTREAM;
! 4454: return -1;
! 4455: }
! 4456: len = sizeof(struct sockaddr_storage);
! 4457: if (getpeername(sp->socket, (struct sockaddr *) &sp->remote_addr, &len) < 0) {
! 4458: i_errno = IEINITSTREAM;
! 4459: return -1;
! 4460: }
! 4461:
! 4462: #if defined(HAVE_DONT_FRAGMENT)
! 4463: /* Set Don't Fragment (DF). Only applicable to IPv4/UDP tests. */
! 4464: if (iperf_get_test_protocol_id(test) == Pudp &&
! 4465: getsockdomain(sp->socket) == AF_INET &&
! 4466: iperf_get_dont_fragment(test)) {
! 4467:
! 4468: /*
! 4469: * There are multiple implementations of this feature depending on the OS.
! 4470: * We need to handle separately Linux, UNIX, and Windows, as well as
! 4471: * the case that DF isn't supported at all (such as on macOS).
! 4472: */
! 4473: #if defined(IP_MTU_DISCOVER) /* Linux version of IP_DONTFRAG */
! 4474: opt = IP_PMTUDISC_DO;
! 4475: if (setsockopt(sp->socket, IPPROTO_IP, IP_MTU_DISCOVER, &opt, sizeof(opt)) < 0) {
! 4476: i_errno = IESETDONTFRAGMENT;
! 4477: return -1;
! 4478: }
! 4479: #else
! 4480: #if defined(IP_DONTFRAG) /* UNIX does IP_DONTFRAG */
! 4481: opt = 1;
! 4482: if (setsockopt(sp->socket, IPPROTO_IP, IP_DONTFRAG, &opt, sizeof(opt)) < 0) {
! 4483: i_errno = IESETDONTFRAGMENT;
! 4484: return -1;
! 4485: }
! 4486: #else
! 4487: #if defined(IP_DONTFRAGMENT) /* Windows does IP_DONTFRAGMENT */
! 4488: opt = 1;
! 4489: if (setsockopt(sp->socket, IPPROTO_IP, IP_DONTFRAGMENT, &opt, sizeof(opt)) < 0) {
! 4490: i_errno = IESETDONTFRAGMENT;
! 4491: return -1;
! 4492: }
! 4493: #else
! 4494: i_errno = IESETDONTFRAGMENT;
! 4495: return -1;
! 4496: #endif /* IP_DONTFRAGMENT */
! 4497: #endif /* IP_DONTFRAG */
! 4498: #endif /* IP_MTU_DISCOVER */
! 4499: }
! 4500: #endif /* HAVE_DONT_FRAGMENT */
1.1 misho 4501:
4502: return 0;
4503: }
4504:
4505: /**************************************************************************/
4506: void
4507: iperf_add_stream(struct iperf_test *test, struct iperf_stream *sp)
4508: {
4509: int i;
4510: struct iperf_stream *n, *prev;
4511:
4512: if (SLIST_EMPTY(&test->streams)) {
4513: SLIST_INSERT_HEAD(&test->streams, sp, streams);
4514: sp->id = 1;
4515: } else {
4516: // for (n = test->streams, i = 2; n->next; n = n->next, ++i);
1.1.1.3 ! misho 4517: // NOTE: this would ideally be set to 1, however this will not
! 4518: // be changed since it is not causing a significant problem
! 4519: // and changing it would break multi-stream tests between old
! 4520: // and new iperf3 versions.
1.1 misho 4521: i = 2;
1.1.1.3 ! misho 4522: prev = NULL;
1.1 misho 4523: SLIST_FOREACH(n, &test->streams, streams) {
4524: prev = n;
4525: ++i;
4526: }
1.1.1.3 ! misho 4527: if (prev) {
! 4528: SLIST_INSERT_AFTER(prev, sp, streams);
! 4529: sp->id = i;
! 4530: }
1.1 misho 4531: }
4532: }
4533:
4534: /* This pair of routines gets inserted into the snd/rcv function pointers
4535: ** when there's a -F flag. They handle the file stuff and call the real
4536: ** snd/rcv functions, which have been saved in snd2/rcv2.
4537: **
4538: ** The advantage of doing it this way is that in the much more common
4539: ** case of no -F flag, there is zero extra overhead.
4540: */
4541:
4542: static int
4543: diskfile_send(struct iperf_stream *sp)
4544: {
4545: int r;
1.1.1.3 ! misho 4546: int buffer_left = sp->diskfile_left; // represents total data in buffer to be sent out
1.1.1.2 misho 4547: static int rtot;
1.1 misho 4548:
1.1.1.2 misho 4549: /* if needed, read enough data from the disk to fill up the buffer */
4550: if (sp->diskfile_left < sp->test->settings->blksize && !sp->test->done) {
1.1.1.3 ! misho 4551: r = read(sp->diskfile_fd, sp->buffer, sp->test->settings->blksize -
! 4552: sp->diskfile_left);
! 4553: buffer_left += r;
! 4554: rtot += r;
! 4555: if (sp->test->debug) {
! 4556: printf("read %d bytes from file, %d total\n", r, rtot);
! 4557: }
! 4558:
! 4559: // If the buffer doesn't contain a full buffer at this point,
! 4560: // adjust the size of the data to send.
! 4561: if (buffer_left != sp->test->settings->blksize) {
! 4562: if (sp->test->debug)
! 4563: printf("possible eof\n");
! 4564: // setting data size to be sent,
! 4565: // which is less than full block/buffer size
! 4566: // (to be used by iperf_tcp_send, etc.)
! 4567: sp->pending_size = buffer_left;
! 4568: }
! 4569:
! 4570: // If there's no work left, we're done.
! 4571: if (buffer_left == 0) {
! 4572: sp->test->done = 1;
! 4573: if (sp->test->debug)
! 4574: printf("done\n");
! 4575: }
! 4576: }
! 4577:
! 4578: // If there's no data left in the file or in the buffer, we're done.
! 4579: // No more data available to be sent.
! 4580: // Return without sending data to the network
! 4581: if( sp->test->done || buffer_left == 0 ){
! 4582: if (sp->test->debug)
! 4583: printf("already done\n");
! 4584: sp->test->done = 1;
! 4585: return 0;
1.1.1.2 misho 4586: }
4587:
4588: r = sp->snd2(sp);
4589: if (r < 0) {
4590: return r;
4591: }
4592: /*
4593: * Compute how much data is in the buffer but didn't get sent.
4594: * If there are bytes that got left behind, slide them to the
4595: * front of the buffer so they can hopefully go out on the next
4596: * pass.
4597: */
1.1.1.3 ! misho 4598: sp->diskfile_left = buffer_left - r;
1.1.1.2 misho 4599: if (sp->diskfile_left && sp->diskfile_left < sp->test->settings->blksize) {
4600: memcpy(sp->buffer,
4601: sp->buffer + (sp->test->settings->blksize - sp->diskfile_left),
4602: sp->diskfile_left);
4603: if (sp->test->debug)
4604: printf("Shifting %d bytes by %d\n", sp->diskfile_left, (sp->test->settings->blksize - sp->diskfile_left));
4605: }
1.1 misho 4606: return r;
4607: }
4608:
4609: static int
4610: diskfile_recv(struct iperf_stream *sp)
4611: {
4612: int r;
4613:
4614: r = sp->rcv2(sp);
4615: if (r > 0) {
1.1.1.3 ! misho 4616: // NOTE: Currently ignoring the return value of writing to disk
! 4617: (void) (write(sp->diskfile_fd, sp->buffer, r) + 1);
1.1 misho 4618: }
4619: return r;
4620: }
4621:
4622:
4623: void
4624: iperf_catch_sigend(void (*handler)(int))
4625: {
1.1.1.2 misho 4626: #ifdef SIGINT
1.1 misho 4627: signal(SIGINT, handler);
1.1.1.2 misho 4628: #endif
4629: #ifdef SIGTERM
1.1 misho 4630: signal(SIGTERM, handler);
1.1.1.2 misho 4631: #endif
4632: #ifdef SIGHUP
1.1 misho 4633: signal(SIGHUP, handler);
1.1.1.2 misho 4634: #endif
1.1 misho 4635: }
4636:
4637: /**
4638: * Called as a result of getting a signal.
4639: * Depending on the current state of the test (and the role of this
4640: * process) compute and report one more set of ending statistics
4641: * before cleaning up and exiting.
4642: */
4643: void
4644: iperf_got_sigend(struct iperf_test *test)
4645: {
4646: /*
4647: * If we're the client, or if we're a server and running a test,
4648: * then dump out the accumulated stats so far.
4649: */
4650: if (test->role == 'c' ||
4651: (test->role == 's' && test->state == TEST_RUNNING)) {
4652:
4653: test->done = 1;
4654: cpu_util(test->cpu_util);
4655: test->stats_callback(test);
4656: test->state = DISPLAY_RESULTS; /* change local state only */
4657: if (test->on_test_finish)
4658: test->on_test_finish(test);
4659: test->reporter_callback(test);
4660: }
4661:
4662: if (test->ctrl_sck >= 0) {
4663: test->state = (test->role == 'c') ? CLIENT_TERMINATE : SERVER_TERMINATE;
4664: (void) Nwrite(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp);
4665: }
4666: i_errno = (test->role == 'c') ? IECLIENTTERM : IESERVERTERM;
4667: iperf_errexit(test, "interrupt - %s", iperf_strerror(i_errno));
4668: }
4669:
4670: /* Try to write a PID file if requested, return -1 on an error. */
4671: int
4672: iperf_create_pidfile(struct iperf_test *test)
4673: {
4674: if (test->pidfile) {
4675: int fd;
4676: char buf[8];
1.1.1.2 misho 4677:
4678: /* See if the file already exists and we can read it. */
4679: fd = open(test->pidfile, O_RDONLY, 0);
4680: if (fd >= 0) {
4681: if (read(fd, buf, sizeof(buf) - 1) >= 0) {
4682:
4683: /* We read some bytes, see if they correspond to a valid PID */
4684: pid_t pid;
4685: pid = atoi(buf);
4686: if (pid > 0) {
4687:
4688: /* See if the process exists. */
4689: if (kill(pid, 0) == 0) {
4690: /*
4691: * Make sure not to try to delete existing PID file by
4692: * scribbling over the pathname we'd use to refer to it.
4693: * Then exit with an error.
4694: */
4695: free(test->pidfile);
4696: test->pidfile = NULL;
4697: iperf_errexit(test, "Another instance of iperf3 appears to be running");
4698: }
4699: }
4700: }
4701: }
1.1.1.3 ! misho 4702:
1.1.1.2 misho 4703: /*
1.1.1.3 ! misho 4704: * File didn't exist, we couldn't read it, or it didn't correspond to
! 4705: * a running process. Try to create it.
1.1.1.2 misho 4706: */
1.1 misho 4707: fd = open(test->pidfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR);
4708: if (fd < 0) {
4709: return -1;
4710: }
4711: snprintf(buf, sizeof(buf), "%d", getpid()); /* no trailing newline */
1.1.1.3 ! misho 4712: if (write(fd, buf, strlen(buf)) < 0) {
! 4713: (void)close(fd);
1.1 misho 4714: return -1;
4715: }
4716: if (close(fd) < 0) {
4717: return -1;
4718: };
4719: }
4720: return 0;
4721: }
4722:
4723: /* Get rid of a PID file, return -1 on error. */
4724: int
4725: iperf_delete_pidfile(struct iperf_test *test)
4726: {
4727: if (test->pidfile) {
4728: if (unlink(test->pidfile) < 0) {
4729: return -1;
4730: }
4731: }
4732: return 0;
4733: }
4734:
4735: int
4736: iperf_json_start(struct iperf_test *test)
4737: {
4738: test->json_top = cJSON_CreateObject();
4739: if (test->json_top == NULL)
4740: return -1;
4741: test->json_start = cJSON_CreateObject();
4742: if (test->json_start == NULL)
4743: return -1;
4744: cJSON_AddItemToObject(test->json_top, "start", test->json_start);
4745: test->json_connected = cJSON_CreateArray();
4746: if (test->json_connected == NULL)
4747: return -1;
4748: cJSON_AddItemToObject(test->json_start, "connected", test->json_connected);
4749: test->json_intervals = cJSON_CreateArray();
4750: if (test->json_intervals == NULL)
4751: return -1;
4752: cJSON_AddItemToObject(test->json_top, "intervals", test->json_intervals);
4753: test->json_end = cJSON_CreateObject();
4754: if (test->json_end == NULL)
4755: return -1;
4756: cJSON_AddItemToObject(test->json_top, "end", test->json_end);
4757: return 0;
4758: }
4759:
4760: int
4761: iperf_json_finish(struct iperf_test *test)
4762: {
1.1.1.3 ! misho 4763: if (test->json_top) {
! 4764: if (test->title) {
! 4765: cJSON_AddStringToObject(test->json_top, "title", test->title);
! 4766: }
! 4767: if (test->extra_data) {
! 4768: cJSON_AddStringToObject(test->json_top, "extra_data", test->extra_data);
! 4769: }
! 4770: /* Include server output */
! 4771: if (test->json_server_output) {
! 4772: cJSON_AddItemToObject(test->json_top, "server_output_json", test->json_server_output);
! 4773: }
! 4774: if (test->server_output_text) {
! 4775: cJSON_AddStringToObject(test->json_top, "server_output_text", test->server_output_text);
! 4776: }
! 4777: // Get ASCII rendering of JSON structure. Then make our
! 4778: // own copy of it and return the storage that cJSON allocated
! 4779: // on our behalf. We keep our own copy around.
! 4780: char *str = cJSON_Print(test->json_top);
! 4781: if (str == NULL) {
! 4782: return -1;
! 4783: }
! 4784: test->json_output_string = strdup(str);
! 4785: cJSON_free(str);
! 4786: if (test->json_output_string == NULL) {
! 4787: return -1;
! 4788: }
! 4789: fprintf(test->outfile, "%s\n", test->json_output_string);
! 4790: iflush(test);
! 4791: cJSON_Delete(test->json_top);
! 4792: test->json_top = NULL;
1.1 misho 4793: }
1.1.1.3 ! misho 4794: test->json_start = test->json_connected = test->json_intervals = test->json_server_output = test->json_end = NULL;
1.1 misho 4795: return 0;
4796: }
4797:
4798:
1.1.1.2 misho 4799: /* CPU affinity stuff - Linux, FreeBSD, and Windows only. */
1.1 misho 4800:
4801: int
4802: iperf_setaffinity(struct iperf_test *test, int affinity)
4803: {
4804: #if defined(HAVE_SCHED_SETAFFINITY)
4805: cpu_set_t cpu_set;
4806:
4807: CPU_ZERO(&cpu_set);
4808: CPU_SET(affinity, &cpu_set);
4809: if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) != 0) {
4810: i_errno = IEAFFINITY;
4811: return -1;
4812: }
4813: return 0;
4814: #elif defined(HAVE_CPUSET_SETAFFINITY)
4815: cpuset_t cpumask;
4816:
4817: if(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
4818: sizeof(cpuset_t), &test->cpumask) != 0) {
4819: i_errno = IEAFFINITY;
4820: return -1;
4821: }
4822:
4823: CPU_ZERO(&cpumask);
4824: CPU_SET(affinity, &cpumask);
4825:
4826: if(cpuset_setaffinity(CPU_LEVEL_WHICH,CPU_WHICH_PID, -1,
4827: sizeof(cpuset_t), &cpumask) != 0) {
4828: i_errno = IEAFFINITY;
4829: return -1;
4830: }
4831: return 0;
1.1.1.2 misho 4832: #elif defined(HAVE_SETPROCESSAFFINITYMASK)
4833: HANDLE process = GetCurrentProcess();
4834: DWORD_PTR processAffinityMask = 1 << affinity;
4835:
4836: if (SetProcessAffinityMask(process, processAffinityMask) == 0) {
4837: i_errno = IEAFFINITY;
4838: return -1;
4839: }
4840: return 0;
4841: #else /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
1.1 misho 4842: i_errno = IEAFFINITY;
4843: return -1;
1.1.1.2 misho 4844: #endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
1.1 misho 4845: }
4846:
4847: int
4848: iperf_clearaffinity(struct iperf_test *test)
4849: {
4850: #if defined(HAVE_SCHED_SETAFFINITY)
4851: cpu_set_t cpu_set;
4852: int i;
4853:
4854: CPU_ZERO(&cpu_set);
4855: for (i = 0; i < CPU_SETSIZE; ++i)
4856: CPU_SET(i, &cpu_set);
4857: if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) != 0) {
4858: i_errno = IEAFFINITY;
4859: return -1;
4860: }
4861: return 0;
4862: #elif defined(HAVE_CPUSET_SETAFFINITY)
4863: if(cpuset_setaffinity(CPU_LEVEL_WHICH,CPU_WHICH_PID, -1,
4864: sizeof(cpuset_t), &test->cpumask) != 0) {
4865: i_errno = IEAFFINITY;
4866: return -1;
4867: }
4868: return 0;
1.1.1.2 misho 4869: #elif defined(HAVE_SETPROCESSAFFINITYMASK)
4870: HANDLE process = GetCurrentProcess();
4871: DWORD_PTR processAffinityMask;
4872: DWORD_PTR lpSystemAffinityMask;
4873:
4874: if (GetProcessAffinityMask(process, &processAffinityMask, &lpSystemAffinityMask) == 0
4875: || SetProcessAffinityMask(process, lpSystemAffinityMask) == 0) {
4876: i_errno = IEAFFINITY;
4877: return -1;
4878: }
4879: return 0;
4880: #else /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
1.1 misho 4881: i_errno = IEAFFINITY;
4882: return -1;
1.1.1.2 misho 4883: #endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY nor HAVE_SETPROCESSAFFINITYMASK */
1.1 misho 4884: }
4885:
1.1.1.3 ! misho 4886: static char iperf_timestr[100];
! 4887: static char linebuffer[1024];
1.1.1.2 misho 4888:
1.1 misho 4889: int
1.1.1.2 misho 4890: iperf_printf(struct iperf_test *test, const char* format, ...)
1.1 misho 4891: {
4892: va_list argp;
1.1.1.3 ! misho 4893: int r = 0, r0;
1.1.1.2 misho 4894: time_t now;
4895: struct tm *ltm = NULL;
4896: char *ct = NULL;
4897:
4898: /* Timestamp if requested */
4899: if (iperf_get_test_timestamps(test)) {
4900: time(&now);
4901: ltm = localtime(&now);
4902: strftime(iperf_timestr, sizeof(iperf_timestr), iperf_get_test_timestamp_format(test), ltm);
4903: ct = iperf_timestr;
4904: }
1.1 misho 4905:
4906: /*
4907: * There are roughly two use cases here. If we're the client,
4908: * want to print stuff directly to the output stream.
4909: * If we're the sender we might need to buffer up output to send
4910: * to the client.
4911: *
4912: * This doesn't make a whole lot of difference except there are
4913: * some chunks of output on the client (on particular the whole
4914: * of the server output with --get-server-output) that could
4915: * easily exceed the size of the line buffer, but which don't need
4916: * to be buffered up anyway.
4917: */
4918: if (test->role == 'c') {
1.1.1.2 misho 4919: if (ct) {
1.1.1.3 ! misho 4920: r0 = fprintf(test->outfile, "%s", ct);
! 4921: if (r0 < 0)
! 4922: return r0;
! 4923: r += r0;
1.1.1.2 misho 4924: }
1.1.1.3 ! misho 4925: if (test->title) {
! 4926: r0 = fprintf(test->outfile, "%s: ", test->title);
! 4927: if (r0 < 0)
! 4928: return r0;
! 4929: r += r0;
! 4930: }
1.1 misho 4931: va_start(argp, format);
1.1.1.3 ! misho 4932: r0 = vfprintf(test->outfile, format, argp);
1.1 misho 4933: va_end(argp);
1.1.1.3 ! misho 4934: if (r0 < 0)
! 4935: return r0;
! 4936: r += r0;
1.1 misho 4937: }
4938: else if (test->role == 's') {
1.1.1.2 misho 4939: if (ct) {
1.1.1.3 ! misho 4940: r0 = snprintf(linebuffer, sizeof(linebuffer), "%s", ct);
! 4941: if (r0 < 0)
! 4942: return r0;
! 4943: r += r0;
1.1.1.2 misho 4944: }
1.1.1.3 ! misho 4945: /* Should always be true as long as sizeof(ct) < sizeof(linebuffer) */
! 4946: if (r < sizeof(linebuffer)) {
! 4947: va_start(argp, format);
! 4948: r0 = vsnprintf(linebuffer + r, sizeof(linebuffer) - r, format, argp);
! 4949: va_end(argp);
! 4950: if (r0 < 0)
! 4951: return r0;
! 4952: r += r0;
! 4953: }
1.1 misho 4954: fprintf(test->outfile, "%s", linebuffer);
4955:
4956: if (test->role == 's' && iperf_get_test_get_server_output(test)) {
4957: struct iperf_textline *l = (struct iperf_textline *) malloc(sizeof(struct iperf_textline));
4958: l->line = strdup(linebuffer);
4959: TAILQ_INSERT_TAIL(&(test->server_output_list), l, textlineentries);
4960: }
4961: }
4962: return r;
4963: }
4964:
4965: int
4966: iflush(struct iperf_test *test)
4967: {
4968: return fflush(test->outfile);
4969: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>