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