1 /* 2 * iperf, Copyright (c) 2014, The Regents of the University of 3 * California, through Lawrence Berkeley National Laboratory (subject 4 * to receipt of any required approvals from the U.S. Dept. of 5 * Energy). All rights reserved. 6 * 7 * If you have questions about your rights to use or distribute this 8 * software, please contact Berkeley Lab's Technology Transfer 9 * Department at [email protected]. 10 * 11 * NOTICE. This software is owned by the U.S. Department of Energy. 12 * As such, the U.S. Government has been granted for itself and others 13 * acting on its behalf a paid-up, nonexclusive, irrevocable, 14 * worldwide license in the Software to reproduce, prepare derivative 15 * works, and perform publicly and display publicly. Beginning five 16 * (5) years after the date permission to assert copyright is obtained 17 * from the U.S. Department of Energy, and subject to any subsequent 18 * five (5) year renewals, the U.S. Government is granted for itself 19 * and others acting on its behalf a paid-up, nonexclusive, 20 * irrevocable, worldwide license in the Software to reproduce, 21 * prepare derivative works, distribute copies to the public, perform 22 * publicly and display publicly, and to permit others to do so. 23 * 24 * This code is distributed under a BSD style license, see the LICENSE 25 * file for complete information. 26 */ 27 #include <errno.h> 28 #include <setjmp.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <signal.h> 34 #include <sys/types.h> 35 #include <sys/select.h> 36 #include <sys/uio.h> 37 #include <arpa/inet.h> 38 39 #include "iperf.h" 40 #include "iperf_api.h" 41 #include "iperf_util.h" 42 #include "iperf_locale.h" 43 #include "net.h" 44 #include "timer.h" 45 46 47 int 48 iperf_create_streams(struct iperf_test *test) 49 { 50 int i, s; 51 struct iperf_stream *sp; 52 53 int orig_bind_port = test->bind_port; 54 for (i = 0; i < test->num_streams; ++i) { 55 56 test->bind_port = orig_bind_port + i; 57 if ((s = test->protocol->connect(test)) < 0) 58 return -1; 59 60 if (test->sender) 61 FD_SET(s, &test->write_set); 62 else 63 FD_SET(s, &test->read_set); 64 if (s > test->max_fd) test->max_fd = s; 65 66 sp = iperf_new_stream(test, s); 67 if (!sp) 68 return -1; 69 70 /* Perform the new stream callback */ 71 if (test->on_new_stream) 72 test->on_new_stream(sp); 73 } 74 75 return 0; 76 } 77 78 static void 79 test_timer_proc(TimerClientData client_data, struct timeval *nowP) 80 { 81 struct iperf_test *test = client_data.p; 82 83 test->timer = NULL; 84 test->done = 1; 85 } 86 87 static void 88 client_stats_timer_proc(TimerClientData client_data, struct timeval *nowP) 89 { 90 struct iperf_test *test = client_data.p; 91 92 if (test->done) 93 return; 94 if (test->stats_callback) 95 test->stats_callback(test); 96 } 97 98 static void 99 client_reporter_timer_proc(TimerClientData client_data, struct timeval *nowP) 100 { 101 struct iperf_test *test = client_data.p; 102 103 if (test->done) 104 return; 105 if (test->reporter_callback) 106 test->reporter_callback(test); 107 } 108 109 static int 110 create_client_timers(struct iperf_test * test) 111 { 112 struct timeval now; 113 TimerClientData cd; 114 115 if (gettimeofday(&now, NULL) < 0) { 116 i_errno = IEINITTEST; 117 return -1; 118 } 119 cd.p = test; 120 test->timer = test->stats_timer = test->reporter_timer = NULL; 121 if (test->duration != 0) { 122 test->done = 0; 123 test->timer = tmr_create(&now, test_timer_proc, cd, ( test->duration + test->omit ) * SEC_TO_US, 0); 124 if (test->timer == NULL) { 125 i_errno = IEINITTEST; 126 return -1; 127 } 128 } 129 if (test->stats_interval != 0) { 130 test->stats_timer = tmr_create(&now, client_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1); 131 if (test->stats_timer == NULL) { 132 i_errno = IEINITTEST; 133 return -1; 134 } 135 } 136 if (test->reporter_interval != 0) { 137 test->reporter_timer = tmr_create(&now, client_reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1); 138 if (test->reporter_timer == NULL) { 139 i_errno = IEINITTEST; 140 return -1; 141 } 142 } 143 return 0; 144 } 145 146 static void 147 client_omit_timer_proc(TimerClientData client_data, struct timeval *nowP) 148 { 149 struct iperf_test *test = client_data.p; 150 151 test->omit_timer = NULL; 152 test->omitting = 0; 153 iperf_reset_stats(test); 154 if (test->verbose && !test->json_output && test->reporter_interval == 0) 155 iprintf(test, "%s", report_omit_done); 156 157 /* Reset the timers. */ 158 if (test->stats_timer != NULL) 159 tmr_reset(nowP, test->stats_timer); 160 if (test->reporter_timer != NULL) 161 tmr_reset(nowP, test->reporter_timer); 162 } 163 164 static int 165 create_client_omit_timer(struct iperf_test * test) 166 { 167 struct timeval now; 168 TimerClientData cd; 169 170 if (test->omit == 0) { 171 test->omit_timer = NULL; 172 test->omitting = 0; 173 } else { 174 if (gettimeofday(&now, NULL) < 0) { 175 i_errno = IEINITTEST; 176 return -1; 177 } 178 test->omitting = 1; 179 cd.p = test; 180 test->omit_timer = tmr_create(&now, client_omit_timer_proc, cd, test->omit * SEC_TO_US, 0); 181 if (test->omit_timer == NULL) { 182 i_errno = IEINITTEST; 183 return -1; 184 } 185 } 186 return 0; 187 } 188 189 int 190 iperf_handle_message_client(struct iperf_test *test) 191 { 192 int rval; 193 int32_t err; 194 195 /*!!! Why is this read() and not Nread()? */ 196 if ((rval = read(test->ctrl_sck, (char*) &test->state, sizeof(signed char))) <= 0) { 197 if (rval == 0) { 198 i_errno = IECTRLCLOSE; 199 return -1; 200 } else { 201 i_errno = IERECVMESSAGE; 202 return -1; 203 } 204 } 205 206 switch (test->state) { 207 case PARAM_EXCHANGE: 208 if (iperf_exchange_parameters(test) < 0) 209 return -1; 210 if (test->on_connect) 211 test->on_connect(test); 212 break; 213 case CREATE_STREAMS: 214 if (iperf_create_streams(test) < 0) 215 return -1; 216 break; 217 case TEST_START: 218 if (iperf_init_test(test) < 0) 219 return -1; 220 if (create_client_timers(test) < 0) 221 return -1; 222 if (create_client_omit_timer(test) < 0) 223 return -1; 224 if (!test->reverse) 225 if (iperf_create_send_timers(test) < 0) 226 return -1; 227 break; 228 case TEST_RUNNING: 229 break; 230 case EXCHANGE_RESULTS: 231 if (iperf_exchange_results(test) < 0) 232 return -1; 233 break; 234 case DISPLAY_RESULTS: 235 if (test->on_test_finish) 236 test->on_test_finish(test); 237 iperf_client_end(test); 238 break; 239 case IPERF_DONE: 240 break; 241 case SERVER_TERMINATE: 242 i_errno = IESERVERTERM; 243 244 /* 245 * Temporarily be in DISPLAY_RESULTS phase so we can get 246 * ending summary statistics. 247 */ 248 signed char oldstate = test->state; 249 cpu_util(test->cpu_util); 250 test->state = DISPLAY_RESULTS; 251 test->reporter_callback(test); 252 test->state = oldstate; 253 return -1; 254 case ACCESS_DENIED: 255 i_errno = IEACCESSDENIED; 256 return -1; 257 case SERVER_ERROR: 258 if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) { 259 i_errno = IECTRLREAD; 260 return -1; 261 } 262 i_errno = ntohl(err); 263 if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) { 264 i_errno = IECTRLREAD; 265 return -1; 266 } 267 errno = ntohl(err); 268 return -1; 269 default: 270 i_errno = IEMESSAGE; 271 return -1; 272 } 273 274 return 0; 275 } 276 277 278 279 /* iperf_connect -- client to server connection function */ 280 int 281 iperf_connect(struct iperf_test *test) 282 { 283 FD_ZERO(&test->read_set); 284 FD_ZERO(&test->write_set); 285 286 make_cookie(test->cookie); 287 288 /* Create and connect the control channel */ 289 if (test->ctrl_sck < 0) 290 // Create the control channel using an ephemeral port 291 test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, 0, test->server_hostname, test->server_port); 292 if (test->ctrl_sck < 0) { 293 i_errno = IECONNECT; 294 return -1; 295 } 296 297 if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) { 298 i_errno = IESENDCOOKIE; 299 return -1; 300 } 301 302 FD_SET(test->ctrl_sck, &test->read_set); 303 if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck; 304 305 return 0; 306 } 307 308 309 int 310 iperf_client_end(struct iperf_test *test) 311 { 312 struct iperf_stream *sp; 313 314 /* Close all stream sockets */ 315 SLIST_FOREACH(sp, &test->streams, streams) { 316 close(sp->socket); 317 } 318 319 /* show final summary */ 320 test->reporter_callback(test); 321 322 if (iperf_set_send_state(test, IPERF_DONE) != 0) 323 return -1; 324 325 return 0; 326 } 327 328 329 static jmp_buf sigend_jmp_buf; 330 331 static void 332 sigend_handler(int sig) 333 { 334 longjmp(sigend_jmp_buf, 1); 335 } 336 337 338 int 339 iperf_run_client(struct iperf_test * test) 340 { 341 int startup; 342 int result = 0; 343 fd_set read_set, write_set; 344 struct timeval now; 345 struct timeval* timeout = NULL; 346 struct iperf_stream *sp; 347 348 /* Termination signals. */ 349 iperf_catch_sigend(sigend_handler); 350 if (setjmp(sigend_jmp_buf)) 351 iperf_got_sigend(test); 352 353 if (test->affinity != -1) 354 if (iperf_setaffinity(test, test->affinity) != 0) 355 return -1; 356 357 if (test->json_output) 358 if (iperf_json_start(test) < 0) 359 return -1; 360 361 if (test->json_output) { 362 cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version)); 363 cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info())); 364 } else if (test->verbose) { 365 iprintf(test, "%s\n", version); 366 iprintf(test, "%s", ""); 367 iprintf(test, "%s\n", get_system_info()); 368 iflush(test); 369 } 370 371 /* Start the client and connect to the server */ 372 if (iperf_connect(test) < 0) 373 return -1; 374 375 /* Begin calculating CPU utilization */ 376 cpu_util(NULL); 377 378 startup = 1; 379 while (test->state != IPERF_DONE) { 380 memcpy(&read_set, &test->read_set, sizeof(fd_set)); 381 memcpy(&write_set, &test->write_set, sizeof(fd_set)); 382 (void) gettimeofday(&now, NULL); 383 timeout = tmr_timeout(&now); 384 result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout); 385 if (result < 0 && errno != EINTR) { 386 i_errno = IESELECT; 387 return -1; 388 } 389 if (result > 0) { 390 if (FD_ISSET(test->ctrl_sck, &read_set)) { 391 if (iperf_handle_message_client(test) < 0) { 392 return -1; 393 } 394 FD_CLR(test->ctrl_sck, &read_set); 395 } 396 } 397 398 if (test->state == TEST_RUNNING) { 399 400 /* Is this our first time really running? */ 401 if (startup) { 402 startup = 0; 403 404 // Set non-blocking for non-UDP tests 405 if (test->protocol->id != Pudp) { 406 SLIST_FOREACH(sp, &test->streams, streams) { 407 setnonblocking(sp->socket, 1); 408 } 409 } 410 } 411 412 if (test->reverse) { 413 // Reverse mode. Client receives. 414 if (iperf_recv(test, &read_set) < 0) 415 return -1; 416 } else { 417 // Regular mode. Client sends. 418 if (iperf_send(test, &write_set) < 0) 419 return -1; 420 } 421 422 /* Run the timers. */ 423 (void) gettimeofday(&now, NULL); 424 tmr_run(&now); 425 426 /* Is the test done yet? */ 427 if ((!test->omitting) && 428 ((test->duration != 0 && test->done) || 429 (test->settings->bytes != 0 && test->bytes_sent >= test->settings->bytes) || 430 (test->settings->blocks != 0 && test->blocks_sent >= test->settings->blocks))) { 431 432 // Unset non-blocking for non-UDP tests 433 if (test->protocol->id != Pudp) { 434 SLIST_FOREACH(sp, &test->streams, streams) { 435 setnonblocking(sp->socket, 0); 436 } 437 } 438 439 /* Yes, done! Send TEST_END. */ 440 test->done = 1; 441 cpu_util(test->cpu_util); 442 test->stats_callback(test); 443 if (iperf_set_send_state(test, TEST_END) != 0) 444 return -1; 445 } 446 } 447 // If we're in reverse mode, continue draining the data 448 // connection(s) even if test is over. This prevents a 449 // deadlock where the server side fills up its pipe(s) 450 // and gets blocked, so it can't receive state changes 451 // from the client side. 452 else if (test->reverse && test->state == TEST_END) { 453 if (iperf_recv(test, &read_set) < 0) 454 return -1; 455 } 456 } 457 458 if (test->json_output) { 459 if (iperf_json_finish(test) < 0) 460 return -1; 461 } else { 462 iprintf(test, "\n"); 463 iprintf(test, "%s", report_done); 464 } 465 466 iflush(test); 467 468 return 0; 469 } 470