1a951c980SBrian Tierney /* 27d375156SJon Dugan * Copyright (c) 2009-2011, The Regents of the University of California, 37d375156SJon Dugan * through Lawrence Berkeley National Laboratory (subject to receipt of any 47d375156SJon Dugan * required approvals from the U.S. Dept. of Energy). All rights reserved. 57d375156SJon Dugan * 67d375156SJon Dugan * This code is distributed under a BSD style license, see the LICENSE file 77d375156SJon Dugan * for complete information. 8a951c980SBrian Tierney */ 9a951c980SBrian Tierney 10a951c980SBrian Tierney /* iperf_server_api.c: Functions to be used by an iperf server 11a951c980SBrian Tierney */ 12a951c980SBrian Tierney 13a951c980SBrian Tierney #include <stdio.h> 14a951c980SBrian Tierney #include <stdlib.h> 15a951c980SBrian Tierney #include <string.h> 16a951c980SBrian Tierney #include <getopt.h> 17a951c980SBrian Tierney #include <errno.h> 18a951c980SBrian Tierney #include <unistd.h> 19a951c980SBrian Tierney #include <assert.h> 20a951c980SBrian Tierney #include <fcntl.h> 21a951c980SBrian Tierney #include <sys/socket.h> 22a951c980SBrian Tierney #include <sys/types.h> 23a951c980SBrian Tierney #include <netinet/in.h> 24a951c980SBrian Tierney #include <arpa/inet.h> 25a951c980SBrian Tierney #include <netdb.h> 26a951c980SBrian Tierney #include <pthread.h> 27a951c980SBrian Tierney #include <stdint.h> 28a951c980SBrian Tierney #include <netinet/tcp.h> 29a951c980SBrian Tierney #include <sys/time.h> 30a951c980SBrian Tierney #include <sys/resource.h> 31a951c980SBrian Tierney #include <sched.h> 32a951c980SBrian Tierney #include <setjmp.h> 33a951c980SBrian Tierney 34a951c980SBrian Tierney #include "iperf.h" 35a951c980SBrian Tierney #include "iperf_api.h" 36a951c980SBrian Tierney #include "iperf_udp.h" 37a951c980SBrian Tierney #include "iperf_tcp.h" 388a0b5a5dSsethdelliott #include "iperf_util.h" 39a951c980SBrian Tierney #include "timer.h" 40a951c980SBrian Tierney #include "net.h" 41a951c980SBrian Tierney #include "units.h" 42a951c980SBrian Tierney #include "tcp_window_size.h" 43b0b16b86SJon Dugan #include "iperf_util.h" 44a951c980SBrian Tierney #include "locale.h" 45a951c980SBrian Tierney 46a3281a3dSBrian Tierney 47982c704aSsethdelliott int 48982c704aSsethdelliott iperf_server_listen(struct iperf_test *test) 49982c704aSsethdelliott { 50f99bd3b2Ssethdelliott if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { 51b60a49ddSsethdelliott i_errno = IELISTEN; 52ec2d0670SJef Poskanzer return -1; 53982c704aSsethdelliott } 54982c704aSsethdelliott 559bfb54c0SJef Poskanzer if (!test->json_output) { 56982c704aSsethdelliott printf("-----------------------------------------------------------\n"); 57982c704aSsethdelliott printf("Server listening on %d\n", test->server_port); 589bfb54c0SJef Poskanzer } 59982c704aSsethdelliott 60982c704aSsethdelliott // This needs to be changed to reflect if client has different window size 61982c704aSsethdelliott // make sure we got what we asked for 62ba2672a2Ssethdelliott /* XXX: This needs to be moved to the stream listener 6366ce7ad4Ssethdelliott if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) { 64982c704aSsethdelliott // Needs to set some sort of error number/message 65982c704aSsethdelliott perror("SO_RCVBUF"); 66982c704aSsethdelliott return -1; 67982c704aSsethdelliott } 68ba2672a2Ssethdelliott */ 69982c704aSsethdelliott 70ba2672a2Ssethdelliott // XXX: This code needs to be moved to after parameter exhange 71c81883bfSsethdelliott /* 7298ce496bSjef char ubuf[UNIT_LEN]; 7398ce496bSjef int x; 7498ce496bSjef 7566ce7ad4Ssethdelliott if (test->protocol->id == Ptcp) { 76112a907cSsethdelliott if (test->settings->socket_bufsize > 0) { 77982c704aSsethdelliott unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A'); 789bfb54c0SJef Poskanzer if (test->json_output) 79982c704aSsethdelliott printf("TCP window size: %s\n", ubuf); 80982c704aSsethdelliott } else { 819bfb54c0SJef Poskanzer if (test->json_output) 82982c704aSsethdelliott printf("Using TCP Autotuning\n"); 83982c704aSsethdelliott } 84982c704aSsethdelliott } 85c81883bfSsethdelliott */ 869bfb54c0SJef Poskanzer if (!test->json_output) 87982c704aSsethdelliott printf("-----------------------------------------------------------\n"); 88982c704aSsethdelliott 89982c704aSsethdelliott FD_ZERO(&test->read_set); 90efdc02f7Ssethdelliott FD_ZERO(&test->write_set); 9166ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 9266ce7ad4Ssethdelliott test->max_fd = (test->listener > test->max_fd) ? test->listener : test->max_fd; 93982c704aSsethdelliott 94982c704aSsethdelliott return 0; 95982c704aSsethdelliott } 96982c704aSsethdelliott 97982c704aSsethdelliott int 98982c704aSsethdelliott iperf_accept(struct iperf_test *test) 99982c704aSsethdelliott { 100982c704aSsethdelliott int s; 101465b565cSsethdelliott int rbuf = ACCESS_DENIED; 102af70b448Ssethdelliott char cookie[COOKIE_SIZE]; 103982c704aSsethdelliott socklen_t len; 10412d474e2SJef Poskanzer struct sockaddr_storage addr; 105982c704aSsethdelliott 106b68ac00eSsethdelliott len = sizeof(addr); 10766ce7ad4Ssethdelliott if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { 108b60a49ddSsethdelliott i_errno = IEACCEPT; 109ec2d0670SJef Poskanzer return -1; 110982c704aSsethdelliott } 111af70b448Ssethdelliott 112af70b448Ssethdelliott if (test->ctrl_sck == -1) { 113af70b448Ssethdelliott /* Server free, accept new client */ 114112a907cSsethdelliott if (Nread(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { 115b60a49ddSsethdelliott i_errno = IERECVCOOKIE; 116ec2d0670SJef Poskanzer return -1; 117af70b448Ssethdelliott } 118af70b448Ssethdelliott 119465b565cSsethdelliott FD_SET(s, &test->read_set); 120465b565cSsethdelliott FD_SET(s, &test->write_set); 121465b565cSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 122465b565cSsethdelliott test->ctrl_sck = s; 123982c704aSsethdelliott 124af70b448Ssethdelliott test->state = PARAM_EXCHANGE; 125af70b448Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 126b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 127ec2d0670SJef Poskanzer return -1; 128af70b448Ssethdelliott } 129b60a49ddSsethdelliott if (iperf_exchange_parameters(test) < 0) { 130ec2d0670SJef Poskanzer return -1; 131b60a49ddSsethdelliott } 1324df383f6Ssethdelliott if (test->on_connect) { 1334df383f6Ssethdelliott test->on_connect(test); 1344df383f6Ssethdelliott } 135982c704aSsethdelliott } else { 136111645edSJef Poskanzer /* XXX: Do we even need to receive cookie if we're just going to deny anyways? */ 137af70b448Ssethdelliott if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { 138b60a49ddSsethdelliott i_errno = IERECVCOOKIE; 139ec2d0670SJef Poskanzer return -1; 140465b565cSsethdelliott } 141987b4323SJef Poskanzer if (Nwrite(s, (char*) &rbuf, sizeof(int), Ptcp) < 0) { 142b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 143ec2d0670SJef Poskanzer return -1; 144465b565cSsethdelliott } 145465b565cSsethdelliott close(s); 146982c704aSsethdelliott } 147982c704aSsethdelliott 148ec2d0670SJef Poskanzer return 0; 149af70b448Ssethdelliott } 150af70b448Ssethdelliott 151b68ac00eSsethdelliott 152a951c980SBrian Tierney /**************************************************************************/ 153982c704aSsethdelliott int 154465b565cSsethdelliott iperf_handle_message_server(struct iperf_test *test) 155982c704aSsethdelliott { 156b68ac00eSsethdelliott int rval; 157efdc02f7Ssethdelliott struct iperf_stream *sp; 158efdc02f7Ssethdelliott 159b60a49ddSsethdelliott // XXX: Need to rethink how this behaves to fit API 160b60a49ddSsethdelliott if ((rval = Nread(test->ctrl_sck, &test->state, sizeof(char), Ptcp)) <= 0) { 161b68ac00eSsethdelliott if (rval == 0) { 162b5e0751fSJef Poskanzer iperf_err(test, "the client has unexpectedly closed the connection"); 163b60a49ddSsethdelliott i_errno = IECTRLCLOSE; 164b68ac00eSsethdelliott test->state = IPERF_DONE; 165ec2d0670SJef Poskanzer return 0; 166b68ac00eSsethdelliott } else { 167b60a49ddSsethdelliott i_errno = IERECVMESSAGE; 168ec2d0670SJef Poskanzer return -1; 169982c704aSsethdelliott } 170b68ac00eSsethdelliott } 171982c704aSsethdelliott 172982c704aSsethdelliott switch(test->state) { 173ba2672a2Ssethdelliott case TEST_START: 174ba2672a2Ssethdelliott break; 175465b565cSsethdelliott case TEST_END: 1763331e801Ssethdelliott cpu_util(&test->cpu_util); 177f1b3bd81Ssethdelliott test->stats_callback(test); 178dd4bc008Ssethdelliott SLIST_FOREACH(sp, &test->streams, streams) { 179efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->read_set); 180efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->write_set); 181efdc02f7Ssethdelliott close(sp->socket); 182efdc02f7Ssethdelliott } 183181d61afSsethdelliott test->state = EXCHANGE_RESULTS; 184efb7bbe4Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 185b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 186ec2d0670SJef Poskanzer return -1; 187181d61afSsethdelliott } 188*69bdbfd3SJef Poskanzer if (iperf_sum_results(test) < 0) 189*69bdbfd3SJef Poskanzer return -1; 190b60a49ddSsethdelliott if (iperf_exchange_results(test) < 0) 191ec2d0670SJef Poskanzer return -1; 192873952e3Ssethdelliott test->state = DISPLAY_RESULTS; 193efb7bbe4Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 194b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 195ec2d0670SJef Poskanzer return -1; 196465b565cSsethdelliott } 1974df383f6Ssethdelliott if (test->on_test_finish) 1984df383f6Ssethdelliott test->on_test_finish(test); 199181d61afSsethdelliott test->reporter_callback(test); 200465b565cSsethdelliott break; 201873952e3Ssethdelliott case IPERF_DONE: 202873952e3Ssethdelliott break; 203465b565cSsethdelliott case CLIENT_TERMINATE: 204ffdcc7d4Ssethdelliott i_errno = IECLIENTTERM; 205ffdcc7d4Ssethdelliott 206ffdcc7d4Ssethdelliott // XXX: Remove this line below! 207b5e0751fSJef Poskanzer iperf_err(test, "the client has terminated"); 208dd4bc008Ssethdelliott SLIST_FOREACH(sp, &test->streams, streams) { 2091ac522ecSsethdelliott FD_CLR(sp->socket, &test->read_set); 2101ac522ecSsethdelliott FD_CLR(sp->socket, &test->write_set); 2111ac522ecSsethdelliott close(sp->socket); 2121ac522ecSsethdelliott } 2131ac522ecSsethdelliott test->state = IPERF_DONE; 2141ac522ecSsethdelliott break; 215ba2672a2Ssethdelliott default: 216b60a49ddSsethdelliott i_errno = IEMESSAGE; 217ec2d0670SJef Poskanzer return -1; 218982c704aSsethdelliott } 219982c704aSsethdelliott 220ec2d0670SJef Poskanzer return 0; 221982c704aSsethdelliott } 222982c704aSsethdelliott 2230bd8d9daSsethdelliott /* XXX: This function is not used anymore */ 224efdc02f7Ssethdelliott void 225efdc02f7Ssethdelliott iperf_test_reset(struct iperf_test *test) 226efdc02f7Ssethdelliott { 2270bd8d9daSsethdelliott struct iperf_stream *sp; 228efdc02f7Ssethdelliott 229efdc02f7Ssethdelliott close(test->ctrl_sck); 230efdc02f7Ssethdelliott 231efdc02f7Ssethdelliott /* Free streams */ 232dd4bc008Ssethdelliott while (!SLIST_EMPTY(&test->streams)) { 233dd4bc008Ssethdelliott sp = SLIST_FIRST(&test->streams); 234dd4bc008Ssethdelliott SLIST_REMOVE_HEAD(&test->streams, streams); 235dd4bc008Ssethdelliott iperf_free_stream(sp); 236dd4bc008Ssethdelliott } 237ec2d0670SJef Poskanzer if (test->timer != NULL) { 238ec2d0670SJef Poskanzer tmr_cancel(test->timer); 239f1b3bd81Ssethdelliott test->timer = NULL; 240ec2d0670SJef Poskanzer } 241ec2d0670SJef Poskanzer if (test->stats_timer != NULL) { 242ec2d0670SJef Poskanzer tmr_cancel(test->stats_timer); 243f1b3bd81Ssethdelliott test->stats_timer = NULL; 244ec2d0670SJef Poskanzer } 245ec2d0670SJef Poskanzer if (test->reporter_timer != NULL) { 246ec2d0670SJef Poskanzer tmr_cancel(test->reporter_timer); 247f1b3bd81Ssethdelliott test->reporter_timer = NULL; 248ec2d0670SJef Poskanzer } 249efdc02f7Ssethdelliott 250dd4bc008Ssethdelliott SLIST_INIT(&test->streams); 25132885561Ssethdelliott 252efdc02f7Ssethdelliott test->role = 's'; 25366ce7ad4Ssethdelliott set_protocol(test, Ptcp); 25432885561Ssethdelliott test->duration = DURATION; 25532885561Ssethdelliott test->state = 0; 25632885561Ssethdelliott test->server_hostname = NULL; 25732885561Ssethdelliott 25832885561Ssethdelliott test->ctrl_sck = -1; 25966ce7ad4Ssethdelliott test->prot_listener = -1; 26032885561Ssethdelliott 261f1b3bd81Ssethdelliott test->bytes_sent = 0; 262f1b3bd81Ssethdelliott 26332885561Ssethdelliott test->reverse = 0; 2642c042fd4SJef Poskanzer test->sender = 0; 265*69bdbfd3SJef Poskanzer test->sender_has_retransmits = 0; 266b68ac00eSsethdelliott test->no_delay = 0; 26732885561Ssethdelliott 268efdc02f7Ssethdelliott FD_ZERO(&test->read_set); 269efdc02f7Ssethdelliott FD_ZERO(&test->write_set); 27066ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 27166ce7ad4Ssethdelliott test->max_fd = test->listener; 27232885561Ssethdelliott 27332885561Ssethdelliott test->num_streams = 1; 274112a907cSsethdelliott test->settings->socket_bufsize = 0; 275112a907cSsethdelliott test->settings->blksize = DEFAULT_TCP_BLKSIZE; 276112a907cSsethdelliott test->settings->rate = RATE; /* UDP only */ 277112a907cSsethdelliott test->settings->mss = 0; 278112a907cSsethdelliott memset(test->cookie, 0, COOKIE_SIZE); 279efdc02f7Ssethdelliott } 280efdc02f7Ssethdelliott 2817fa9f68fSsethdelliott int 282a951c980SBrian Tierney iperf_run_server(struct iperf_test *test) 283a951c980SBrian Tierney { 284112a907cSsethdelliott int result, s, streams_accepted; 2856177a7f1SJef Poskanzer fd_set read_set, write_set; 2868a0b5a5dSsethdelliott struct iperf_stream *sp; 287ec2d0670SJef Poskanzer struct timeval now; 288a951c980SBrian Tierney 289e96ab740SJef Poskanzer if (test->json_output) 290e96ab740SJef Poskanzer if (iperf_json_start(test) < 0) 291e96ab740SJef Poskanzer return -1; 292e96ab740SJef Poskanzer 293e96ab740SJef Poskanzer if (test->json_output) { 294e96ab740SJef Poskanzer cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version)); 295e96ab740SJef Poskanzer cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info())); 296e96ab740SJef Poskanzer } else if (test->verbose) { 297e96ab740SJef Poskanzer printf("%s\n", version); 298e96ab740SJef Poskanzer system("uname -a"); 299e96ab740SJef Poskanzer } 300e96ab740SJef Poskanzer 301982c704aSsethdelliott // Open socket and listen 302982c704aSsethdelliott if (iperf_server_listen(test) < 0) { 303ec2d0670SJef Poskanzer return -1; 304e99faeaeSBrian Tierney } 305a951c980SBrian Tierney 3063331e801Ssethdelliott // Begin calculating CPU utilization 3073331e801Ssethdelliott cpu_util(NULL); 3083331e801Ssethdelliott 309efdc02f7Ssethdelliott test->state = IPERF_START; 310112a907cSsethdelliott streams_accepted = 0; 311a951c980SBrian Tierney 312ec2d0670SJef Poskanzer (void) gettimeofday(&now, NULL); 313873952e3Ssethdelliott while (test->state != IPERF_DONE) { 314982c704aSsethdelliott 3156177a7f1SJef Poskanzer memcpy(&read_set, &test->read_set, sizeof(fd_set)); 3166177a7f1SJef Poskanzer memcpy(&write_set, &test->write_set, sizeof(fd_set)); 317982c704aSsethdelliott 3186177a7f1SJef Poskanzer result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now)); 319982c704aSsethdelliott if (result < 0 && errno != EINTR) { 320b60a49ddSsethdelliott i_errno = IESELECT; 321ec2d0670SJef Poskanzer return -1; 322ec2d0670SJef Poskanzer } 323ec2d0670SJef Poskanzer if (result > 0) { 3246177a7f1SJef Poskanzer if (FD_ISSET(test->listener, &read_set)) { 325b68ac00eSsethdelliott if (test->state != CREATE_STREAMS) { 326465b565cSsethdelliott if (iperf_accept(test) < 0) { 327ec2d0670SJef Poskanzer return -1; 328982c704aSsethdelliott } 3296177a7f1SJef Poskanzer FD_CLR(test->listener, &read_set); 330982c704aSsethdelliott } 331b68ac00eSsethdelliott } 3326177a7f1SJef Poskanzer if (FD_ISSET(test->ctrl_sck, &read_set)) { 333b60a49ddSsethdelliott if (iperf_handle_message_server(test) < 0) 334ec2d0670SJef Poskanzer return -1; 3356177a7f1SJef Poskanzer FD_CLR(test->ctrl_sck, &read_set); 336982c704aSsethdelliott } 337465b565cSsethdelliott 338465b565cSsethdelliott if (test->state == CREATE_STREAMS) { 3396177a7f1SJef Poskanzer if (FD_ISSET(test->prot_listener, &read_set)) { 3408a0b5a5dSsethdelliott 34166ce7ad4Ssethdelliott if ((s = test->protocol->accept(test)) < 0) 342ec2d0670SJef Poskanzer return -1; 3438a0b5a5dSsethdelliott 3448a0b5a5dSsethdelliott if (!is_closed(s)) { 34566ce7ad4Ssethdelliott sp = iperf_new_stream(test, s); 3468a0b5a5dSsethdelliott if (!sp) 347ec2d0670SJef Poskanzer return -1; 34866ce7ad4Ssethdelliott 3498a0b5a5dSsethdelliott FD_SET(s, &test->read_set); 3508a0b5a5dSsethdelliott FD_SET(s, &test->write_set); 3518a0b5a5dSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 35266ce7ad4Ssethdelliott 353112a907cSsethdelliott streams_accepted++; 3544df383f6Ssethdelliott if (test->on_new_stream) 3554df383f6Ssethdelliott test->on_new_stream(sp); 356b68ac00eSsethdelliott } 3576177a7f1SJef Poskanzer FD_CLR(test->prot_listener, &read_set); 358b68ac00eSsethdelliott } 3598a0b5a5dSsethdelliott 360112a907cSsethdelliott if (streams_accepted == test->num_streams) { 36166ce7ad4Ssethdelliott if (test->protocol->id != Ptcp) { 3628a0b5a5dSsethdelliott FD_CLR(test->prot_listener, &test->read_set); 3638a0b5a5dSsethdelliott close(test->prot_listener); 36466ce7ad4Ssethdelliott } else { 3650bd8d9daSsethdelliott if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { 36666ce7ad4Ssethdelliott FD_CLR(test->listener, &test->read_set); 36766ce7ad4Ssethdelliott close(test->listener); 368f99bd3b2Ssethdelliott if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { 369b60a49ddSsethdelliott i_errno = IELISTEN; 370ec2d0670SJef Poskanzer return -1; 371c81883bfSsethdelliott } 37266ce7ad4Ssethdelliott test->listener = s; 373c81883bfSsethdelliott test->max_fd = (s > test->max_fd ? s : test->max_fd); 37466ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 375c81883bfSsethdelliott } 3768556db5dSsethdelliott } 3778a0b5a5dSsethdelliott test->prot_listener = -1; 378465b565cSsethdelliott test->state = TEST_START; 379b68ac00eSsethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 380b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 381ec2d0670SJef Poskanzer return -1; 382982c704aSsethdelliott } 383b60a49ddSsethdelliott if (iperf_init_test(test) < 0) 384ec2d0670SJef Poskanzer return -1; 385f1b3bd81Ssethdelliott test->state = TEST_RUNNING; 386f1b3bd81Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 387b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 388ec2d0670SJef Poskanzer return -1; 389f1b3bd81Ssethdelliott } 390982c704aSsethdelliott } 391982c704aSsethdelliott } 392982c704aSsethdelliott 393f1b3bd81Ssethdelliott if (test->state == TEST_RUNNING) { 394465b565cSsethdelliott if (test->reverse) { 395465b565cSsethdelliott // Reverse mode. Server sends. 3966177a7f1SJef Poskanzer if (iperf_send(test, &write_set) < 0) 397ec2d0670SJef Poskanzer return -1; 398982c704aSsethdelliott } else { 399465b565cSsethdelliott // Regular mode. Server receives. 4006177a7f1SJef Poskanzer if (iperf_recv(test, &read_set) < 0) 401ec2d0670SJef Poskanzer return -1; 402e99faeaeSBrian Tierney } 403f1b3bd81Ssethdelliott 404ec2d0670SJef Poskanzer /* Run the timers. */ 405ec2d0670SJef Poskanzer (void) gettimeofday(&now, NULL); 406ec2d0670SJef Poskanzer tmr_run(&now); 407f1b3bd81Ssethdelliott } 408a951c980SBrian Tierney } 409982c704aSsethdelliott } 410e99faeaeSBrian Tierney 41102a35f07Ssethdelliott /* Close open test sockets */ 4120bd8d9daSsethdelliott close(test->ctrl_sck); 4130bd8d9daSsethdelliott close(test->listener); 414efdc02f7Ssethdelliott 415e96ab740SJef Poskanzer if (test->json_output) { 416e96ab740SJef Poskanzer if (iperf_json_finish(test) < 0) 417e96ab740SJef Poskanzer return -1; 418e96ab740SJef Poskanzer } 419e96ab740SJef Poskanzer 420ec2d0670SJef Poskanzer return 0; 421a3281a3dSBrian Tierney } 422