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