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