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