Annotation of embedaddon/iperf/src/iperf_api.c, revision 1.1.1.1
1.1 misho 1: /*
2: * iperf, Copyright (c) 2014, 2015, 2016, The Regents of the University of
3: * California, through Lawrence Berkeley National Laboratory (subject
4: * to receipt of any required approvals from the U.S. Dept. of
5: * Energy). All rights reserved.
6: *
7: * If you have questions about your rights to use or distribute this
8: * software, please contact Berkeley Lab's Technology Transfer
9: * Department at TTD@lbl.gov.
10: *
11: * NOTICE. This software is owned by the U.S. Department of Energy.
12: * As such, the U.S. Government has been granted for itself and others
13: * acting on its behalf a paid-up, nonexclusive, irrevocable,
14: * worldwide license in the Software to reproduce, prepare derivative
15: * works, and perform publicly and display publicly. Beginning five
16: * (5) years after the date permission to assert copyright is obtained
17: * from the U.S. Department of Energy, and subject to any subsequent
18: * five (5) year renewals, the U.S. Government is granted for itself
19: * and others acting on its behalf a paid-up, nonexclusive,
20: * irrevocable, worldwide license in the Software to reproduce,
21: * prepare derivative works, distribute copies to the public, perform
22: * publicly and display publicly, and to permit others to do so.
23: *
24: * This code is distributed under a BSD style license, see the LICENSE file
25: * for complete information.
26: */
27: #define _GNU_SOURCE
28: #define __USE_GNU
29:
30: #include "iperf_config.h"
31:
32: #include <stdio.h>
33: #include <stdlib.h>
34: #include <string.h>
35: #include <getopt.h>
36: #include <errno.h>
37: #include <signal.h>
38: #include <unistd.h>
39: #include <assert.h>
40: #include <fcntl.h>
41: #include <sys/socket.h>
42: #include <sys/types.h>
43: #include <netinet/in.h>
44: #include <arpa/inet.h>
45: #include <netdb.h>
46: #include <pthread.h>
47: #ifdef HAVE_STDINT_H
48: #include <stdint.h>
49: #endif
50: #include <netinet/tcp.h>
51: #include <sys/time.h>
52: #include <sys/resource.h>
53: #include <sys/mman.h>
54: #include <sys/stat.h>
55: #include <sched.h>
56: #include <setjmp.h>
57: #include <stdarg.h>
58:
59: #if defined(HAVE_CPUSET_SETAFFINITY)
60: #include <sys/param.h>
61: #include <sys/cpuset.h>
62: #endif /* HAVE_CPUSET_SETAFFINITY */
63:
64: #include "net.h"
65: #include "iperf.h"
66: #include "iperf_api.h"
67: #include "iperf_udp.h"
68: #include "iperf_tcp.h"
69: #if defined(HAVE_SCTP)
70: #include "iperf_sctp.h"
71: #endif /* HAVE_SCTP */
72: #include "timer.h"
73:
74: #include "cjson.h"
75: #include "units.h"
76: #include "tcp_window_size.h"
77: #include "iperf_util.h"
78: #include "iperf_locale.h"
79: #include "version.h"
80:
81: /* Forwards. */
82: static int send_parameters(struct iperf_test *test);
83: static int get_parameters(struct iperf_test *test);
84: static int send_results(struct iperf_test *test);
85: static int get_results(struct iperf_test *test);
86: static int diskfile_send(struct iperf_stream *sp);
87: static int diskfile_recv(struct iperf_stream *sp);
88: static int JSON_write(int fd, cJSON *json);
89: static void print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *json_interval_streams);
90: static cJSON *JSON_read(int fd);
91:
92:
93: /*************************** Print usage functions ****************************/
94:
95: void
96: usage()
97: {
98: fputs(usage_shortstr, stderr);
99: }
100:
101:
102: void
103: usage_long()
104: {
105: fprintf(stderr, usage_longstr, UDP_RATE / (1024*1024), DURATION, DEFAULT_TCP_BLKSIZE / 1024, DEFAULT_UDP_BLKSIZE / 1024);
106: }
107:
108:
109: void warning(char *str)
110: {
111: fprintf(stderr, "warning: %s\n", str);
112: }
113:
114:
115: /************** Getter routines for some fields inside iperf_test *************/
116:
117: int
118: iperf_get_verbose(struct iperf_test *ipt)
119: {
120: return ipt->verbose;
121: }
122:
123: int
124: iperf_get_control_socket(struct iperf_test *ipt)
125: {
126: return ipt->ctrl_sck;
127: }
128:
129: int
130: iperf_get_test_omit(struct iperf_test *ipt)
131: {
132: return ipt->omit;
133: }
134:
135: int
136: iperf_get_test_duration(struct iperf_test *ipt)
137: {
138: return ipt->duration;
139: }
140:
141: uint64_t
142: iperf_get_test_rate(struct iperf_test *ipt)
143: {
144: return ipt->settings->rate;
145: }
146:
147: int
148: iperf_get_test_burst(struct iperf_test *ipt)
149: {
150: return ipt->settings->burst;
151: }
152:
153: char
154: iperf_get_test_role(struct iperf_test *ipt)
155: {
156: return ipt->role;
157: }
158:
159: int
160: iperf_get_test_reverse(struct iperf_test *ipt)
161: {
162: return ipt->reverse;
163: }
164:
165: int
166: iperf_get_test_blksize(struct iperf_test *ipt)
167: {
168: return ipt->settings->blksize;
169: }
170:
171: FILE *
172: iperf_get_test_outfile (struct iperf_test *ipt)
173: {
174: return ipt->outfile;
175: }
176:
177: int
178: iperf_get_test_socket_bufsize(struct iperf_test *ipt)
179: {
180: return ipt->settings->socket_bufsize;
181: }
182:
183: double
184: iperf_get_test_reporter_interval(struct iperf_test *ipt)
185: {
186: return ipt->reporter_interval;
187: }
188:
189: double
190: iperf_get_test_stats_interval(struct iperf_test *ipt)
191: {
192: return ipt->stats_interval;
193: }
194:
195: int
196: iperf_get_test_num_streams(struct iperf_test *ipt)
197: {
198: return ipt->num_streams;
199: }
200:
201: int
202: iperf_get_test_server_port(struct iperf_test *ipt)
203: {
204: return ipt->server_port;
205: }
206:
207: char*
208: iperf_get_test_server_hostname(struct iperf_test *ipt)
209: {
210: return ipt->server_hostname;
211: }
212:
213: char*
214: iperf_get_test_template(struct iperf_test *ipt)
215: {
216: return ipt->tmp_template;
217: }
218:
219: int
220: iperf_get_test_protocol_id(struct iperf_test *ipt)
221: {
222: return ipt->protocol->id;
223: }
224:
225: int
226: iperf_get_test_json_output(struct iperf_test *ipt)
227: {
228: return ipt->json_output;
229: }
230:
231: char *
232: iperf_get_test_json_output_string(struct iperf_test *ipt)
233: {
234: return ipt->json_output_string;
235: }
236:
237: int
238: iperf_get_test_zerocopy(struct iperf_test *ipt)
239: {
240: return ipt->zerocopy;
241: }
242:
243: int
244: iperf_get_test_get_server_output(struct iperf_test *ipt)
245: {
246: return ipt->get_server_output;
247: }
248:
249: char
250: iperf_get_test_unit_format(struct iperf_test *ipt)
251: {
252: return ipt->settings->unit_format;
253: }
254:
255: char *
256: iperf_get_test_bind_address(struct iperf_test *ipt)
257: {
258: return ipt->bind_address;
259: }
260:
261: int
262: iperf_get_test_udp_counters_64bit(struct iperf_test *ipt)
263: {
264: return ipt->udp_counters_64bit;
265: }
266:
267: int
268: iperf_get_test_one_off(struct iperf_test *ipt)
269: {
270: return ipt->one_off;
271: }
272:
273: int
274: iperf_get_no_fq_socket_pacing(struct iperf_test *ipt)
275: {
276: return ipt->no_fq_socket_pacing;
277: }
278:
279: /************** Setter routines for some fields inside iperf_test *************/
280:
281: void
282: iperf_set_verbose(struct iperf_test *ipt, int verbose)
283: {
284: ipt->verbose = verbose;
285: }
286:
287: void
288: iperf_set_control_socket(struct iperf_test *ipt, int ctrl_sck)
289: {
290: ipt->ctrl_sck = ctrl_sck;
291: }
292:
293: void
294: iperf_set_test_omit(struct iperf_test *ipt, int omit)
295: {
296: ipt->omit = omit;
297: }
298:
299: void
300: iperf_set_test_duration(struct iperf_test *ipt, int duration)
301: {
302: ipt->duration = duration;
303: }
304:
305: void
306: iperf_set_test_reporter_interval(struct iperf_test *ipt, double reporter_interval)
307: {
308: ipt->reporter_interval = reporter_interval;
309: }
310:
311: void
312: iperf_set_test_stats_interval(struct iperf_test *ipt, double stats_interval)
313: {
314: ipt->stats_interval = stats_interval;
315: }
316:
317: void
318: iperf_set_test_state(struct iperf_test *ipt, signed char state)
319: {
320: ipt->state = state;
321: }
322:
323: void
324: iperf_set_test_blksize(struct iperf_test *ipt, int blksize)
325: {
326: ipt->settings->blksize = blksize;
327: }
328:
329: void
330: iperf_set_test_rate(struct iperf_test *ipt, uint64_t rate)
331: {
332: ipt->settings->rate = rate;
333: }
334:
335: void
336: iperf_set_test_burst(struct iperf_test *ipt, int burst)
337: {
338: ipt->settings->burst = burst;
339: }
340:
341: void
342: iperf_set_test_server_port(struct iperf_test *ipt, int server_port)
343: {
344: ipt->server_port = server_port;
345: }
346:
347: void
348: iperf_set_test_socket_bufsize(struct iperf_test *ipt, int socket_bufsize)
349: {
350: ipt->settings->socket_bufsize = socket_bufsize;
351: }
352:
353: void
354: iperf_set_test_num_streams(struct iperf_test *ipt, int num_streams)
355: {
356: ipt->num_streams = num_streams;
357: }
358:
359: static void
360: check_sender_has_retransmits(struct iperf_test *ipt)
361: {
362: if (ipt->sender && ipt->protocol->id == Ptcp && has_tcpinfo_retransmits())
363: ipt->sender_has_retransmits = 1;
364: else
365: ipt->sender_has_retransmits = 0;
366: }
367:
368: void
369: iperf_set_test_role(struct iperf_test *ipt, char role)
370: {
371: ipt->role = role;
372: if (role == 'c')
373: ipt->sender = 1;
374: else if (role == 's')
375: ipt->sender = 0;
376: if (ipt->reverse)
377: ipt->sender = ! ipt->sender;
378: check_sender_has_retransmits(ipt);
379: }
380:
381: void
382: iperf_set_test_server_hostname(struct iperf_test *ipt, char *server_hostname)
383: {
384: ipt->server_hostname = strdup(server_hostname);
385: }
386:
387: void
388: iperf_set_test_template(struct iperf_test *ipt, char *tmp_template)
389: {
390: ipt->tmp_template = strdup(tmp_template);
391: }
392:
393: void
394: iperf_set_test_reverse(struct iperf_test *ipt, int reverse)
395: {
396: ipt->reverse = reverse;
397: if (ipt->reverse)
398: ipt->sender = ! ipt->sender;
399: check_sender_has_retransmits(ipt);
400: }
401:
402: void
403: iperf_set_test_json_output(struct iperf_test *ipt, int json_output)
404: {
405: ipt->json_output = json_output;
406: }
407:
408: int
409: iperf_has_zerocopy( void )
410: {
411: return has_sendfile();
412: }
413:
414: void
415: iperf_set_test_zerocopy(struct iperf_test *ipt, int zerocopy)
416: {
417: ipt->zerocopy = (zerocopy && has_sendfile());
418: }
419:
420: void
421: iperf_set_test_get_server_output(struct iperf_test *ipt, int get_server_output)
422: {
423: ipt->get_server_output = get_server_output;
424: }
425:
426: void
427: iperf_set_test_unit_format(struct iperf_test *ipt, char unit_format)
428: {
429: ipt->settings->unit_format = unit_format;
430: }
431:
432: void
433: iperf_set_test_bind_address(struct iperf_test *ipt, char *bind_address)
434: {
435: ipt->bind_address = strdup(bind_address);
436: }
437:
438: void
439: iperf_set_test_udp_counters_64bit(struct iperf_test *ipt, int udp_counters_64bit)
440: {
441: ipt->udp_counters_64bit = udp_counters_64bit;
442: }
443:
444: void
445: iperf_set_test_one_off(struct iperf_test *ipt, int one_off)
446: {
447: ipt->one_off = one_off;
448: }
449:
450: void
451: iperf_set_no_fq_socket_pacing(struct iperf_test *ipt, int no_pacing)
452: {
453: ipt->no_fq_socket_pacing = no_pacing;
454: }
455:
456: /********************** Get/set test protocol structure ***********************/
457:
458: struct protocol *
459: get_protocol(struct iperf_test *test, int prot_id)
460: {
461: struct protocol *prot;
462:
463: SLIST_FOREACH(prot, &test->protocols, protocols) {
464: if (prot->id == prot_id)
465: break;
466: }
467:
468: if (prot == NULL)
469: i_errno = IEPROTOCOL;
470:
471: return prot;
472: }
473:
474: int
475: set_protocol(struct iperf_test *test, int prot_id)
476: {
477: struct protocol *prot = NULL;
478:
479: SLIST_FOREACH(prot, &test->protocols, protocols) {
480: if (prot->id == prot_id) {
481: test->protocol = prot;
482: check_sender_has_retransmits(test);
483: return 0;
484: }
485: }
486:
487: i_errno = IEPROTOCOL;
488: return -1;
489: }
490:
491:
492: /************************** Iperf callback functions **************************/
493:
494: void
495: iperf_on_new_stream(struct iperf_stream *sp)
496: {
497: connect_msg(sp);
498: }
499:
500: void
501: iperf_on_test_start(struct iperf_test *test)
502: {
503: if (test->json_output) {
504: 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", 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));
505: } else {
506: if (test->verbose) {
507: if (test->settings->bytes)
508: iprintf(test, test_start_bytes, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->settings->bytes);
509: else if (test->settings->blocks)
510: iprintf(test, test_start_blocks, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->settings->blocks);
511: else
512: iprintf(test, test_start_time, test->protocol->name, test->num_streams, test->settings->blksize, test->omit, test->duration);
513: }
514: }
515: }
516:
517: /* This converts an IPv6 string address from IPv4-mapped format into regular
518: ** old IPv4 format, which is easier on the eyes of network veterans.
519: **
520: ** If the v6 address is not v4-mapped it is left alone.
521: */
522: static void
523: mapped_v4_to_regular_v4(char *str)
524: {
525: char *prefix = "::ffff:";
526: int prefix_len;
527:
528: prefix_len = strlen(prefix);
529: if (strncmp(str, prefix, prefix_len) == 0) {
530: int str_len = strlen(str);
531: memmove(str, str + prefix_len, str_len - prefix_len + 1);
532: }
533: }
534:
535: void
536: iperf_on_connect(struct iperf_test *test)
537: {
538: time_t now_secs;
539: const char* rfc1123_fmt = "%a, %d %b %Y %H:%M:%S GMT";
540: char now_str[100];
541: char ipr[INET6_ADDRSTRLEN];
542: int port;
543: struct sockaddr_storage sa;
544: struct sockaddr_in *sa_inP;
545: struct sockaddr_in6 *sa_in6P;
546: socklen_t len;
547: int opt;
548:
549: now_secs = time((time_t*) 0);
550: (void) strftime(now_str, sizeof(now_str), rfc1123_fmt, gmtime(&now_secs));
551: if (test->json_output)
552: cJSON_AddItemToObject(test->json_start, "timestamp", iperf_json_printf("time: %s timesecs: %d", now_str, (int64_t) now_secs));
553: else if (test->verbose)
554: iprintf(test, report_time, now_str);
555:
556: if (test->role == 'c') {
557: if (test->json_output)
558: cJSON_AddItemToObject(test->json_start, "connecting_to", iperf_json_printf("host: %s port: %d", test->server_hostname, (int64_t) test->server_port));
559: else {
560: iprintf(test, report_connecting, test->server_hostname, test->server_port);
561: if (test->reverse)
562: iprintf(test, report_reverse, test->server_hostname);
563: }
564: } else {
565: len = sizeof(sa);
566: getpeername(test->ctrl_sck, (struct sockaddr *) &sa, &len);
567: if (getsockdomain(test->ctrl_sck) == AF_INET) {
568: sa_inP = (struct sockaddr_in *) &sa;
569: inet_ntop(AF_INET, &sa_inP->sin_addr, ipr, sizeof(ipr));
570: port = ntohs(sa_inP->sin_port);
571: } else {
572: sa_in6P = (struct sockaddr_in6 *) &sa;
573: inet_ntop(AF_INET6, &sa_in6P->sin6_addr, ipr, sizeof(ipr));
574: port = ntohs(sa_in6P->sin6_port);
575: }
576: mapped_v4_to_regular_v4(ipr);
577: if (test->json_output)
578: cJSON_AddItemToObject(test->json_start, "accepted_connection", iperf_json_printf("host: %s port: %d", ipr, (int64_t) port));
579: else
580: iprintf(test, report_accepted, ipr, port);
581: }
582: if (test->json_output) {
583: cJSON_AddStringToObject(test->json_start, "cookie", test->cookie);
584: if (test->protocol->id == SOCK_STREAM) {
585: if (test->settings->mss)
586: cJSON_AddNumberToObject(test->json_start, "tcp_mss", test->settings->mss);
587: else {
588: len = sizeof(opt);
589: getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len);
590: cJSON_AddNumberToObject(test->json_start, "tcp_mss_default", opt);
591: }
592: }
593: } else if (test->verbose) {
594: iprintf(test, report_cookie, test->cookie);
595: if (test->protocol->id == SOCK_STREAM) {
596: if (test->settings->mss)
597: iprintf(test, " TCP MSS: %d\n", test->settings->mss);
598: else {
599: len = sizeof(opt);
600: getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len);
601: iprintf(test, " TCP MSS: %d (default)\n", opt);
602: }
603: }
604:
605: }
606: }
607:
608: void
609: iperf_on_test_finish(struct iperf_test *test)
610: {
611: }
612:
613:
614: /******************************************************************************/
615:
616: int
617: iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
618: {
619: static struct option longopts[] =
620: {
621: {"port", required_argument, NULL, 'p'},
622: {"format", required_argument, NULL, 'f'},
623: {"interval", required_argument, NULL, 'i'},
624: {"daemon", no_argument, NULL, 'D'},
625: {"one-off", no_argument, NULL, '1'},
626: {"verbose", no_argument, NULL, 'V'},
627: {"json", no_argument, NULL, 'J'},
628: {"version", no_argument, NULL, 'v'},
629: {"server", no_argument, NULL, 's'},
630: {"client", required_argument, NULL, 'c'},
631: {"udp", no_argument, NULL, 'u'},
632: {"bandwidth", required_argument, NULL, 'b'},
633: {"time", required_argument, NULL, 't'},
634: {"bytes", required_argument, NULL, 'n'},
635: {"blockcount", required_argument, NULL, 'k'},
636: {"length", required_argument, NULL, 'l'},
637: {"parallel", required_argument, NULL, 'P'},
638: {"reverse", no_argument, NULL, 'R'},
639: {"window", required_argument, NULL, 'w'},
640: {"bind", required_argument, NULL, 'B'},
641: {"cport", required_argument, NULL, OPT_CLIENT_PORT},
642: {"set-mss", required_argument, NULL, 'M'},
643: {"no-delay", no_argument, NULL, 'N'},
644: {"version4", no_argument, NULL, '4'},
645: {"version6", no_argument, NULL, '6'},
646: {"tos", required_argument, NULL, 'S'},
647: #if defined(HAVE_FLOWLABEL)
648: {"flowlabel", required_argument, NULL, 'L'},
649: #endif /* HAVE_FLOWLABEL */
650: {"zerocopy", no_argument, NULL, 'Z'},
651: {"omit", required_argument, NULL, 'O'},
652: {"file", required_argument, NULL, 'F'},
653: #if defined(HAVE_CPU_AFFINITY)
654: {"affinity", required_argument, NULL, 'A'},
655: #endif /* HAVE_CPU_AFFINITY */
656: {"title", required_argument, NULL, 'T'},
657: #if defined(HAVE_TCP_CONGESTION)
658: {"congestion", required_argument, NULL, 'C'},
659: {"linux-congestion", required_argument, NULL, 'C'},
660: #endif /* HAVE_TCP_CONGESTION */
661: #if defined(HAVE_SCTP)
662: {"sctp", no_argument, NULL, OPT_SCTP},
663: {"nstreams", required_argument, NULL, OPT_NUMSTREAMS},
664: {"xbind", required_argument, NULL, 'X'},
665: #endif
666: {"pidfile", required_argument, NULL, 'I'},
667: {"logfile", required_argument, NULL, OPT_LOGFILE},
668: {"get-server-output", no_argument, NULL, OPT_GET_SERVER_OUTPUT},
669: {"udp-counters-64bit", no_argument, NULL, OPT_UDP_COUNTERS_64BIT},
670: {"no-fq-socket-pacing", no_argument, NULL, OPT_NO_FQ_SOCKET_PACING},
671: {"debug", no_argument, NULL, 'd'},
672: {"help", no_argument, NULL, 'h'},
673: {NULL, 0, NULL, 0}
674: };
675: int flag;
676: int blksize;
677: int server_flag, client_flag, rate_flag, duration_flag;
678: char *endptr;
679: #if defined(HAVE_CPU_AFFINITY)
680: char* comma;
681: #endif /* HAVE_CPU_AFFINITY */
682: char* slash;
683: struct xbind_entry *xbe;
684:
685: blksize = 0;
686: server_flag = client_flag = rate_flag = duration_flag = 0;
687: 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) {
688: switch (flag) {
689: case 'p':
690: test->server_port = atoi(optarg);
691: break;
692: case 'f':
693: test->settings->unit_format = *optarg;
694: break;
695: case 'i':
696: /* XXX: could potentially want separate stat collection and reporting intervals,
697: but just set them to be the same for now */
698: test->stats_interval = test->reporter_interval = atof(optarg);
699: if ((test->stats_interval < MIN_INTERVAL || test->stats_interval > MAX_INTERVAL) && test->stats_interval != 0) {
700: i_errno = IEINTERVAL;
701: return -1;
702: }
703: break;
704: case 'D':
705: test->daemon = 1;
706: server_flag = 1;
707: break;
708: case '1':
709: test->one_off = 1;
710: server_flag = 1;
711: break;
712: case 'V':
713: test->verbose = 1;
714: break;
715: case 'J':
716: test->json_output = 1;
717: break;
718: case 'v':
719: printf("%s\n%s\n%s\n", version, get_system_info(),
720: get_optional_features());
721: exit(0);
722: case 's':
723: if (test->role == 'c') {
724: i_errno = IESERVCLIENT;
725: return -1;
726: }
727: iperf_set_test_role(test, 's');
728: break;
729: case 'c':
730: if (test->role == 's') {
731: i_errno = IESERVCLIENT;
732: return -1;
733: }
734: iperf_set_test_role(test, 'c');
735: iperf_set_test_server_hostname(test, optarg);
736: break;
737: case 'u':
738: set_protocol(test, Pudp);
739: client_flag = 1;
740: break;
741: case OPT_SCTP:
742: #if defined(HAVE_SCTP)
743: set_protocol(test, Psctp);
744: client_flag = 1;
745: #else /* HAVE_SCTP */
746: i_errno = IEUNIMP;
747: return -1;
748: #endif /* HAVE_SCTP */
749: break;
750:
751: case OPT_NUMSTREAMS:
752: #if defined(linux) || defined(__FreeBSD__)
753: test->settings->num_ostreams = unit_atoi(optarg);
754: client_flag = 1;
755: #else /* linux */
756: i_errno = IEUNIMP;
757: return -1;
758: #endif /* linux */
759: case 'b':
760: slash = strchr(optarg, '/');
761: if (slash) {
762: *slash = '\0';
763: ++slash;
764: test->settings->burst = atoi(slash);
765: if (test->settings->burst <= 0 ||
766: test->settings->burst > MAX_BURST) {
767: i_errno = IEBURST;
768: return -1;
769: }
770: }
771: test->settings->rate = unit_atof_rate(optarg);
772: rate_flag = 1;
773: client_flag = 1;
774: break;
775: case 't':
776: test->duration = atoi(optarg);
777: if (test->duration > MAX_TIME) {
778: i_errno = IEDURATION;
779: return -1;
780: }
781: duration_flag = 1;
782: client_flag = 1;
783: break;
784: case 'n':
785: test->settings->bytes = unit_atoi(optarg);
786: client_flag = 1;
787: break;
788: case 'k':
789: test->settings->blocks = unit_atoi(optarg);
790: client_flag = 1;
791: break;
792: case 'l':
793: blksize = unit_atoi(optarg);
794: client_flag = 1;
795: break;
796: case 'P':
797: test->num_streams = atoi(optarg);
798: if (test->num_streams > MAX_STREAMS) {
799: i_errno = IENUMSTREAMS;
800: return -1;
801: }
802: client_flag = 1;
803: break;
804: case 'R':
805: iperf_set_test_reverse(test, 1);
806: client_flag = 1;
807: break;
808: case 'w':
809: // XXX: This is a socket buffer, not specific to TCP
810: test->settings->socket_bufsize = unit_atof(optarg);
811: if (test->settings->socket_bufsize > MAX_TCP_BUFFER) {
812: i_errno = IEBUFSIZE;
813: return -1;
814: }
815: client_flag = 1;
816: break;
817: case 'B':
818: test->bind_address = strdup(optarg);
819: break;
820: case OPT_CLIENT_PORT:
821: test->bind_port = atoi(optarg);
822: break;
823: case 'M':
824: test->settings->mss = atoi(optarg);
825: if (test->settings->mss > MAX_MSS) {
826: i_errno = IEMSS;
827: return -1;
828: }
829: client_flag = 1;
830: break;
831: case 'N':
832: test->no_delay = 1;
833: client_flag = 1;
834: break;
835: case '4':
836: test->settings->domain = AF_INET;
837: break;
838: case '6':
839: test->settings->domain = AF_INET6;
840: break;
841: case 'S':
842: test->settings->tos = strtol(optarg, &endptr, 0);
843: if (endptr == optarg ||
844: test->settings->tos < 0 ||
845: test->settings->tos > 255) {
846: i_errno = IEBADTOS;
847: return -1;
848: }
849: client_flag = 1;
850: break;
851: case 'L':
852: #if defined(HAVE_FLOWLABEL)
853: test->settings->flowlabel = strtol(optarg, &endptr, 0);
854: if (endptr == optarg ||
855: test->settings->flowlabel < 1 || test->settings->flowlabel > 0xfffff) {
856: i_errno = IESETFLOW;
857: return -1;
858: }
859: client_flag = 1;
860: #else /* HAVE_FLOWLABEL */
861: i_errno = IEUNIMP;
862: return -1;
863: #endif /* HAVE_FLOWLABEL */
864: break;
865: case 'X':
866: xbe = (struct xbind_entry *)malloc(sizeof(struct xbind_entry));
867: if (!xbe) {
868: i_errno = IESETSCTPBINDX;
869: return -1;
870: }
871: memset(xbe, 0, sizeof(*xbe));
872: xbe->name = strdup(optarg);
873: if (!xbe->name) {
874: i_errno = IESETSCTPBINDX;
875: return -1;
876: }
877: TAILQ_INSERT_TAIL(&test->xbind_addrs, xbe, link);
878: break;
879: case 'Z':
880: if (!has_sendfile()) {
881: i_errno = IENOSENDFILE;
882: return -1;
883: }
884: test->zerocopy = 1;
885: client_flag = 1;
886: break;
887: case 'O':
888: test->omit = atoi(optarg);
889: if (test->omit < 0 || test->omit > 60) {
890: i_errno = IEOMIT;
891: return -1;
892: }
893: client_flag = 1;
894: break;
895: case 'F':
896: test->diskfile_name = optarg;
897: break;
898: case 'A':
899: #if defined(HAVE_CPU_AFFINITY)
900: test->affinity = strtol(optarg, &endptr, 0);
901: if (endptr == optarg ||
902: test->affinity < 0 || test->affinity > 1024) {
903: i_errno = IEAFFINITY;
904: return -1;
905: }
906: comma = strchr(optarg, ',');
907: if (comma != NULL) {
908: test->server_affinity = atoi(comma+1);
909: if (test->server_affinity < 0 || test->server_affinity > 1024) {
910: i_errno = IEAFFINITY;
911: return -1;
912: }
913: client_flag = 1;
914: }
915: #else /* HAVE_CPU_AFFINITY */
916: i_errno = IEUNIMP;
917: return -1;
918: #endif /* HAVE_CPU_AFFINITY */
919: break;
920: case 'T':
921: test->title = strdup(optarg);
922: client_flag = 1;
923: break;
924: case 'C':
925: #if defined(HAVE_TCP_CONGESTION)
926: test->congestion = strdup(optarg);
927: client_flag = 1;
928: #else /* HAVE_TCP_CONGESTION */
929: i_errno = IEUNIMP;
930: return -1;
931: #endif /* HAVE_TCP_CONGESTION */
932: break;
933: case 'd':
934: test->debug = 1;
935: break;
936: case 'I':
937: test->pidfile = strdup(optarg);
938: server_flag = 1;
939: break;
940: case OPT_LOGFILE:
941: test->logfile = strdup(optarg);
942: break;
943: case OPT_GET_SERVER_OUTPUT:
944: test->get_server_output = 1;
945: client_flag = 1;
946: break;
947: case OPT_UDP_COUNTERS_64BIT:
948: test->udp_counters_64bit = 1;
949: break;
950: case OPT_NO_FQ_SOCKET_PACING:
951: #if defined(HAVE_SO_MAX_PACING_RATE)
952: test->no_fq_socket_pacing = 1;
953: #else /* HAVE_SO_MAX_PACING_RATE */
954: i_errno = IEUNIMP;
955: return -1;
956: #endif
957: break;
958: case 'h':
959: default:
960: usage_long();
961: exit(1);
962: }
963: }
964:
965: /* Set logging to a file if specified, otherwise use the default (stdout) */
966: if (test->logfile) {
967: test->outfile = fopen(test->logfile, "a+");
968: if (test->outfile == NULL) {
969: i_errno = IELOGFILE;
970: return -1;
971: }
972: }
973:
974: /* Check flag / role compatibility. */
975: if (test->role == 'c' && server_flag) {
976: i_errno = IESERVERONLY;
977: return -1;
978: }
979: if (test->role == 's' && client_flag) {
980: i_errno = IECLIENTONLY;
981: return -1;
982: }
983:
984: if (!test->bind_address && test->bind_port) {
985: i_errno = IEBIND;
986: return -1;
987: }
988: if (blksize == 0) {
989: if (test->protocol->id == Pudp)
990: blksize = DEFAULT_UDP_BLKSIZE;
991: else if (test->protocol->id == Psctp)
992: blksize = DEFAULT_SCTP_BLKSIZE;
993: else
994: blksize = DEFAULT_TCP_BLKSIZE;
995: }
996: if (blksize <= 0 || blksize > MAX_BLOCKSIZE) {
997: i_errno = IEBLOCKSIZE;
998: return -1;
999: }
1000: if (test->protocol->id == Pudp &&
1001: blksize > MAX_UDP_BLOCKSIZE) {
1002: i_errno = IEUDPBLOCKSIZE;
1003: return -1;
1004: }
1005: test->settings->blksize = blksize;
1006:
1007: if (!rate_flag)
1008: test->settings->rate = test->protocol->id == Pudp ? UDP_RATE : 0;
1009:
1010: if ((test->settings->bytes != 0 || test->settings->blocks != 0) && ! duration_flag)
1011: test->duration = 0;
1012:
1013: /* Disallow specifying multiple test end conditions. The code actually
1014: ** works just fine without this prohibition. As soon as any one of the
1015: ** three possible end conditions is met, the test ends. So this check
1016: ** could be removed if desired.
1017: */
1018: if ((duration_flag && test->settings->bytes != 0) ||
1019: (duration_flag && test->settings->blocks != 0) ||
1020: (test->settings->bytes != 0 && test->settings->blocks != 0)) {
1021: i_errno = IEENDCONDITIONS;
1022: return -1;
1023: }
1024:
1025: /* For subsequent calls to getopt */
1026: #ifdef __APPLE__
1027: optreset = 1;
1028: #endif
1029: optind = 0;
1030:
1031: if ((test->role != 'c') && (test->role != 's')) {
1032: i_errno = IENOROLE;
1033: return -1;
1034: }
1035:
1036: return 0;
1037: }
1038:
1039: int
1040: iperf_set_send_state(struct iperf_test *test, signed char state)
1041: {
1042: test->state = state;
1043: if (Nwrite(test->ctrl_sck, (char*) &state, sizeof(state), Ptcp) < 0) {
1044: i_errno = IESENDMESSAGE;
1045: return -1;
1046: }
1047: return 0;
1048: }
1049:
1050: void
1051: iperf_check_throttle(struct iperf_stream *sp, struct timeval *nowP)
1052: {
1053: double seconds;
1054: uint64_t bits_per_second;
1055:
1056: if (sp->test->done)
1057: return;
1058: seconds = timeval_diff(&sp->result->start_time_fixed, nowP);
1059: bits_per_second = sp->result->bytes_sent * 8 / seconds;
1060: if (bits_per_second < sp->test->settings->rate) {
1061: sp->green_light = 1;
1062: FD_SET(sp->socket, &sp->test->write_set);
1063: } else {
1064: sp->green_light = 0;
1065: FD_CLR(sp->socket, &sp->test->write_set);
1066: }
1067: }
1068:
1069: int
1070: iperf_send(struct iperf_test *test, fd_set *write_setP)
1071: {
1072: register int multisend, r, streams_active;
1073: register struct iperf_stream *sp;
1074: struct timeval now;
1075:
1076: /* Can we do multisend mode? */
1077: if (test->settings->burst != 0)
1078: multisend = test->settings->burst;
1079: else if (test->settings->rate == 0)
1080: multisend = test->multisend;
1081: else
1082: multisend = 1; /* nope */
1083:
1084: for (; multisend > 0; --multisend) {
1085: if (test->settings->rate != 0 && test->settings->burst == 0)
1086: gettimeofday(&now, NULL);
1087: streams_active = 0;
1088: SLIST_FOREACH(sp, &test->streams, streams) {
1089: if (! test->no_fq_socket_pacing ||
1090: (sp->green_light &&
1091: (write_setP == NULL || FD_ISSET(sp->socket, write_setP)))) {
1092: if ((r = sp->snd(sp)) < 0) {
1093: if (r == NET_SOFTERROR)
1094: break;
1095: i_errno = IESTREAMWRITE;
1096: return r;
1097: }
1098: streams_active = 1;
1099: test->bytes_sent += r;
1100: ++test->blocks_sent;
1101: if (test->settings->rate != 0 && test->settings->burst == 0)
1102: iperf_check_throttle(sp, &now);
1103: if (multisend > 1 && test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes)
1104: break;
1105: if (multisend > 1 && test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks)
1106: break;
1107: }
1108: }
1109: if (!streams_active)
1110: break;
1111: }
1112: if (test->settings->burst != 0) {
1113: gettimeofday(&now, NULL);
1114: SLIST_FOREACH(sp, &test->streams, streams)
1115: iperf_check_throttle(sp, &now);
1116: }
1117: if (write_setP != NULL)
1118: SLIST_FOREACH(sp, &test->streams, streams)
1119: if (FD_ISSET(sp->socket, write_setP))
1120: FD_CLR(sp->socket, write_setP);
1121:
1122: return 0;
1123: }
1124:
1125: int
1126: iperf_recv(struct iperf_test *test, fd_set *read_setP)
1127: {
1128: int r;
1129: struct iperf_stream *sp;
1130:
1131: SLIST_FOREACH(sp, &test->streams, streams) {
1132: if (FD_ISSET(sp->socket, read_setP)) {
1133: if ((r = sp->rcv(sp)) < 0) {
1134: i_errno = IESTREAMREAD;
1135: return r;
1136: }
1137: test->bytes_sent += r;
1138: ++test->blocks_sent;
1139: FD_CLR(sp->socket, read_setP);
1140: }
1141: }
1142:
1143: return 0;
1144: }
1145:
1146: int
1147: iperf_init_test(struct iperf_test *test)
1148: {
1149: struct timeval now;
1150: struct iperf_stream *sp;
1151:
1152: if (test->protocol->init) {
1153: if (test->protocol->init(test) < 0)
1154: return -1;
1155: }
1156:
1157: /* Init each stream. */
1158: if (gettimeofday(&now, NULL) < 0) {
1159: i_errno = IEINITTEST;
1160: return -1;
1161: }
1162: SLIST_FOREACH(sp, &test->streams, streams) {
1163: sp->result->start_time = sp->result->start_time_fixed = now;
1164: }
1165:
1166: if (test->on_test_start)
1167: test->on_test_start(test);
1168:
1169: return 0;
1170: }
1171:
1172: static void
1173: send_timer_proc(TimerClientData client_data, struct timeval *nowP)
1174: {
1175: struct iperf_stream *sp = client_data.p;
1176:
1177: /* All we do here is set or clear the flag saying that this stream may
1178: ** be sent to. The actual sending gets done in the send proc, after
1179: ** checking the flag.
1180: */
1181: iperf_check_throttle(sp, nowP);
1182: }
1183:
1184: int
1185: iperf_create_send_timers(struct iperf_test * test)
1186: {
1187: struct timeval now;
1188: struct iperf_stream *sp;
1189: TimerClientData cd;
1190:
1191: if (gettimeofday(&now, NULL) < 0) {
1192: i_errno = IEINITTEST;
1193: return -1;
1194: }
1195: SLIST_FOREACH(sp, &test->streams, streams) {
1196: sp->green_light = 1;
1197: if (test->settings->rate != 0) {
1198: cd.p = sp;
1199: sp->send_timer = tmr_create((struct timeval*) 0, send_timer_proc, cd, 100000L, 1);
1200: /* (Repeat every tenth second - arbitrary often value.) */
1201: if (sp->send_timer == NULL) {
1202: i_errno = IEINITTEST;
1203: return -1;
1204: }
1205: }
1206: }
1207: return 0;
1208: }
1209:
1210: /**
1211: * iperf_exchange_parameters - handles the param_Exchange part for client
1212: *
1213: */
1214:
1215: int
1216: iperf_exchange_parameters(struct iperf_test *test)
1217: {
1218: int s;
1219: int32_t err;
1220:
1221: if (test->role == 'c') {
1222:
1223: if (send_parameters(test) < 0)
1224: return -1;
1225:
1226: } else {
1227:
1228: if (get_parameters(test) < 0)
1229: return -1;
1230:
1231: if ((s = test->protocol->listen(test)) < 0) {
1232: if (iperf_set_send_state(test, SERVER_ERROR) != 0)
1233: return -1;
1234: err = htonl(i_errno);
1235: if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
1236: i_errno = IECTRLWRITE;
1237: return -1;
1238: }
1239: err = htonl(errno);
1240: if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
1241: i_errno = IECTRLWRITE;
1242: return -1;
1243: }
1244: return -1;
1245: }
1246: FD_SET(s, &test->read_set);
1247: test->max_fd = (s > test->max_fd) ? s : test->max_fd;
1248: test->prot_listener = s;
1249:
1250: // Send the control message to create streams and start the test
1251: if (iperf_set_send_state(test, CREATE_STREAMS) != 0)
1252: return -1;
1253:
1254: }
1255:
1256: return 0;
1257: }
1258:
1259: /*************************************************************/
1260:
1261: int
1262: iperf_exchange_results(struct iperf_test *test)
1263: {
1264: if (test->role == 'c') {
1265: /* Send results to server. */
1266: if (send_results(test) < 0)
1267: return -1;
1268: /* Get server results. */
1269: if (get_results(test) < 0)
1270: return -1;
1271: } else {
1272: /* Get client results. */
1273: if (get_results(test) < 0)
1274: return -1;
1275: /* Send results to client. */
1276: if (send_results(test) < 0)
1277: return -1;
1278: }
1279: return 0;
1280: }
1281:
1282: /*************************************************************/
1283:
1284: static int
1285: send_parameters(struct iperf_test *test)
1286: {
1287: int r = 0;
1288: cJSON *j;
1289:
1290: j = cJSON_CreateObject();
1291: if (j == NULL) {
1292: i_errno = IESENDPARAMS;
1293: r = -1;
1294: } else {
1295: if (test->protocol->id == Ptcp)
1296: cJSON_AddTrueToObject(j, "tcp");
1297: else if (test->protocol->id == Pudp)
1298: cJSON_AddTrueToObject(j, "udp");
1299: else if (test->protocol->id == Psctp)
1300: cJSON_AddTrueToObject(j, "sctp");
1301: cJSON_AddNumberToObject(j, "omit", test->omit);
1302: if (test->server_affinity != -1)
1303: cJSON_AddNumberToObject(j, "server_affinity", test->server_affinity);
1304: if (test->duration)
1305: cJSON_AddNumberToObject(j, "time", test->duration);
1306: if (test->settings->bytes)
1307: cJSON_AddNumberToObject(j, "num", test->settings->bytes);
1308: if (test->settings->blocks)
1309: cJSON_AddNumberToObject(j, "blockcount", test->settings->blocks);
1310: if (test->settings->mss)
1311: cJSON_AddNumberToObject(j, "MSS", test->settings->mss);
1312: if (test->no_delay)
1313: cJSON_AddTrueToObject(j, "nodelay");
1314: cJSON_AddNumberToObject(j, "parallel", test->num_streams);
1315: if (test->reverse)
1316: cJSON_AddTrueToObject(j, "reverse");
1317: if (test->settings->socket_bufsize)
1318: cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);
1319: if (test->settings->blksize)
1320: cJSON_AddNumberToObject(j, "len", test->settings->blksize);
1321: if (test->settings->rate)
1322: cJSON_AddNumberToObject(j, "bandwidth", test->settings->rate);
1323: if (test->settings->burst)
1324: cJSON_AddNumberToObject(j, "burst", test->settings->burst);
1325: if (test->settings->tos)
1326: cJSON_AddNumberToObject(j, "TOS", test->settings->tos);
1327: if (test->settings->flowlabel)
1328: cJSON_AddNumberToObject(j, "flowlabel", test->settings->flowlabel);
1329: if (test->title)
1330: cJSON_AddStringToObject(j, "title", test->title);
1331: if (test->congestion)
1332: cJSON_AddStringToObject(j, "congestion", test->congestion);
1333: if (test->get_server_output)
1334: cJSON_AddNumberToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
1335: if (test->udp_counters_64bit)
1336: cJSON_AddNumberToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));
1337: if (test->no_fq_socket_pacing)
1338: cJSON_AddNumberToObject(j, "no_fq_socket_pacing", iperf_get_no_fq_socket_pacing(test));
1339:
1340: cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);
1341:
1342: if (test->debug) {
1343: printf("send_parameters:\n%s\n", cJSON_Print(j));
1344: }
1345:
1346: if (JSON_write(test->ctrl_sck, j) < 0) {
1347: i_errno = IESENDPARAMS;
1348: r = -1;
1349: }
1350: cJSON_Delete(j);
1351: }
1352: return r;
1353: }
1354:
1355: /*************************************************************/
1356:
1357: static int
1358: get_parameters(struct iperf_test *test)
1359: {
1360: int r = 0;
1361: cJSON *j;
1362: cJSON *j_p;
1363:
1364: j = JSON_read(test->ctrl_sck);
1365: if (j == NULL) {
1366: i_errno = IERECVPARAMS;
1367: r = -1;
1368: } else {
1369: if (test->debug) {
1370: printf("get_parameters:\n%s\n", cJSON_Print(j));
1371: }
1372:
1373: if ((j_p = cJSON_GetObjectItem(j, "tcp")) != NULL)
1374: set_protocol(test, Ptcp);
1375: if ((j_p = cJSON_GetObjectItem(j, "udp")) != NULL)
1376: set_protocol(test, Pudp);
1377: if ((j_p = cJSON_GetObjectItem(j, "sctp")) != NULL)
1378: set_protocol(test, Psctp);
1379: if ((j_p = cJSON_GetObjectItem(j, "omit")) != NULL)
1380: test->omit = j_p->valueint;
1381: if ((j_p = cJSON_GetObjectItem(j, "server_affinity")) != NULL)
1382: test->server_affinity = j_p->valueint;
1383: if ((j_p = cJSON_GetObjectItem(j, "time")) != NULL)
1384: test->duration = j_p->valueint;
1385: if ((j_p = cJSON_GetObjectItem(j, "num")) != NULL)
1386: test->settings->bytes = j_p->valueint;
1387: if ((j_p = cJSON_GetObjectItem(j, "blockcount")) != NULL)
1388: test->settings->blocks = j_p->valueint;
1389: if ((j_p = cJSON_GetObjectItem(j, "MSS")) != NULL)
1390: test->settings->mss = j_p->valueint;
1391: if ((j_p = cJSON_GetObjectItem(j, "nodelay")) != NULL)
1392: test->no_delay = 1;
1393: if ((j_p = cJSON_GetObjectItem(j, "parallel")) != NULL)
1394: test->num_streams = j_p->valueint;
1395: if ((j_p = cJSON_GetObjectItem(j, "reverse")) != NULL)
1396: iperf_set_test_reverse(test, 1);
1397: if ((j_p = cJSON_GetObjectItem(j, "window")) != NULL)
1398: test->settings->socket_bufsize = j_p->valueint;
1399: if ((j_p = cJSON_GetObjectItem(j, "len")) != NULL)
1400: test->settings->blksize = j_p->valueint;
1401: if ((j_p = cJSON_GetObjectItem(j, "bandwidth")) != NULL)
1402: test->settings->rate = j_p->valueint;
1403: if ((j_p = cJSON_GetObjectItem(j, "burst")) != NULL)
1404: test->settings->burst = j_p->valueint;
1405: if ((j_p = cJSON_GetObjectItem(j, "TOS")) != NULL)
1406: test->settings->tos = j_p->valueint;
1407: if ((j_p = cJSON_GetObjectItem(j, "flowlabel")) != NULL)
1408: test->settings->flowlabel = j_p->valueint;
1409: if ((j_p = cJSON_GetObjectItem(j, "title")) != NULL)
1410: test->title = strdup(j_p->valuestring);
1411: if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL)
1412: test->congestion = strdup(j_p->valuestring);
1413: if ((j_p = cJSON_GetObjectItem(j, "get_server_output")) != NULL)
1414: iperf_set_test_get_server_output(test, 1);
1415: if ((j_p = cJSON_GetObjectItem(j, "udp_counters_64bit")) != NULL)
1416: iperf_set_test_udp_counters_64bit(test, 1);
1417: if ((j_p = cJSON_GetObjectItem(j, "no_fq_socket_pacing")) != NULL)
1418: iperf_set_no_fq_socket_pacing(test, 1);
1419:
1420: if (test->sender && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
1421: test->sender_has_retransmits = 1;
1422: cJSON_Delete(j);
1423: }
1424: return r;
1425: }
1426:
1427: /*************************************************************/
1428:
1429: static int
1430: send_results(struct iperf_test *test)
1431: {
1432: int r = 0;
1433: cJSON *j;
1434: cJSON *j_streams;
1435: struct iperf_stream *sp;
1436: cJSON *j_stream;
1437: int sender_has_retransmits;
1438: iperf_size_t bytes_transferred;
1439: int retransmits;
1440:
1441: j = cJSON_CreateObject();
1442: if (j == NULL) {
1443: i_errno = IEPACKAGERESULTS;
1444: r = -1;
1445: } else {
1446: cJSON_AddNumberToObject(j, "cpu_util_total", test->cpu_util[0]);
1447: cJSON_AddNumberToObject(j, "cpu_util_user", test->cpu_util[1]);
1448: cJSON_AddNumberToObject(j, "cpu_util_system", test->cpu_util[2]);
1449: if ( ! test->sender )
1450: sender_has_retransmits = -1;
1451: else
1452: sender_has_retransmits = test->sender_has_retransmits;
1453: cJSON_AddNumberToObject(j, "sender_has_retransmits", sender_has_retransmits);
1454:
1455: /* If on the server and sending server output, then do this */
1456: if (test->role == 's' && test->get_server_output) {
1457: if (test->json_output) {
1458: /* Add JSON output */
1459: cJSON_AddItemReferenceToObject(j, "server_output_json", test->json_top);
1460: }
1461: else {
1462: /* Add textual output */
1463: size_t buflen = 0;
1464:
1465: /* Figure out how much room we need to hold the complete output string */
1466: struct iperf_textline *t;
1467: TAILQ_FOREACH(t, &(test->server_output_list), textlineentries) {
1468: buflen += strlen(t->line);
1469: }
1470:
1471: /* Allocate and build it up from the component lines */
1472: char *output = calloc(buflen + 1, 1);
1473: TAILQ_FOREACH(t, &(test->server_output_list), textlineentries) {
1474: strncat(output, t->line, buflen);
1475: buflen -= strlen(t->line);
1476: }
1477:
1478: cJSON_AddStringToObject(j, "server_output_text", output);
1479: }
1480: }
1481:
1482: j_streams = cJSON_CreateArray();
1483: if (j_streams == NULL) {
1484: i_errno = IEPACKAGERESULTS;
1485: r = -1;
1486: } else {
1487: cJSON_AddItemToObject(j, "streams", j_streams);
1488: SLIST_FOREACH(sp, &test->streams, streams) {
1489: j_stream = cJSON_CreateObject();
1490: if (j_stream == NULL) {
1491: i_errno = IEPACKAGERESULTS;
1492: r = -1;
1493: } else {
1494: cJSON_AddItemToArray(j_streams, j_stream);
1495: bytes_transferred = test->sender ? (sp->result->bytes_sent - sp->result->bytes_sent_omit) : sp->result->bytes_received;
1496: retransmits = (test->sender && test->sender_has_retransmits) ? sp->result->stream_retrans : -1;
1497: cJSON_AddNumberToObject(j_stream, "id", sp->id);
1498: cJSON_AddNumberToObject(j_stream, "bytes", bytes_transferred);
1499: cJSON_AddNumberToObject(j_stream, "retransmits", retransmits);
1500: cJSON_AddNumberToObject(j_stream, "jitter", sp->jitter);
1501: cJSON_AddNumberToObject(j_stream, "errors", sp->cnt_error);
1502: cJSON_AddNumberToObject(j_stream, "packets", sp->packet_count);
1503: }
1504: }
1505: if (r == 0 && test->debug) {
1506: printf("send_results\n%s\n", cJSON_Print(j));
1507: }
1508: if (r == 0 && JSON_write(test->ctrl_sck, j) < 0) {
1509: i_errno = IESENDRESULTS;
1510: r = -1;
1511: }
1512: }
1513: cJSON_Delete(j);
1514: }
1515: return r;
1516: }
1517:
1518: /*************************************************************/
1519:
1520: static int
1521: get_results(struct iperf_test *test)
1522: {
1523: int r = 0;
1524: cJSON *j;
1525: cJSON *j_cpu_util_total;
1526: cJSON *j_cpu_util_user;
1527: cJSON *j_cpu_util_system;
1528: cJSON *j_sender_has_retransmits;
1529: int result_has_retransmits;
1530: cJSON *j_streams;
1531: int n, i;
1532: cJSON *j_stream;
1533: cJSON *j_id;
1534: cJSON *j_bytes;
1535: cJSON *j_retransmits;
1536: cJSON *j_jitter;
1537: cJSON *j_errors;
1538: cJSON *j_packets;
1539: cJSON *j_server_output;
1540: int sid, cerror, pcount;
1541: double jitter;
1542: iperf_size_t bytes_transferred;
1543: int retransmits;
1544: struct iperf_stream *sp;
1545:
1546: j = JSON_read(test->ctrl_sck);
1547: if (j == NULL) {
1548: i_errno = IERECVRESULTS;
1549: r = -1;
1550: } else {
1551: j_cpu_util_total = cJSON_GetObjectItem(j, "cpu_util_total");
1552: j_cpu_util_user = cJSON_GetObjectItem(j, "cpu_util_user");
1553: j_cpu_util_system = cJSON_GetObjectItem(j, "cpu_util_system");
1554: j_sender_has_retransmits = cJSON_GetObjectItem(j, "sender_has_retransmits");
1555: if (j_cpu_util_total == NULL || j_cpu_util_user == NULL || j_cpu_util_system == NULL || j_sender_has_retransmits == NULL) {
1556: i_errno = IERECVRESULTS;
1557: r = -1;
1558: } else {
1559: if (test->debug) {
1560: printf("get_results\n%s\n", cJSON_Print(j));
1561: }
1562:
1563: test->remote_cpu_util[0] = j_cpu_util_total->valuedouble;
1564: test->remote_cpu_util[1] = j_cpu_util_user->valuedouble;
1565: test->remote_cpu_util[2] = j_cpu_util_system->valuedouble;
1566: result_has_retransmits = j_sender_has_retransmits->valueint;
1567: if (! test->sender)
1568: test->sender_has_retransmits = result_has_retransmits;
1569: j_streams = cJSON_GetObjectItem(j, "streams");
1570: if (j_streams == NULL) {
1571: i_errno = IERECVRESULTS;
1572: r = -1;
1573: } else {
1574: n = cJSON_GetArraySize(j_streams);
1575: for (i=0; i<n; ++i) {
1576: j_stream = cJSON_GetArrayItem(j_streams, i);
1577: if (j_stream == NULL) {
1578: i_errno = IERECVRESULTS;
1579: r = -1;
1580: } else {
1581: j_id = cJSON_GetObjectItem(j_stream, "id");
1582: j_bytes = cJSON_GetObjectItem(j_stream, "bytes");
1583: j_retransmits = cJSON_GetObjectItem(j_stream, "retransmits");
1584: j_jitter = cJSON_GetObjectItem(j_stream, "jitter");
1585: j_errors = cJSON_GetObjectItem(j_stream, "errors");
1586: j_packets = cJSON_GetObjectItem(j_stream, "packets");
1587: if (j_id == NULL || j_bytes == NULL || j_retransmits == NULL || j_jitter == NULL || j_errors == NULL || j_packets == NULL) {
1588: i_errno = IERECVRESULTS;
1589: r = -1;
1590: } else {
1591: sid = j_id->valueint;
1592: bytes_transferred = j_bytes->valueint;
1593: retransmits = j_retransmits->valueint;
1594: jitter = j_jitter->valuedouble;
1595: cerror = j_errors->valueint;
1596: pcount = j_packets->valueint;
1597: SLIST_FOREACH(sp, &test->streams, streams)
1598: if (sp->id == sid) break;
1599: if (sp == NULL) {
1600: i_errno = IESTREAMID;
1601: r = -1;
1602: } else {
1603: if (test->sender) {
1604: sp->jitter = jitter;
1605: sp->cnt_error = cerror;
1606: sp->packet_count = pcount;
1607: sp->result->bytes_received = bytes_transferred;
1608: } else {
1609: sp->result->bytes_sent = bytes_transferred;
1610: sp->result->stream_retrans = retransmits;
1611: }
1612: }
1613: }
1614: }
1615: }
1616: /*
1617: * If we're the client and we're supposed to get remote results,
1618: * look them up and process accordingly.
1619: */
1620: if (test->role == 'c' && iperf_get_test_get_server_output(test)) {
1621: /* Look for JSON. If we find it, grab the object so it doesn't get deleted. */
1622: j_server_output = cJSON_DetachItemFromObject(j, "server_output_json");
1623: if (j_server_output != NULL) {
1624: test->json_server_output = j_server_output;
1625: }
1626: else {
1627: /* No JSON, look for textual output. Make a copy of the text for later. */
1628: j_server_output = cJSON_GetObjectItem(j, "server_output_text");
1629: if (j_server_output != NULL) {
1630: test->server_output_text = strdup(j_server_output->valuestring);
1631: }
1632: }
1633: }
1634: }
1635: }
1636: cJSON_Delete(j);
1637: }
1638: return r;
1639: }
1640:
1641: /*************************************************************/
1642:
1643: static int
1644: JSON_write(int fd, cJSON *json)
1645: {
1646: uint32_t hsize, nsize;
1647: char *str;
1648: int r = 0;
1649:
1650: str = cJSON_PrintUnformatted(json);
1651: if (str == NULL)
1652: r = -1;
1653: else {
1654: hsize = strlen(str);
1655: nsize = htonl(hsize);
1656: if (Nwrite(fd, (char*) &nsize, sizeof(nsize), Ptcp) < 0)
1657: r = -1;
1658: else {
1659: if (Nwrite(fd, str, hsize, Ptcp) < 0)
1660: r = -1;
1661: }
1662: free(str);
1663: }
1664: return r;
1665: }
1666:
1667: /*************************************************************/
1668:
1669: static cJSON *
1670: JSON_read(int fd)
1671: {
1672: uint32_t hsize, nsize;
1673: char *str;
1674: cJSON *json = NULL;
1675: int rc;
1676:
1677: /*
1678: * Read a four-byte integer, which is the length of the JSON to follow.
1679: * Then read the JSON into a buffer and parse it. Return a parsed JSON
1680: * structure, NULL if there was an error.
1681: */
1682: if (Nread(fd, (char*) &nsize, sizeof(nsize), Ptcp) >= 0) {
1683: hsize = ntohl(nsize);
1684: /* Allocate a buffer to hold the JSON */
1685: str = (char *) calloc(sizeof(char), hsize+1); /* +1 for trailing null */
1686: if (str != NULL) {
1687: rc = Nread(fd, str, hsize, Ptcp);
1688: if (rc >= 0) {
1689: /*
1690: * We should be reading in the number of bytes corresponding to the
1691: * length in that 4-byte integer. If we don't the socket might have
1692: * prematurely closed. Only do the JSON parsing if we got the
1693: * correct number of bytes.
1694: */
1695: if (rc == hsize) {
1696: json = cJSON_Parse(str);
1697: }
1698: else {
1699: printf("WARNING: Size of data read does not correspond to offered length\n");
1700: }
1701: }
1702: }
1703: free(str);
1704: }
1705: return json;
1706: }
1707:
1708: /*************************************************************/
1709: /**
1710: * add_to_interval_list -- adds new interval to the interval_list
1711: */
1712:
1713: void
1714: add_to_interval_list(struct iperf_stream_result * rp, struct iperf_interval_results * new)
1715: {
1716: struct iperf_interval_results *irp;
1717:
1718: irp = (struct iperf_interval_results *) malloc(sizeof(struct iperf_interval_results));
1719: memcpy(irp, new, sizeof(struct iperf_interval_results));
1720: TAILQ_INSERT_TAIL(&rp->interval_results, irp, irlistentries);
1721: }
1722:
1723:
1724: /************************************************************/
1725:
1726: /**
1727: * connect_msg -- displays connection message
1728: * denoting sender/receiver details
1729: *
1730: */
1731:
1732: void
1733: connect_msg(struct iperf_stream *sp)
1734: {
1735: char ipl[INET6_ADDRSTRLEN], ipr[INET6_ADDRSTRLEN];
1736: int lport, rport;
1737:
1738: if (getsockdomain(sp->socket) == AF_INET) {
1739: inet_ntop(AF_INET, (void *) &((struct sockaddr_in *) &sp->local_addr)->sin_addr, ipl, sizeof(ipl));
1740: mapped_v4_to_regular_v4(ipl);
1741: inet_ntop(AF_INET, (void *) &((struct sockaddr_in *) &sp->remote_addr)->sin_addr, ipr, sizeof(ipr));
1742: mapped_v4_to_regular_v4(ipr);
1743: lport = ntohs(((struct sockaddr_in *) &sp->local_addr)->sin_port);
1744: rport = ntohs(((struct sockaddr_in *) &sp->remote_addr)->sin_port);
1745: } else {
1746: inet_ntop(AF_INET6, (void *) &((struct sockaddr_in6 *) &sp->local_addr)->sin6_addr, ipl, sizeof(ipl));
1747: mapped_v4_to_regular_v4(ipl);
1748: inet_ntop(AF_INET6, (void *) &((struct sockaddr_in6 *) &sp->remote_addr)->sin6_addr, ipr, sizeof(ipr));
1749: mapped_v4_to_regular_v4(ipr);
1750: lport = ntohs(((struct sockaddr_in6 *) &sp->local_addr)->sin6_port);
1751: rport = ntohs(((struct sockaddr_in6 *) &sp->remote_addr)->sin6_port);
1752: }
1753:
1754: if (sp->test->json_output)
1755: 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));
1756: else
1757: iprintf(sp->test, report_connected, sp->socket, ipl, lport, ipr, rport);
1758: }
1759:
1760:
1761: /**************************************************************************/
1762:
1763: struct iperf_test *
1764: iperf_new_test()
1765: {
1766: struct iperf_test *test;
1767:
1768: test = (struct iperf_test *) malloc(sizeof(struct iperf_test));
1769: if (!test) {
1770: i_errno = IENEWTEST;
1771: return NULL;
1772: }
1773: /* initialize everything to zero */
1774: memset(test, 0, sizeof(struct iperf_test));
1775:
1776: test->settings = (struct iperf_settings *) malloc(sizeof(struct iperf_settings));
1777: if (!test->settings) {
1778: free(test);
1779: i_errno = IENEWTEST;
1780: return NULL;
1781: }
1782: memset(test->settings, 0, sizeof(struct iperf_settings));
1783:
1784: /* By default all output goes to stdout */
1785: test->outfile = stdout;
1786:
1787: return test;
1788: }
1789:
1790: /**************************************************************************/
1791:
1792: struct protocol *
1793: protocol_new(void)
1794: {
1795: struct protocol *proto;
1796:
1797: proto = malloc(sizeof(struct protocol));
1798: if(!proto) {
1799: return NULL;
1800: }
1801: memset(proto, 0, sizeof(struct protocol));
1802:
1803: return proto;
1804: }
1805:
1806: void
1807: protocol_free(struct protocol *proto)
1808: {
1809: free(proto);
1810: }
1811:
1812: /**************************************************************************/
1813: int
1814: iperf_defaults(struct iperf_test *testp)
1815: {
1816: struct protocol *tcp, *udp;
1817: #if defined(HAVE_SCTP)
1818: struct protocol *sctp;
1819: #endif /* HAVE_SCTP */
1820:
1821: testp->omit = OMIT;
1822: testp->duration = DURATION;
1823: testp->diskfile_name = (char*) 0;
1824: testp->affinity = -1;
1825: testp->server_affinity = -1;
1826: TAILQ_INIT(&testp->xbind_addrs);
1827: #if defined(HAVE_CPUSET_SETAFFINITY)
1828: CPU_ZERO(&testp->cpumask);
1829: #endif /* HAVE_CPUSET_SETAFFINITY */
1830: testp->title = NULL;
1831: testp->congestion = NULL;
1832: testp->server_port = PORT;
1833: testp->ctrl_sck = -1;
1834: testp->prot_listener = -1;
1835:
1836: testp->stats_callback = iperf_stats_callback;
1837: testp->reporter_callback = iperf_reporter_callback;
1838:
1839: testp->stats_interval = testp->reporter_interval = 1;
1840: testp->num_streams = 1;
1841:
1842: testp->settings->domain = AF_UNSPEC;
1843: testp->settings->unit_format = 'a';
1844: testp->settings->socket_bufsize = 0; /* use autotuning */
1845: testp->settings->blksize = DEFAULT_TCP_BLKSIZE;
1846: testp->settings->rate = 0;
1847: testp->settings->burst = 0;
1848: testp->settings->mss = 0;
1849: testp->settings->bytes = 0;
1850: testp->settings->blocks = 0;
1851: memset(testp->cookie, 0, COOKIE_SIZE);
1852:
1853: testp->multisend = 10; /* arbitrary */
1854:
1855: /* Set up protocol list */
1856: SLIST_INIT(&testp->streams);
1857: SLIST_INIT(&testp->protocols);
1858:
1859: tcp = protocol_new();
1860: if (!tcp)
1861: return -1;
1862:
1863: tcp->id = Ptcp;
1864: tcp->name = "TCP";
1865: tcp->accept = iperf_tcp_accept;
1866: tcp->listen = iperf_tcp_listen;
1867: tcp->connect = iperf_tcp_connect;
1868: tcp->send = iperf_tcp_send;
1869: tcp->recv = iperf_tcp_recv;
1870: tcp->init = NULL;
1871: SLIST_INSERT_HEAD(&testp->protocols, tcp, protocols);
1872:
1873: udp = protocol_new();
1874: if (!udp) {
1875: protocol_free(tcp);
1876: return -1;
1877: }
1878:
1879: udp->id = Pudp;
1880: udp->name = "UDP";
1881: udp->accept = iperf_udp_accept;
1882: udp->listen = iperf_udp_listen;
1883: udp->connect = iperf_udp_connect;
1884: udp->send = iperf_udp_send;
1885: udp->recv = iperf_udp_recv;
1886: udp->init = iperf_udp_init;
1887: SLIST_INSERT_AFTER(tcp, udp, protocols);
1888:
1889: set_protocol(testp, Ptcp);
1890:
1891: #if defined(HAVE_SCTP)
1892: sctp = protocol_new();
1893: if (!sctp) {
1894: protocol_free(tcp);
1895: protocol_free(udp);
1896: return -1;
1897: }
1898:
1899: sctp->id = Psctp;
1900: sctp->name = "SCTP";
1901: sctp->accept = iperf_sctp_accept;
1902: sctp->listen = iperf_sctp_listen;
1903: sctp->connect = iperf_sctp_connect;
1904: sctp->send = iperf_sctp_send;
1905: sctp->recv = iperf_sctp_recv;
1906: sctp->init = iperf_sctp_init;
1907:
1908: SLIST_INSERT_AFTER(udp, sctp, protocols);
1909: #endif /* HAVE_SCTP */
1910:
1911: testp->on_new_stream = iperf_on_new_stream;
1912: testp->on_test_start = iperf_on_test_start;
1913: testp->on_connect = iperf_on_connect;
1914: testp->on_test_finish = iperf_on_test_finish;
1915:
1916: TAILQ_INIT(&testp->server_output_list);
1917:
1918: return 0;
1919: }
1920:
1921:
1922: /**************************************************************************/
1923: void
1924: iperf_free_test(struct iperf_test *test)
1925: {
1926: struct protocol *prot;
1927: struct iperf_stream *sp;
1928:
1929: /* Free streams */
1930: while (!SLIST_EMPTY(&test->streams)) {
1931: sp = SLIST_FIRST(&test->streams);
1932: SLIST_REMOVE_HEAD(&test->streams, streams);
1933: iperf_free_stream(sp);
1934: }
1935:
1936: if (test->server_hostname)
1937: free(test->server_hostname);
1938: if (test->tmp_template)
1939: free(test->tmp_template);
1940: if (test->bind_address)
1941: free(test->bind_address);
1942: if (!TAILQ_EMPTY(&test->xbind_addrs)) {
1943: struct xbind_entry *xbe;
1944:
1945: while (!TAILQ_EMPTY(&test->xbind_addrs)) {
1946: xbe = TAILQ_FIRST(&test->xbind_addrs);
1947: TAILQ_REMOVE(&test->xbind_addrs, xbe, link);
1948: if (xbe->ai)
1949: freeaddrinfo(xbe->ai);
1950: free(xbe->name);
1951: free(xbe);
1952: }
1953: }
1954: if (test->settings)
1955: free(test->settings);
1956: if (test->title)
1957: free(test->title);
1958: if (test->congestion)
1959: free(test->congestion);
1960: if (test->omit_timer != NULL)
1961: tmr_cancel(test->omit_timer);
1962: if (test->timer != NULL)
1963: tmr_cancel(test->timer);
1964: if (test->stats_timer != NULL)
1965: tmr_cancel(test->stats_timer);
1966: if (test->reporter_timer != NULL)
1967: tmr_cancel(test->reporter_timer);
1968:
1969: /* Free protocol list */
1970: while (!SLIST_EMPTY(&test->protocols)) {
1971: prot = SLIST_FIRST(&test->protocols);
1972: SLIST_REMOVE_HEAD(&test->protocols, protocols);
1973: free(prot);
1974: }
1975:
1976: if (test->server_output_text) {
1977: free(test->server_output_text);
1978: test->server_output_text = NULL;
1979: }
1980:
1981: if (test->json_output_string) {
1982: free(test->json_output_string);
1983: test->json_output_string = NULL;
1984: }
1985:
1986: /* Free output line buffers, if any (on the server only) */
1987: struct iperf_textline *t;
1988: while (!TAILQ_EMPTY(&test->server_output_list)) {
1989: t = TAILQ_FIRST(&test->server_output_list);
1990: TAILQ_REMOVE(&test->server_output_list, t, textlineentries);
1991: free(t->line);
1992: free(t);
1993: }
1994:
1995: /* sctp_bindx: do not free the arguments, only the resolver results */
1996: if (!TAILQ_EMPTY(&test->xbind_addrs)) {
1997: struct xbind_entry *xbe;
1998:
1999: TAILQ_FOREACH(xbe, &test->xbind_addrs, link) {
2000: if (xbe->ai) {
2001: freeaddrinfo(xbe->ai);
2002: xbe->ai = NULL;
2003: }
2004: }
2005: }
2006:
2007: /* XXX: Why are we setting these values to NULL? */
2008: // test->streams = NULL;
2009: test->stats_callback = NULL;
2010: test->reporter_callback = NULL;
2011: free(test);
2012: }
2013:
2014:
2015: void
2016: iperf_reset_test(struct iperf_test *test)
2017: {
2018: struct iperf_stream *sp;
2019:
2020: /* Free streams */
2021: while (!SLIST_EMPTY(&test->streams)) {
2022: sp = SLIST_FIRST(&test->streams);
2023: SLIST_REMOVE_HEAD(&test->streams, streams);
2024: iperf_free_stream(sp);
2025: }
2026: if (test->omit_timer != NULL) {
2027: tmr_cancel(test->omit_timer);
2028: test->omit_timer = NULL;
2029: }
2030: if (test->timer != NULL) {
2031: tmr_cancel(test->timer);
2032: test->timer = NULL;
2033: }
2034: if (test->stats_timer != NULL) {
2035: tmr_cancel(test->stats_timer);
2036: test->stats_timer = NULL;
2037: }
2038: if (test->reporter_timer != NULL) {
2039: tmr_cancel(test->reporter_timer);
2040: test->reporter_timer = NULL;
2041: }
2042: test->done = 0;
2043:
2044: SLIST_INIT(&test->streams);
2045:
2046: test->role = 's';
2047: test->sender = 0;
2048: test->sender_has_retransmits = 0;
2049: set_protocol(test, Ptcp);
2050: test->omit = OMIT;
2051: test->duration = DURATION;
2052: test->server_affinity = -1;
2053: #if defined(HAVE_CPUSET_SETAFFINITY)
2054: CPU_ZERO(&test->cpumask);
2055: #endif /* HAVE_CPUSET_SETAFFINITY */
2056: test->state = 0;
2057:
2058: test->ctrl_sck = -1;
2059: test->prot_listener = -1;
2060:
2061: test->bytes_sent = 0;
2062: test->blocks_sent = 0;
2063:
2064: test->reverse = 0;
2065: test->no_delay = 0;
2066:
2067: FD_ZERO(&test->read_set);
2068: FD_ZERO(&test->write_set);
2069:
2070: test->num_streams = 1;
2071: test->settings->socket_bufsize = 0;
2072: test->settings->blksize = DEFAULT_TCP_BLKSIZE;
2073: test->settings->rate = 0;
2074: test->settings->burst = 0;
2075: test->settings->mss = 0;
2076: memset(test->cookie, 0, COOKIE_SIZE);
2077: test->multisend = 10; /* arbitrary */
2078: test->udp_counters_64bit = 0;
2079:
2080: /* Free output line buffers, if any (on the server only) */
2081: struct iperf_textline *t;
2082: while (!TAILQ_EMPTY(&test->server_output_list)) {
2083: t = TAILQ_FIRST(&test->server_output_list);
2084: TAILQ_REMOVE(&test->server_output_list, t, textlineentries);
2085: free(t->line);
2086: free(t);
2087: }
2088: }
2089:
2090:
2091: /* Reset all of a test's stats back to zero. Called when the omitting
2092: ** period is over.
2093: */
2094: void
2095: iperf_reset_stats(struct iperf_test *test)
2096: {
2097: struct timeval now;
2098: struct iperf_stream *sp;
2099: struct iperf_stream_result *rp;
2100:
2101: test->bytes_sent = 0;
2102: test->blocks_sent = 0;
2103: gettimeofday(&now, NULL);
2104: SLIST_FOREACH(sp, &test->streams, streams) {
2105: sp->omitted_packet_count = sp->packet_count;
2106: sp->omitted_cnt_error = sp->cnt_error;
2107: sp->omitted_outoforder_packets = sp->outoforder_packets;
2108: sp->jitter = 0;
2109: rp = sp->result;
2110: rp->bytes_sent_omit = rp->bytes_sent;
2111: rp->bytes_received = 0;
2112: rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
2113: if (test->sender && test->sender_has_retransmits) {
2114: struct iperf_interval_results ir; /* temporary results structure */
2115: save_tcpinfo(sp, &ir);
2116: rp->stream_prev_total_retrans = get_total_retransmits(&ir);
2117: }
2118: rp->stream_retrans = 0;
2119: rp->start_time = now;
2120: }
2121: }
2122:
2123:
2124: /**************************************************************************/
2125:
2126: /**
2127: * Gather statistics during a test.
2128: * This function works for both the client and server side.
2129: */
2130: void
2131: iperf_stats_callback(struct iperf_test *test)
2132: {
2133: struct iperf_stream *sp;
2134: struct iperf_stream_result *rp = NULL;
2135: struct iperf_interval_results *irp, temp;
2136:
2137: temp.omitted = test->omitting;
2138: SLIST_FOREACH(sp, &test->streams, streams) {
2139: rp = sp->result;
2140:
2141: temp.bytes_transferred = test->sender ? rp->bytes_sent_this_interval : rp->bytes_received_this_interval;
2142:
2143: irp = TAILQ_LAST(&rp->interval_results, irlisthead);
2144: /* result->end_time contains timestamp of previous interval */
2145: if ( irp != NULL ) /* not the 1st interval */
2146: memcpy(&temp.interval_start_time, &rp->end_time, sizeof(struct timeval));
2147: else /* or use timestamp from beginning */
2148: memcpy(&temp.interval_start_time, &rp->start_time, sizeof(struct timeval));
2149: /* now save time of end of this interval */
2150: gettimeofday(&rp->end_time, NULL);
2151: memcpy(&temp.interval_end_time, &rp->end_time, sizeof(struct timeval));
2152: temp.interval_duration = timeval_diff(&temp.interval_start_time, &temp.interval_end_time);
2153: //temp.interval_duration = timeval_diff(&temp.interval_start_time, &temp.interval_end_time);
2154: if (test->protocol->id == Ptcp) {
2155: if ( has_tcpinfo()) {
2156: save_tcpinfo(sp, &temp);
2157: if (test->sender && test->sender_has_retransmits) {
2158: long total_retrans = get_total_retransmits(&temp);
2159: temp.interval_retrans = total_retrans - rp->stream_prev_total_retrans;
2160: rp->stream_retrans += temp.interval_retrans;
2161: rp->stream_prev_total_retrans = total_retrans;
2162:
2163: temp.snd_cwnd = get_snd_cwnd(&temp);
2164: if (temp.snd_cwnd > rp->stream_max_snd_cwnd) {
2165: rp->stream_max_snd_cwnd = temp.snd_cwnd;
2166: }
2167:
2168: temp.rtt = get_rtt(&temp);
2169: if (temp.rtt > rp->stream_max_rtt) {
2170: rp->stream_max_rtt = temp.rtt;
2171: }
2172: if (rp->stream_min_rtt == 0 ||
2173: temp.rtt < rp->stream_min_rtt) {
2174: rp->stream_min_rtt = temp.rtt;
2175: }
2176: rp->stream_sum_rtt += temp.rtt;
2177: rp->stream_count_rtt++;
2178: }
2179: }
2180: } else {
2181: if (irp == NULL) {
2182: temp.interval_packet_count = sp->packet_count;
2183: temp.interval_outoforder_packets = sp->outoforder_packets;
2184: temp.interval_cnt_error = sp->cnt_error;
2185: } else {
2186: temp.interval_packet_count = sp->packet_count - irp->packet_count;
2187: temp.interval_outoforder_packets = sp->outoforder_packets - irp->outoforder_packets;
2188: temp.interval_cnt_error = sp->cnt_error - irp->cnt_error;
2189: }
2190: temp.packet_count = sp->packet_count;
2191: temp.jitter = sp->jitter;
2192: temp.outoforder_packets = sp->outoforder_packets;
2193: temp.cnt_error = sp->cnt_error;
2194: }
2195: add_to_interval_list(rp, &temp);
2196: rp->bytes_sent_this_interval = rp->bytes_received_this_interval = 0;
2197: }
2198: }
2199:
2200: /**
2201: * Print intermediate results during a test (interval report).
2202: * Uses print_interval_results to print the results for each stream,
2203: * then prints an interval summary for all streams in this
2204: * interval.
2205: */
2206: static void
2207: iperf_print_intermediate(struct iperf_test *test)
2208: {
2209: char ubuf[UNIT_LEN];
2210: char nbuf[UNIT_LEN];
2211: struct iperf_stream *sp = NULL;
2212: struct iperf_interval_results *irp;
2213: iperf_size_t bytes = 0;
2214: double bandwidth;
2215: int retransmits = 0;
2216: double start_time, end_time;
2217: cJSON *json_interval;
2218: cJSON *json_interval_streams;
2219: int total_packets = 0, lost_packets = 0;
2220: double avg_jitter = 0.0, lost_percent;
2221:
2222: if (test->json_output) {
2223: json_interval = cJSON_CreateObject();
2224: if (json_interval == NULL)
2225: return;
2226: cJSON_AddItemToArray(test->json_intervals, json_interval);
2227: json_interval_streams = cJSON_CreateArray();
2228: if (json_interval_streams == NULL)
2229: return;
2230: cJSON_AddItemToObject(json_interval, "streams", json_interval_streams);
2231: } else {
2232: json_interval = NULL;
2233: json_interval_streams = NULL;
2234: }
2235:
2236: SLIST_FOREACH(sp, &test->streams, streams) {
2237: print_interval_results(test, sp, json_interval_streams);
2238: /* sum up all streams */
2239: irp = TAILQ_LAST(&sp->result->interval_results, irlisthead);
2240: if (irp == NULL) {
2241: iperf_err(test, "iperf_print_intermediate error: interval_results is NULL");
2242: return;
2243: }
2244: bytes += irp->bytes_transferred;
2245: if (test->protocol->id == Ptcp) {
2246: if (test->sender && test->sender_has_retransmits) {
2247: retransmits += irp->interval_retrans;
2248: }
2249: } else {
2250: total_packets += irp->interval_packet_count;
2251: lost_packets += irp->interval_cnt_error;
2252: avg_jitter += irp->jitter;
2253: }
2254: }
2255:
2256: /* next build string with sum of all streams */
2257: if (test->num_streams > 1 || test->json_output) {
2258: sp = SLIST_FIRST(&test->streams); /* reset back to 1st stream */
2259: /* Only do this of course if there was a first stream */
2260: if (sp) {
2261: irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* use 1st stream for timing info */
2262:
2263: unit_snprintf(ubuf, UNIT_LEN, (double) bytes, 'A');
2264: bandwidth = (double) bytes / (double) irp->interval_duration;
2265: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
2266:
2267: start_time = timeval_diff(&sp->result->start_time,&irp->interval_start_time);
2268: end_time = timeval_diff(&sp->result->start_time,&irp->interval_end_time);
2269: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
2270: if (test->sender && test->sender_has_retransmits) {
2271: /* Interval sum, TCP with retransmits. */
2272: if (test->json_output)
2273: cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d omitted: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) retransmits, irp->omitted)); /* XXX irp->omitted or test->omitting? */
2274: else
2275: iprintf(test, report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, retransmits, irp->omitted?report_omitted:""); /* XXX irp->omitted or test->omitting? */
2276: } else {
2277: /* Interval sum, TCP without retransmits. */
2278: if (test->json_output)
2279: cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f omitted: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, test->omitting));
2280: else
2281: iprintf(test, report_sum_bw_format, start_time, end_time, ubuf, nbuf, test->omitting?report_omitted:"");
2282: }
2283: } else {
2284: /* Interval sum, UDP. */
2285: if (test->sender) {
2286: if (test->json_output)
2287: cJSON_AddItemToObject(json_interval, "sum", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f packets: %d omitted: %b", (double) start_time, (double) end_time, (double) irp->interval_duration, (int64_t) bytes, bandwidth * 8, (int64_t) total_packets, test->omitting));
2288: else
2289: iprintf(test, report_sum_bw_udp_sender_format, start_time, end_time, ubuf, nbuf, total_packets, test->omitting?report_omitted:"");
2290: } else {
2291: avg_jitter /= test->num_streams;
2292: if (total_packets > 0) {
2293: lost_percent = 100.0 * lost_packets / total_packets;
2294: }
2295: else {
2296: lost_percent = 0.0;
2297: }
2298: if (test->json_output)
2299: cJSON_AddItemToObject(json_interval, "sum", 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", (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));
2300: else
2301: iprintf(test, report_sum_bw_udp_format, start_time, end_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, total_packets, lost_percent, test->omitting?report_omitted:"");
2302: }
2303: }
2304: }
2305: }
2306: }
2307:
2308: /**
2309: * Print overall summary statistics at the end of a test.
2310: */
2311: static void
2312: iperf_print_results(struct iperf_test *test)
2313: {
2314:
2315: cJSON *json_summary_streams = NULL;
2316: cJSON *json_summary_stream = NULL;
2317: int total_retransmits = 0;
2318: int total_packets = 0, lost_packets = 0;
2319: char ubuf[UNIT_LEN];
2320: char nbuf[UNIT_LEN];
2321: struct stat sb;
2322: char sbuf[UNIT_LEN];
2323: struct iperf_stream *sp = NULL;
2324: iperf_size_t bytes_sent, total_sent = 0;
2325: iperf_size_t bytes_received, total_received = 0;
2326: double start_time, end_time, avg_jitter = 0.0, lost_percent;
2327: double bandwidth;
2328:
2329: /* print final summary for all intervals */
2330:
2331: if (test->json_output) {
2332: json_summary_streams = cJSON_CreateArray();
2333: if (json_summary_streams == NULL)
2334: return;
2335: cJSON_AddItemToObject(test->json_end, "streams", json_summary_streams);
2336: } else {
2337: iprintf(test, "%s", report_bw_separator);
2338: if (test->verbose)
2339: iprintf(test, "%s", report_summary);
2340: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
2341: if (test->sender_has_retransmits)
2342: iprintf(test, "%s", report_bw_retrans_header);
2343: else
2344: iprintf(test, "%s", report_bw_header);
2345: } else
2346: iprintf(test, "%s", report_bw_udp_header);
2347: }
2348:
2349: start_time = 0.;
2350: sp = SLIST_FIRST(&test->streams);
2351: /*
2352: * If there is at least one stream, then figure out the length of time
2353: * we were running the tests and print out some statistics about
2354: * the streams. It's possible to not have any streams at all
2355: * if the client got interrupted before it got to do anything.
2356: */
2357: if (sp) {
2358: end_time = timeval_diff(&sp->result->start_time, &sp->result->end_time);
2359: SLIST_FOREACH(sp, &test->streams, streams) {
2360: if (test->json_output) {
2361: json_summary_stream = cJSON_CreateObject();
2362: if (json_summary_stream == NULL)
2363: return;
2364: cJSON_AddItemToArray(json_summary_streams, json_summary_stream);
2365: }
2366:
2367: bytes_sent = sp->result->bytes_sent - sp->result->bytes_sent_omit;
2368: bytes_received = sp->result->bytes_received;
2369: total_sent += bytes_sent;
2370: total_received += bytes_received;
2371:
2372: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
2373: if (test->sender_has_retransmits) {
2374: total_retransmits += sp->result->stream_retrans;
2375: }
2376: } else {
2377: total_packets += (sp->packet_count - sp->omitted_packet_count);
2378: lost_packets += (sp->cnt_error - sp->omitted_cnt_error);
2379: avg_jitter += sp->jitter;
2380: }
2381:
2382: unit_snprintf(ubuf, UNIT_LEN, (double) bytes_sent, 'A');
2383: bandwidth = (double) bytes_sent / (double) end_time;
2384: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
2385: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
2386: if (test->sender_has_retransmits) {
2387: /* Summary, TCP with retransmits. */
2388: if (test->json_output)
2389: cJSON_AddItemToObject(json_summary_stream, "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_rtt: %d min_rtt: %d mean_rtt: %d", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_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_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)));
2390: else
2391: iprintf(test, report_bw_retrans_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->result->stream_retrans, report_sender);
2392: } else {
2393: /* Summary, TCP without retransmits. */
2394: if (test->json_output)
2395: cJSON_AddItemToObject(json_summary_stream, "sender", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8));
2396: else
2397: iprintf(test, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, report_sender);
2398: }
2399: } else {
2400: /* Summary, UDP. */
2401: if (sp->packet_count - sp->omitted_packet_count > 0) {
2402: lost_percent = 100.0 * (sp->cnt_error - sp->omitted_cnt_error) / (sp->packet_count - sp->omitted_packet_count);
2403: }
2404: else {
2405: lost_percent = 0.0;
2406: }
2407: if (test->json_output)
2408: 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", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_sent, bandwidth * 8, (double) sp->jitter * 1000.0, (int64_t) (sp->cnt_error - sp->omitted_cnt_error), (int64_t) (sp->packet_count - sp->omitted_packet_count), (double) lost_percent, (int64_t) (sp->outoforder_packets - sp->omitted_outoforder_packets)));
2409: else {
2410: iprintf(test, report_bw_udp_format, sp->socket, start_time, end_time, ubuf, nbuf, sp->jitter * 1000.0, (sp->cnt_error - sp->omitted_cnt_error), (sp->packet_count - sp->omitted_packet_count), lost_percent, "");
2411: if (test->role == 'c')
2412: iprintf(test, report_datagrams, sp->socket, (sp->packet_count - sp->omitted_packet_count));
2413: if ((sp->outoforder_packets - sp->omitted_outoforder_packets) > 0)
2414: iprintf(test, report_sum_outoforder, start_time, end_time, (sp->outoforder_packets - sp->omitted_outoforder_packets));
2415: }
2416: }
2417:
2418: if (sp->diskfile_fd >= 0) {
2419: if (fstat(sp->diskfile_fd, &sb) == 0) {
2420: int percent = (int) ( ( (double) bytes_sent / (double) sb.st_size ) * 100.0 );
2421: unit_snprintf(sbuf, UNIT_LEN, (double) sb.st_size, 'A');
2422: if (test->json_output)
2423: cJSON_AddItemToObject(json_summary_stream, "diskfile", iperf_json_printf("sent: %d size: %d percent: %d filename: %s", (int64_t) bytes_sent, (int64_t) sb.st_size, (int64_t) percent, test->diskfile_name));
2424: else
2425: iprintf(test, report_diskfile, ubuf, sbuf, percent, test->diskfile_name);
2426: }
2427: }
2428:
2429: unit_snprintf(ubuf, UNIT_LEN, (double) bytes_received, 'A');
2430: bandwidth = (double) bytes_received / (double) end_time;
2431: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
2432: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
2433: if (test->json_output)
2434: cJSON_AddItemToObject(json_summary_stream, "receiver", iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (int64_t) sp->socket, (double) start_time, (double) end_time, (double) end_time, (int64_t) bytes_received, bandwidth * 8));
2435: else
2436: iprintf(test, report_bw_format, sp->socket, start_time, end_time, ubuf, nbuf, report_receiver);
2437: }
2438: }
2439: }
2440:
2441: if (test->num_streams > 1 || test->json_output) {
2442: unit_snprintf(ubuf, UNIT_LEN, (double) total_sent, 'A');
2443: /* If no tests were run, arbitrariliy set bandwidth to 0. */
2444: if (end_time > 0.0) {
2445: bandwidth = (double) total_sent / (double) end_time;
2446: }
2447: else {
2448: bandwidth = 0.0;
2449: }
2450: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
2451: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
2452: if (test->sender_has_retransmits) {
2453: /* Summary sum, TCP with retransmits. */
2454: if (test->json_output)
2455: cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f retransmits: %d", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8, (int64_t) total_retransmits));
2456: else
2457: iprintf(test, report_sum_bw_retrans_format, start_time, end_time, ubuf, nbuf, total_retransmits, report_sender);
2458: } else {
2459: /* Summary sum, TCP without retransmits. */
2460: if (test->json_output)
2461: cJSON_AddItemToObject(test->json_end, "sum_sent", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8));
2462: else
2463: iprintf(test, report_sum_bw_format, start_time, end_time, ubuf, nbuf, report_sender);
2464: }
2465: unit_snprintf(ubuf, UNIT_LEN, (double) total_received, 'A');
2466: /* If no tests were run, set received bandwidth to 0 */
2467: if (end_time > 0.0) {
2468: bandwidth = (double) total_received / (double) end_time;
2469: }
2470: else {
2471: bandwidth = 0.0;
2472: }
2473: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
2474: if (test->json_output)
2475: cJSON_AddItemToObject(test->json_end, "sum_received", iperf_json_printf("start: %f end: %f seconds: %f bytes: %d bits_per_second: %f", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_received, bandwidth * 8));
2476: else
2477: iprintf(test, report_sum_bw_format, start_time, end_time, ubuf, nbuf, report_receiver);
2478: } else {
2479: /* Summary sum, UDP. */
2480: avg_jitter /= test->num_streams;
2481: /* If no packets were sent, arbitrarily set loss percentage to 0. */
2482: if (total_packets > 0) {
2483: lost_percent = 100.0 * lost_packets / total_packets;
2484: }
2485: else {
2486: lost_percent = 0.0;
2487: }
2488: if (test->json_output)
2489: cJSON_AddItemToObject(test->json_end, "sum", 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", (double) start_time, (double) end_time, (double) end_time, (int64_t) total_sent, bandwidth * 8, (double) avg_jitter * 1000.0, (int64_t) lost_packets, (int64_t) total_packets, (double) lost_percent));
2490: else
2491: iprintf(test, report_sum_bw_udp_format, start_time, end_time, ubuf, nbuf, avg_jitter * 1000.0, lost_packets, total_packets, lost_percent, "");
2492: }
2493: }
2494:
2495: if (test->json_output)
2496: 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]));
2497: else {
2498: if (test->verbose) {
2499: iprintf(test, report_cpu, report_local, test->sender?report_sender:report_receiver, test->cpu_util[0], test->cpu_util[1], test->cpu_util[2], report_remote, test->sender?report_receiver:report_sender, test->remote_cpu_util[0], test->remote_cpu_util[1], test->remote_cpu_util[2]);
2500: }
2501:
2502: /* Print server output if we're on the client and it was requested/provided */
2503: if (test->role == 'c' && iperf_get_test_get_server_output(test)) {
2504: if (test->json_server_output) {
2505: iprintf(test, "\nServer JSON output:\n%s\n", cJSON_Print(test->json_server_output));
2506: cJSON_Delete(test->json_server_output);
2507: test->json_server_output = NULL;
2508: }
2509: if (test->server_output_text) {
2510: iprintf(test, "\nServer output:\n%s\n", test->server_output_text);
2511: test->server_output_text = NULL;
2512: }
2513: }
2514: }
2515: }
2516:
2517: /**************************************************************************/
2518:
2519: /**
2520: * Main report-printing callback.
2521: * Prints results either during a test (interval report only) or
2522: * after the entire test has been run (last interval report plus
2523: * overall summary).
2524: */
2525: void
2526: iperf_reporter_callback(struct iperf_test *test)
2527: {
2528: switch (test->state) {
2529: case TEST_RUNNING:
2530: case STREAM_RUNNING:
2531: /* print interval results for each stream */
2532: iperf_print_intermediate(test);
2533: break;
2534: case TEST_END:
2535: case DISPLAY_RESULTS:
2536: iperf_print_intermediate(test);
2537: iperf_print_results(test);
2538: break;
2539: }
2540:
2541: }
2542:
2543: /**
2544: * Print the interval results for one stream.
2545: * This function needs to know about the overall test so it can determine the
2546: * context for printing headers, separators, etc.
2547: */
2548: static void
2549: print_interval_results(struct iperf_test *test, struct iperf_stream *sp, cJSON *json_interval_streams)
2550: {
2551: char ubuf[UNIT_LEN];
2552: char nbuf[UNIT_LEN];
2553: char cbuf[UNIT_LEN];
2554: double st = 0., et = 0.;
2555: struct iperf_interval_results *irp = NULL;
2556: double bandwidth, lost_percent;
2557:
2558: irp = TAILQ_LAST(&sp->result->interval_results, irlisthead); /* get last entry in linked list */
2559: if (irp == NULL) {
2560: iperf_err(test, "print_interval_results error: interval_results is NULL");
2561: return;
2562: }
2563: if (!test->json_output) {
2564: /* First stream? */
2565: if (sp == SLIST_FIRST(&test->streams)) {
2566: /* It it's the first interval, print the header;
2567: ** else if there's more than one stream, print the separator;
2568: ** else nothing.
2569: */
2570: if (timeval_equals(&sp->result->start_time, &irp->interval_start_time)) {
2571: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
2572: if (test->sender && test->sender_has_retransmits)
2573: iprintf(test, "%s", report_bw_retrans_cwnd_header);
2574: else
2575: iprintf(test, "%s", report_bw_header);
2576: } else {
2577: if (test->sender)
2578: iprintf(test, "%s", report_bw_udp_sender_header);
2579: else
2580: iprintf(test, "%s", report_bw_udp_header);
2581: }
2582: } else if (test->num_streams > 1)
2583: iprintf(test, "%s", report_bw_separator);
2584: }
2585: }
2586:
2587: unit_snprintf(ubuf, UNIT_LEN, (double) (irp->bytes_transferred), 'A');
2588: bandwidth = (double) irp->bytes_transferred / (double) irp->interval_duration;
2589: unit_snprintf(nbuf, UNIT_LEN, bandwidth, test->settings->unit_format);
2590:
2591: st = timeval_diff(&sp->result->start_time, &irp->interval_start_time);
2592: et = timeval_diff(&sp->result->start_time, &irp->interval_end_time);
2593:
2594: if (test->protocol->id == Ptcp || test->protocol->id == Psctp) {
2595: if (test->sender && test->sender_has_retransmits) {
2596: /* Interval, TCP with retransmits. */
2597: if (test->json_output)
2598: 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 rtt: %d omitted: %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->rtt, irp->omitted));
2599: else {
2600: unit_snprintf(cbuf, UNIT_LEN, irp->snd_cwnd, 'A');
2601: iprintf(test, report_bw_retrans_cwnd_format, sp->socket, st, et, ubuf, nbuf, irp->interval_retrans, cbuf, irp->omitted?report_omitted:"");
2602: }
2603: } else {
2604: /* Interval, TCP without retransmits. */
2605: if (test->json_output)
2606: cJSON_AddItemToArray(json_interval_streams, iperf_json_printf("socket: %d start: %f end: %f seconds: %f bytes: %d bits_per_second: %f omitted: %b", (int64_t) sp->socket, (double) st, (double) et, (double) irp->interval_duration, (int64_t) irp->bytes_transferred, bandwidth * 8, irp->omitted));
2607: else
2608: iprintf(test, report_bw_format, sp->socket, st, et, ubuf, nbuf, irp->omitted?report_omitted:"");
2609: }
2610: } else {
2611: /* Interval, UDP. */
2612: if (test->sender) {
2613: if (test->json_output)
2614: 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", (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));
2615: else
2616: iprintf(test, report_bw_udp_sender_format, sp->socket, st, et, ubuf, nbuf, irp->interval_packet_count, irp->omitted?report_omitted:"");
2617: } else {
2618: if (irp->interval_packet_count > 0) {
2619: lost_percent = 100.0 * irp->interval_cnt_error / irp->interval_packet_count;
2620: }
2621: else {
2622: lost_percent = 0.0;
2623: }
2624: if (test->json_output)
2625: 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", (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));
2626: else
2627: iprintf(test, report_bw_udp_format, sp->socket, st, et, ubuf, nbuf, irp->jitter * 1000.0, irp->interval_cnt_error, irp->interval_packet_count, lost_percent, irp->omitted?report_omitted:"");
2628: }
2629: }
2630:
2631: if (test->logfile)
2632: iflush(test);
2633: }
2634:
2635: /**************************************************************************/
2636: void
2637: iperf_free_stream(struct iperf_stream *sp)
2638: {
2639: struct iperf_interval_results *irp, *nirp;
2640:
2641: /* XXX: need to free interval list too! */
2642: munmap(sp->buffer, sp->test->settings->blksize);
2643: close(sp->buffer_fd);
2644: if (sp->diskfile_fd >= 0)
2645: close(sp->diskfile_fd);
2646: for (irp = TAILQ_FIRST(&sp->result->interval_results); irp != NULL; irp = nirp) {
2647: nirp = TAILQ_NEXT(irp, irlistentries);
2648: free(irp);
2649: }
2650: free(sp->result);
2651: if (sp->send_timer != NULL)
2652: tmr_cancel(sp->send_timer);
2653: free(sp);
2654: }
2655:
2656: /**************************************************************************/
2657: struct iperf_stream *
2658: iperf_new_stream(struct iperf_test *test, int s)
2659: {
2660: int i;
2661: struct iperf_stream *sp;
2662:
2663: char template[1024];
2664: if (test->tmp_template) {
2665: snprintf(template, sizeof(template) / sizeof(char), "%s", test->tmp_template);
2666: } else {
2667: char buf[] = "/tmp/iperf3.XXXXXX";
2668: snprintf(template, sizeof(template) / sizeof(char), "%s", buf);
2669: }
2670:
2671: h_errno = 0;
2672:
2673: sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream));
2674: if (!sp) {
2675: i_errno = IECREATESTREAM;
2676: return NULL;
2677: }
2678:
2679: memset(sp, 0, sizeof(struct iperf_stream));
2680:
2681: sp->test = test;
2682: sp->settings = test->settings;
2683: sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result));
2684: if (!sp->result) {
2685: free(sp);
2686: i_errno = IECREATESTREAM;
2687: return NULL;
2688: }
2689:
2690: memset(sp->result, 0, sizeof(struct iperf_stream_result));
2691: TAILQ_INIT(&sp->result->interval_results);
2692:
2693: /* Create and randomize the buffer */
2694: sp->buffer_fd = mkstemp(template);
2695: if (sp->buffer_fd == -1) {
2696: i_errno = IECREATESTREAM;
2697: free(sp->result);
2698: free(sp);
2699: return NULL;
2700: }
2701: if (unlink(template) < 0) {
2702: i_errno = IECREATESTREAM;
2703: free(sp->result);
2704: free(sp);
2705: return NULL;
2706: }
2707: if (ftruncate(sp->buffer_fd, test->settings->blksize) < 0) {
2708: i_errno = IECREATESTREAM;
2709: free(sp->result);
2710: free(sp);
2711: return NULL;
2712: }
2713: sp->buffer = (char *) mmap(NULL, test->settings->blksize, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0);
2714: if (sp->buffer == MAP_FAILED) {
2715: i_errno = IECREATESTREAM;
2716: free(sp->result);
2717: free(sp);
2718: return NULL;
2719: }
2720: srandom(time(NULL));
2721: for (i = 0; i < test->settings->blksize; ++i)
2722: sp->buffer[i] = random();
2723:
2724: /* Set socket */
2725: sp->socket = s;
2726:
2727: sp->snd = test->protocol->send;
2728: sp->rcv = test->protocol->recv;
2729:
2730: if (test->diskfile_name != (char*) 0) {
2731: sp->diskfile_fd = open(test->diskfile_name, test->sender ? O_RDONLY : (O_WRONLY|O_CREAT|O_TRUNC), S_IRUSR|S_IWUSR);
2732: if (sp->diskfile_fd == -1) {
2733: i_errno = IEFILE;
2734: munmap(sp->buffer, sp->test->settings->blksize);
2735: free(sp->result);
2736: free(sp);
2737: return NULL;
2738: }
2739: sp->snd2 = sp->snd;
2740: sp->snd = diskfile_send;
2741: sp->rcv2 = sp->rcv;
2742: sp->rcv = diskfile_recv;
2743: } else
2744: sp->diskfile_fd = -1;
2745:
2746: /* Initialize stream */
2747: if (iperf_init_stream(sp, test) < 0) {
2748: close(sp->buffer_fd);
2749: munmap(sp->buffer, sp->test->settings->blksize);
2750: free(sp->result);
2751: free(sp);
2752: return NULL;
2753: }
2754: iperf_add_stream(test, sp);
2755:
2756: return sp;
2757: }
2758:
2759: /**************************************************************************/
2760: int
2761: iperf_init_stream(struct iperf_stream *sp, struct iperf_test *test)
2762: {
2763: socklen_t len;
2764: int opt;
2765:
2766: len = sizeof(struct sockaddr_storage);
2767: if (getsockname(sp->socket, (struct sockaddr *) &sp->local_addr, &len) < 0) {
2768: i_errno = IEINITSTREAM;
2769: return -1;
2770: }
2771: len = sizeof(struct sockaddr_storage);
2772: if (getpeername(sp->socket, (struct sockaddr *) &sp->remote_addr, &len) < 0) {
2773: i_errno = IEINITSTREAM;
2774: return -1;
2775: }
2776:
2777: /* Set IP TOS */
2778: if ((opt = test->settings->tos)) {
2779: if (getsockdomain(sp->socket) == AF_INET6) {
2780: #ifdef IPV6_TCLASS
2781: if (setsockopt(sp->socket, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) < 0) {
2782: i_errno = IESETCOS;
2783: return -1;
2784: }
2785: #else
2786: i_errno = IESETCOS;
2787: return -1;
2788: #endif
2789: } else {
2790: if (setsockopt(sp->socket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) < 0) {
2791: i_errno = IESETTOS;
2792: return -1;
2793: }
2794: }
2795: }
2796:
2797: return 0;
2798: }
2799:
2800: /**************************************************************************/
2801: void
2802: iperf_add_stream(struct iperf_test *test, struct iperf_stream *sp)
2803: {
2804: int i;
2805: struct iperf_stream *n, *prev;
2806:
2807: if (SLIST_EMPTY(&test->streams)) {
2808: SLIST_INSERT_HEAD(&test->streams, sp, streams);
2809: sp->id = 1;
2810: } else {
2811: // for (n = test->streams, i = 2; n->next; n = n->next, ++i);
2812: i = 2;
2813: SLIST_FOREACH(n, &test->streams, streams) {
2814: prev = n;
2815: ++i;
2816: }
2817: SLIST_INSERT_AFTER(prev, sp, streams);
2818: sp->id = i;
2819: }
2820: }
2821:
2822: /* This pair of routines gets inserted into the snd/rcv function pointers
2823: ** when there's a -F flag. They handle the file stuff and call the real
2824: ** snd/rcv functions, which have been saved in snd2/rcv2.
2825: **
2826: ** The advantage of doing it this way is that in the much more common
2827: ** case of no -F flag, there is zero extra overhead.
2828: */
2829:
2830: static int
2831: diskfile_send(struct iperf_stream *sp)
2832: {
2833: int r;
2834:
2835: r = read(sp->diskfile_fd, sp->buffer, sp->test->settings->blksize);
2836: if (r == 0)
2837: sp->test->done = 1;
2838: else
2839: r = sp->snd2(sp);
2840: return r;
2841: }
2842:
2843: static int
2844: diskfile_recv(struct iperf_stream *sp)
2845: {
2846: int r;
2847:
2848: r = sp->rcv2(sp);
2849: if (r > 0) {
2850: (void) write(sp->diskfile_fd, sp->buffer, r);
2851: (void) fsync(sp->diskfile_fd);
2852: }
2853: return r;
2854: }
2855:
2856:
2857: void
2858: iperf_catch_sigend(void (*handler)(int))
2859: {
2860: signal(SIGINT, handler);
2861: signal(SIGTERM, handler);
2862: signal(SIGHUP, handler);
2863: }
2864:
2865: /**
2866: * Called as a result of getting a signal.
2867: * Depending on the current state of the test (and the role of this
2868: * process) compute and report one more set of ending statistics
2869: * before cleaning up and exiting.
2870: */
2871: void
2872: iperf_got_sigend(struct iperf_test *test)
2873: {
2874: /*
2875: * If we're the client, or if we're a server and running a test,
2876: * then dump out the accumulated stats so far.
2877: */
2878: if (test->role == 'c' ||
2879: (test->role == 's' && test->state == TEST_RUNNING)) {
2880:
2881: test->done = 1;
2882: cpu_util(test->cpu_util);
2883: test->stats_callback(test);
2884: test->state = DISPLAY_RESULTS; /* change local state only */
2885: if (test->on_test_finish)
2886: test->on_test_finish(test);
2887: test->reporter_callback(test);
2888: }
2889:
2890: if (test->ctrl_sck >= 0) {
2891: test->state = (test->role == 'c') ? CLIENT_TERMINATE : SERVER_TERMINATE;
2892: (void) Nwrite(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp);
2893: }
2894: i_errno = (test->role == 'c') ? IECLIENTTERM : IESERVERTERM;
2895: iperf_errexit(test, "interrupt - %s", iperf_strerror(i_errno));
2896: }
2897:
2898: /* Try to write a PID file if requested, return -1 on an error. */
2899: int
2900: iperf_create_pidfile(struct iperf_test *test)
2901: {
2902: if (test->pidfile) {
2903: int fd;
2904: char buf[8];
2905: fd = open(test->pidfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR);
2906: if (fd < 0) {
2907: return -1;
2908: }
2909: snprintf(buf, sizeof(buf), "%d", getpid()); /* no trailing newline */
2910: if (write(fd, buf, strlen(buf) + 1) < 0) {
2911: return -1;
2912: }
2913: if (close(fd) < 0) {
2914: return -1;
2915: };
2916: }
2917: return 0;
2918: }
2919:
2920: /* Get rid of a PID file, return -1 on error. */
2921: int
2922: iperf_delete_pidfile(struct iperf_test *test)
2923: {
2924: if (test->pidfile) {
2925: if (unlink(test->pidfile) < 0) {
2926: return -1;
2927: }
2928: }
2929: return 0;
2930: }
2931:
2932: int
2933: iperf_json_start(struct iperf_test *test)
2934: {
2935: test->json_top = cJSON_CreateObject();
2936: if (test->json_top == NULL)
2937: return -1;
2938: test->json_start = cJSON_CreateObject();
2939: if (test->json_start == NULL)
2940: return -1;
2941: cJSON_AddItemToObject(test->json_top, "start", test->json_start);
2942: test->json_connected = cJSON_CreateArray();
2943: if (test->json_connected == NULL)
2944: return -1;
2945: cJSON_AddItemToObject(test->json_start, "connected", test->json_connected);
2946: test->json_intervals = cJSON_CreateArray();
2947: if (test->json_intervals == NULL)
2948: return -1;
2949: cJSON_AddItemToObject(test->json_top, "intervals", test->json_intervals);
2950: test->json_end = cJSON_CreateObject();
2951: if (test->json_end == NULL)
2952: return -1;
2953: cJSON_AddItemToObject(test->json_top, "end", test->json_end);
2954: return 0;
2955: }
2956:
2957: int
2958: iperf_json_finish(struct iperf_test *test)
2959: {
2960: if (test->title)
2961: cJSON_AddStringToObject(test->json_top, "title", test->title);
2962: /* Include server output */
2963: if (test->json_server_output) {
2964: cJSON_AddItemToObject(test->json_top, "server_output_json", test->json_server_output);
2965: }
2966: if (test->server_output_text) {
2967: cJSON_AddStringToObject(test->json_top, "server_output_text", test->server_output_text);
2968: }
2969: test->json_output_string = cJSON_Print(test->json_top);
2970: if (test->json_output_string == NULL)
2971: return -1;
2972: fprintf(test->outfile, "%s\n", test->json_output_string);
2973: iflush(test);
2974: cJSON_Delete(test->json_top);
2975: test->json_top = test->json_start = test->json_connected = test->json_intervals = test->json_server_output = test->json_end = NULL;
2976: return 0;
2977: }
2978:
2979:
2980: /* CPU affinity stuff - Linux and FreeBSD only. */
2981:
2982: int
2983: iperf_setaffinity(struct iperf_test *test, int affinity)
2984: {
2985: #if defined(HAVE_SCHED_SETAFFINITY)
2986: cpu_set_t cpu_set;
2987:
2988: CPU_ZERO(&cpu_set);
2989: CPU_SET(affinity, &cpu_set);
2990: if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) != 0) {
2991: i_errno = IEAFFINITY;
2992: return -1;
2993: }
2994: return 0;
2995: #elif defined(HAVE_CPUSET_SETAFFINITY)
2996: cpuset_t cpumask;
2997:
2998: if(cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
2999: sizeof(cpuset_t), &test->cpumask) != 0) {
3000: i_errno = IEAFFINITY;
3001: return -1;
3002: }
3003:
3004: CPU_ZERO(&cpumask);
3005: CPU_SET(affinity, &cpumask);
3006:
3007: if(cpuset_setaffinity(CPU_LEVEL_WHICH,CPU_WHICH_PID, -1,
3008: sizeof(cpuset_t), &cpumask) != 0) {
3009: i_errno = IEAFFINITY;
3010: return -1;
3011: }
3012: return 0;
3013: #else /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY */
3014: i_errno = IEAFFINITY;
3015: return -1;
3016: #endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY */
3017: }
3018:
3019: int
3020: iperf_clearaffinity(struct iperf_test *test)
3021: {
3022: #if defined(HAVE_SCHED_SETAFFINITY)
3023: cpu_set_t cpu_set;
3024: int i;
3025:
3026: CPU_ZERO(&cpu_set);
3027: for (i = 0; i < CPU_SETSIZE; ++i)
3028: CPU_SET(i, &cpu_set);
3029: if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) != 0) {
3030: i_errno = IEAFFINITY;
3031: return -1;
3032: }
3033: return 0;
3034: #elif defined(HAVE_CPUSET_SETAFFINITY)
3035: if(cpuset_setaffinity(CPU_LEVEL_WHICH,CPU_WHICH_PID, -1,
3036: sizeof(cpuset_t), &test->cpumask) != 0) {
3037: i_errno = IEAFFINITY;
3038: return -1;
3039: }
3040: return 0;
3041: #else /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY */
3042: i_errno = IEAFFINITY;
3043: return -1;
3044: #endif /* neither HAVE_SCHED_SETAFFINITY nor HAVE_CPUSET_SETAFFINITY */
3045: }
3046:
3047: int
3048: iprintf(struct iperf_test *test, const char* format, ...)
3049: {
3050: va_list argp;
3051: int r = -1;
3052:
3053: /*
3054: * There are roughly two use cases here. If we're the client,
3055: * want to print stuff directly to the output stream.
3056: * If we're the sender we might need to buffer up output to send
3057: * to the client.
3058: *
3059: * This doesn't make a whole lot of difference except there are
3060: * some chunks of output on the client (on particular the whole
3061: * of the server output with --get-server-output) that could
3062: * easily exceed the size of the line buffer, but which don't need
3063: * to be buffered up anyway.
3064: */
3065: if (test->role == 'c') {
3066: if (test->title)
3067: fprintf(test->outfile, "%s: ", test->title);
3068: va_start(argp, format);
3069: r = vfprintf(test->outfile, format, argp);
3070: va_end(argp);
3071: }
3072: else if (test->role == 's') {
3073: char linebuffer[1024];
3074: va_start(argp, format);
3075: r = vsnprintf(linebuffer, sizeof(linebuffer), format, argp);
3076: va_end(argp);
3077: fprintf(test->outfile, "%s", linebuffer);
3078:
3079: if (test->role == 's' && iperf_get_test_get_server_output(test)) {
3080: struct iperf_textline *l = (struct iperf_textline *) malloc(sizeof(struct iperf_textline));
3081: l->line = strdup(linebuffer);
3082: TAILQ_INSERT_TAIL(&(test->server_output_list), l, textlineentries);
3083: }
3084: }
3085: return r;
3086: }
3087:
3088: int
3089: iflush(struct iperf_test *test)
3090: {
3091: return fflush(test->outfile);
3092: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>