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