1a951c980SBrian Tierney 2a951c980SBrian Tierney /* 3a951c980SBrian Tierney * Copyright (c) 2009, The Regents of the University of California, through 4a951c980SBrian Tierney * Lawrence Berkeley National Laboratory (subject to receipt of any required 5a951c980SBrian Tierney * approvals from the U.S. Dept. of Energy). All rights reserved. 6a951c980SBrian Tierney */ 7a951c980SBrian Tierney 8a951c980SBrian Tierney /* iperf_server_api.c: Functions to be used by an iperf server 9a951c980SBrian Tierney */ 10a951c980SBrian Tierney 11a951c980SBrian Tierney #include <stdio.h> 12a951c980SBrian Tierney #include <stdlib.h> 13a951c980SBrian Tierney #include <string.h> 14a951c980SBrian Tierney #include <getopt.h> 15a951c980SBrian Tierney #include <errno.h> 16a951c980SBrian Tierney #include <signal.h> 17a951c980SBrian Tierney #include <unistd.h> 18a951c980SBrian Tierney #include <assert.h> 19a951c980SBrian Tierney #include <fcntl.h> 208a0b5a5dSsethdelliott #include <sys/queue.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_server_api.h" 36a951c980SBrian Tierney #include "iperf_api.h" 37a951c980SBrian Tierney #include "iperf_udp.h" 38a951c980SBrian Tierney #include "iperf_tcp.h" 39b60a49ddSsethdelliott #include "iperf_error.h" 408a0b5a5dSsethdelliott #include "iperf_util.h" 41a951c980SBrian Tierney #include "timer.h" 42a951c980SBrian Tierney #include "net.h" 43a951c980SBrian Tierney #include "units.h" 44a951c980SBrian Tierney #include "tcp_window_size.h" 45b0b16b86SJon Dugan #include "iperf_util.h" 46a951c980SBrian Tierney #include "locale.h" 47a951c980SBrian Tierney 48a3281a3dSBrian Tierney 49982c704aSsethdelliott int 50982c704aSsethdelliott iperf_server_listen(struct iperf_test *test) 51982c704aSsethdelliott { 52982c704aSsethdelliott char ubuf[UNIT_LEN]; 53982c704aSsethdelliott int x; 54982c704aSsethdelliott 5566ce7ad4Ssethdelliott if((test->listener = netannounce(Ptcp, NULL, test->server_port)) < 0) { 56b60a49ddSsethdelliott i_errno = IELISTEN; 57b60a49ddSsethdelliott return (-1); 58982c704aSsethdelliott } 59982c704aSsethdelliott 60982c704aSsethdelliott printf("-----------------------------------------------------------\n"); 61982c704aSsethdelliott printf("Server listening on %d\n", test->server_port); 62982c704aSsethdelliott 63982c704aSsethdelliott // This needs to be changed to reflect if client has different window size 64982c704aSsethdelliott // make sure we got what we asked for 65ba2672a2Ssethdelliott /* XXX: This needs to be moved to the stream listener 6666ce7ad4Ssethdelliott if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) { 67982c704aSsethdelliott // Needs to set some sort of error number/message 68982c704aSsethdelliott perror("SO_RCVBUF"); 69982c704aSsethdelliott return -1; 70982c704aSsethdelliott } 71ba2672a2Ssethdelliott */ 72982c704aSsethdelliott 73ba2672a2Ssethdelliott // XXX: This code needs to be moved to after parameter exhange 74c81883bfSsethdelliott /* 7566ce7ad4Ssethdelliott if (test->protocol->id == Ptcp) { 76*112a907cSsethdelliott if (test->settings->socket_bufsize > 0) { 77982c704aSsethdelliott unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A'); 78982c704aSsethdelliott printf("TCP window size: %s\n", ubuf); 79982c704aSsethdelliott } else { 80982c704aSsethdelliott printf("Using TCP Autotuning\n"); 81982c704aSsethdelliott } 82982c704aSsethdelliott } 83c81883bfSsethdelliott */ 84982c704aSsethdelliott printf("-----------------------------------------------------------\n"); 85982c704aSsethdelliott 86982c704aSsethdelliott FD_ZERO(&test->read_set); 87efdc02f7Ssethdelliott FD_ZERO(&test->write_set); 8866ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 8966ce7ad4Ssethdelliott test->max_fd = (test->listener > test->max_fd) ? test->listener : test->max_fd; 90982c704aSsethdelliott 91982c704aSsethdelliott return 0; 92982c704aSsethdelliott } 93982c704aSsethdelliott 94982c704aSsethdelliott int 95982c704aSsethdelliott iperf_accept(struct iperf_test *test) 96982c704aSsethdelliott { 97982c704aSsethdelliott int s; 98465b565cSsethdelliott int rbuf = ACCESS_DENIED; 99b60a49ddSsethdelliott char ipl[512], ipr[512]; // XXX: This is overkill. Max length of IPv6 address = 46 (INET6_ADDRSTRLEN) 100af70b448Ssethdelliott char cookie[COOKIE_SIZE]; 101982c704aSsethdelliott socklen_t len; 102982c704aSsethdelliott struct sockaddr_in addr; 103465b565cSsethdelliott struct sockaddr_in temp1, temp2; 104982c704aSsethdelliott 105b68ac00eSsethdelliott len = sizeof(addr); 10666ce7ad4Ssethdelliott if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { 107b60a49ddSsethdelliott i_errno = IEACCEPT; 108b60a49ddSsethdelliott return (-1); 109982c704aSsethdelliott } 110af70b448Ssethdelliott 111af70b448Ssethdelliott if (test->ctrl_sck == -1) { 112af70b448Ssethdelliott /* Server free, accept new client */ 113*112a907cSsethdelliott if (Nread(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { 114b60a49ddSsethdelliott i_errno = IERECVCOOKIE; 115b60a49ddSsethdelliott return (-1); 116af70b448Ssethdelliott } 117af70b448Ssethdelliott 118465b565cSsethdelliott FD_SET(s, &test->read_set); 119465b565cSsethdelliott FD_SET(s, &test->write_set); 120465b565cSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 121465b565cSsethdelliott test->ctrl_sck = s; 122982c704aSsethdelliott 123465b565cSsethdelliott len = sizeof(struct sockaddr_in); 124b60a49ddSsethdelliott if (getsockname(s, (struct sockaddr *) &temp1, &len) < 0) { 125b60a49ddSsethdelliott i_errno = IEACCEPT; 126b60a49ddSsethdelliott return (-1); 127b60a49ddSsethdelliott } 128b60a49ddSsethdelliott if (getpeername(s, (struct sockaddr *) &temp2, &len) < 0) { 129b60a49ddSsethdelliott i_errno = IEACCEPT; 130b60a49ddSsethdelliott return (-1); 131b60a49ddSsethdelliott } 132982c704aSsethdelliott 133b60a49ddSsethdelliott // XXX: Check inet_ntop for errors? 134465b565cSsethdelliott inet_ntop(AF_INET, (void *) &temp1.sin_addr, ipl, sizeof(ipl)); 135465b565cSsethdelliott inet_ntop(AF_INET, (void *) &temp2.sin_addr, ipr, sizeof(ipr)); 136b60a49ddSsethdelliott 137465b565cSsethdelliott printf(report_peer, s, ipl, ntohs(temp1.sin_port), ipr, ntohs(temp2.sin_port)); 138465b565cSsethdelliott 139af70b448Ssethdelliott test->state = PARAM_EXCHANGE; 140af70b448Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 141b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 142b60a49ddSsethdelliott return (-1); 143af70b448Ssethdelliott } 144b60a49ddSsethdelliott if (iperf_exchange_parameters(test) < 0) { 145b60a49ddSsethdelliott return (-1); 146b60a49ddSsethdelliott } 147982c704aSsethdelliott } else { 148b60a49ddSsethdelliott // XXX: Do we even need to receive cookie if we're just going to deny anyways? 149af70b448Ssethdelliott if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { 150b60a49ddSsethdelliott i_errno = IERECVCOOKIE; 151b60a49ddSsethdelliott return (-1); 152465b565cSsethdelliott } 153efb7bbe4Ssethdelliott if (Nwrite(s, &rbuf, sizeof(int), Ptcp) < 0) { 154b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 155b60a49ddSsethdelliott return (-1); 156465b565cSsethdelliott } 157465b565cSsethdelliott close(s); 158982c704aSsethdelliott } 159982c704aSsethdelliott 160b60a49ddSsethdelliott return (0); 161af70b448Ssethdelliott } 162af70b448Ssethdelliott 163b68ac00eSsethdelliott 164a951c980SBrian Tierney /**************************************************************************/ 165982c704aSsethdelliott int 166465b565cSsethdelliott iperf_handle_message_server(struct iperf_test *test) 167982c704aSsethdelliott { 168b68ac00eSsethdelliott int rval; 169efdc02f7Ssethdelliott struct iperf_stream *sp; 170efdc02f7Ssethdelliott 171b60a49ddSsethdelliott // XXX: Need to rethink how this behaves to fit API 172b60a49ddSsethdelliott if ((rval = Nread(test->ctrl_sck, &test->state, sizeof(char), Ptcp)) <= 0) { 173b68ac00eSsethdelliott if (rval == 0) { 174b68ac00eSsethdelliott fprintf(stderr, "The client has unexpectedly closed the connection.\n"); 175b60a49ddSsethdelliott i_errno = IECTRLCLOSE; 176b68ac00eSsethdelliott test->state = IPERF_DONE; 177b60a49ddSsethdelliott return (0); 178b68ac00eSsethdelliott } else { 179b60a49ddSsethdelliott i_errno = IERECVMESSAGE; 180b60a49ddSsethdelliott return (-1); 181982c704aSsethdelliott } 182b68ac00eSsethdelliott } 183982c704aSsethdelliott 184982c704aSsethdelliott switch(test->state) { 185ba2672a2Ssethdelliott case TEST_START: 186ba2672a2Ssethdelliott break; 187465b565cSsethdelliott case TEST_END: 188f1b3bd81Ssethdelliott test->stats_callback(test); 189efdc02f7Ssethdelliott for (sp = test->streams; sp; sp = sp->next) { 190efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->read_set); 191efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->write_set); 192efdc02f7Ssethdelliott close(sp->socket); 193efdc02f7Ssethdelliott } 194181d61afSsethdelliott test->state = EXCHANGE_RESULTS; 195efb7bbe4Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 196b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 197b60a49ddSsethdelliott return (-1); 198181d61afSsethdelliott } 199b60a49ddSsethdelliott if (iperf_exchange_results(test) < 0) 200b60a49ddSsethdelliott return (-1); 201873952e3Ssethdelliott test->state = DISPLAY_RESULTS; 202efb7bbe4Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 203b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 204b60a49ddSsethdelliott return (-1); 205465b565cSsethdelliott } 206181d61afSsethdelliott test->reporter_callback(test); 207465b565cSsethdelliott break; 208873952e3Ssethdelliott case IPERF_DONE: 209873952e3Ssethdelliott break; 210465b565cSsethdelliott case CLIENT_TERMINATE: 2111ac522ecSsethdelliott fprintf(stderr, "The client has terminated.\n"); 2121ac522ecSsethdelliott for (sp = test->streams; sp; sp = sp->next) { 2131ac522ecSsethdelliott FD_CLR(sp->socket, &test->read_set); 2141ac522ecSsethdelliott FD_CLR(sp->socket, &test->write_set); 2151ac522ecSsethdelliott close(sp->socket); 2161ac522ecSsethdelliott } 2171ac522ecSsethdelliott test->state = IPERF_DONE; 2181ac522ecSsethdelliott break; 219ba2672a2Ssethdelliott default: 220b60a49ddSsethdelliott i_errno = IEMESSAGE; 221b60a49ddSsethdelliott return (-1); 222982c704aSsethdelliott } 223982c704aSsethdelliott 224b60a49ddSsethdelliott return (0); 225982c704aSsethdelliott } 226982c704aSsethdelliott 227efdc02f7Ssethdelliott void 228efdc02f7Ssethdelliott iperf_test_reset(struct iperf_test *test) 229efdc02f7Ssethdelliott { 230efdc02f7Ssethdelliott struct iperf_stream *sp, *np; 231efdc02f7Ssethdelliott 232efdc02f7Ssethdelliott close(test->ctrl_sck); 233efdc02f7Ssethdelliott 234efdc02f7Ssethdelliott /* Free streams */ 235efdc02f7Ssethdelliott for (sp = test->streams; sp; sp = np) { 236efdc02f7Ssethdelliott np = sp->next; 237efdc02f7Ssethdelliott iperf_free_stream(sp); 238efdc02f7Ssethdelliott } 239f1b3bd81Ssethdelliott free_timer(test->timer); 240f1b3bd81Ssethdelliott free_timer(test->stats_timer); 241f1b3bd81Ssethdelliott free_timer(test->reporter_timer); 242f1b3bd81Ssethdelliott test->timer = NULL; 243f1b3bd81Ssethdelliott test->stats_timer = NULL; 244f1b3bd81Ssethdelliott test->reporter_timer = NULL; 245efdc02f7Ssethdelliott 24632885561Ssethdelliott test->streams = NULL; 24732885561Ssethdelliott 248efdc02f7Ssethdelliott test->role = 's'; 24966ce7ad4Ssethdelliott set_protocol(test, Ptcp); 25032885561Ssethdelliott test->duration = DURATION; 25132885561Ssethdelliott test->state = 0; 25232885561Ssethdelliott test->server_hostname = NULL; 25332885561Ssethdelliott 25432885561Ssethdelliott test->ctrl_sck = -1; 25566ce7ad4Ssethdelliott test->prot_listener = -1; 25632885561Ssethdelliott 257f1b3bd81Ssethdelliott test->bytes_sent = 0; 258f1b3bd81Ssethdelliott 25932885561Ssethdelliott test->reverse = 0; 260b68ac00eSsethdelliott test->no_delay = 0; 26132885561Ssethdelliott 262efdc02f7Ssethdelliott FD_ZERO(&test->read_set); 263efdc02f7Ssethdelliott FD_ZERO(&test->write_set); 26466ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 26566ce7ad4Ssethdelliott test->max_fd = test->listener; 26632885561Ssethdelliott 26732885561Ssethdelliott test->num_streams = 1; 268*112a907cSsethdelliott test->settings->socket_bufsize = 0; 269*112a907cSsethdelliott test->settings->blksize = DEFAULT_TCP_BLKSIZE; 270*112a907cSsethdelliott test->settings->rate = RATE; /* UDP only */ 271*112a907cSsethdelliott test->settings->mss = 0; 272*112a907cSsethdelliott memset(test->cookie, 0, COOKIE_SIZE); 273efdc02f7Ssethdelliott } 274efdc02f7Ssethdelliott 2757fa9f68fSsethdelliott int 276a951c980SBrian Tierney iperf_run_server(struct iperf_test *test) 277a951c980SBrian Tierney { 278*112a907cSsethdelliott int result, s, streams_accepted; 279efdc02f7Ssethdelliott fd_set temp_read_set, temp_write_set; 2808a0b5a5dSsethdelliott struct iperf_stream *sp; 2817fa9f68fSsethdelliott struct timeval tv; 282a951c980SBrian Tierney 283982c704aSsethdelliott // Open socket and listen 284982c704aSsethdelliott if (iperf_server_listen(test) < 0) { 285b60a49ddSsethdelliott return (-1); 286e99faeaeSBrian Tierney } 287a951c980SBrian Tierney 288465b565cSsethdelliott signal(SIGINT, sig_handler); 289465b565cSsethdelliott if (setjmp(env)) { 290465b565cSsethdelliott test->state = SERVER_TERMINATE; 291465b565cSsethdelliott if (test->ctrl_sck >= 0) { 292efb7bbe4Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 293b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 294b60a49ddSsethdelliott return (-1); 295465b565cSsethdelliott } 296465b565cSsethdelliott } 29766ce7ad4Ssethdelliott return (0); 298465b565cSsethdelliott } 299465b565cSsethdelliott 300efdc02f7Ssethdelliott for ( ; ; ) { 301efdc02f7Ssethdelliott 302efdc02f7Ssethdelliott test->state = IPERF_START; 303*112a907cSsethdelliott streams_accepted = 0; 304a951c980SBrian Tierney 305873952e3Ssethdelliott while (test->state != IPERF_DONE) { 306982c704aSsethdelliott 307efdc02f7Ssethdelliott memcpy(&temp_read_set, &test->read_set, sizeof(fd_set)); 308efdc02f7Ssethdelliott memcpy(&temp_write_set, &test->write_set, sizeof(fd_set)); 309982c704aSsethdelliott tv.tv_sec = 15; 310982c704aSsethdelliott tv.tv_usec = 0; 311982c704aSsethdelliott 312efdc02f7Ssethdelliott result = select(test->max_fd + 1, &temp_read_set, &temp_write_set, NULL, &tv); 313982c704aSsethdelliott if (result < 0 && errno != EINTR) { 314b60a49ddSsethdelliott i_errno = IESELECT; 315b60a49ddSsethdelliott return (-1); 316982c704aSsethdelliott } else if (result > 0) { 31766ce7ad4Ssethdelliott if (FD_ISSET(test->listener, &temp_read_set)) { 318b68ac00eSsethdelliott if (test->state != CREATE_STREAMS) { 319465b565cSsethdelliott if (iperf_accept(test) < 0) { 320b60a49ddSsethdelliott return (-1); 321982c704aSsethdelliott } 32266ce7ad4Ssethdelliott FD_CLR(test->listener, &temp_read_set); 323982c704aSsethdelliott } 324b68ac00eSsethdelliott } 325efdc02f7Ssethdelliott if (FD_ISSET(test->ctrl_sck, &temp_read_set)) { 326b60a49ddSsethdelliott if (iperf_handle_message_server(test) < 0) 327b60a49ddSsethdelliott return (-1); 328efdc02f7Ssethdelliott FD_CLR(test->ctrl_sck, &temp_read_set); 329982c704aSsethdelliott } 330465b565cSsethdelliott 331465b565cSsethdelliott if (test->state == CREATE_STREAMS) { 3328a0b5a5dSsethdelliott if (FD_ISSET(test->prot_listener, &temp_read_set)) { 3338a0b5a5dSsethdelliott 33466ce7ad4Ssethdelliott if ((s = test->protocol->accept(test)) < 0) 335b60a49ddSsethdelliott return (-1); 3368a0b5a5dSsethdelliott 3378a0b5a5dSsethdelliott if (!is_closed(s)) { 33866ce7ad4Ssethdelliott sp = iperf_new_stream(test, s); 3398a0b5a5dSsethdelliott if (!sp) 340b60a49ddSsethdelliott return (-1); 34166ce7ad4Ssethdelliott 3428a0b5a5dSsethdelliott FD_SET(s, &test->read_set); 3438a0b5a5dSsethdelliott FD_SET(s, &test->write_set); 3448a0b5a5dSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 34566ce7ad4Ssethdelliott 346*112a907cSsethdelliott streams_accepted++; 3478a0b5a5dSsethdelliott connect_msg(sp); 348b68ac00eSsethdelliott } 3498a0b5a5dSsethdelliott FD_CLR(test->prot_listener, &temp_read_set); 350b68ac00eSsethdelliott } 3518a0b5a5dSsethdelliott 352*112a907cSsethdelliott if (streams_accepted == test->num_streams) { 35366ce7ad4Ssethdelliott if (test->protocol->id != Ptcp) { 3548a0b5a5dSsethdelliott FD_CLR(test->prot_listener, &test->read_set); 3558a0b5a5dSsethdelliott close(test->prot_listener); 35666ce7ad4Ssethdelliott } else { 357*112a907cSsethdelliott if (test->no_delay || test->settings->mss) { 35866ce7ad4Ssethdelliott FD_CLR(test->listener, &test->read_set); 35966ce7ad4Ssethdelliott close(test->listener); 360c81883bfSsethdelliott if ((s = netannounce(Ptcp, NULL, test->server_port)) < 0) { 361b60a49ddSsethdelliott i_errno = IELISTEN; 362c81883bfSsethdelliott return (-1); 363c81883bfSsethdelliott } 36466ce7ad4Ssethdelliott test->listener = s; 365c81883bfSsethdelliott test->max_fd = (s > test->max_fd ? s : test->max_fd); 36666ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 367c81883bfSsethdelliott } 3688556db5dSsethdelliott } 3698a0b5a5dSsethdelliott test->prot_listener = -1; 370465b565cSsethdelliott test->state = TEST_START; 371b68ac00eSsethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 372b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 373b60a49ddSsethdelliott return (-1); 374982c704aSsethdelliott } 375b60a49ddSsethdelliott if (iperf_init_test(test) < 0) 376b60a49ddSsethdelliott return (-1); 377f1b3bd81Ssethdelliott test->state = TEST_RUNNING; 378f1b3bd81Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 379b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 380b60a49ddSsethdelliott return (-1); 381f1b3bd81Ssethdelliott } 382982c704aSsethdelliott } 383982c704aSsethdelliott } 384982c704aSsethdelliott 385f1b3bd81Ssethdelliott if (test->state == TEST_RUNNING) { 386465b565cSsethdelliott if (test->reverse) { 387465b565cSsethdelliott // Reverse mode. Server sends. 388b60a49ddSsethdelliott if (iperf_send(test) < 0) 389b60a49ddSsethdelliott return (-1); 390982c704aSsethdelliott } else { 391465b565cSsethdelliott // Regular mode. Server receives. 392b60a49ddSsethdelliott if (iperf_recv(test) < 0) 393b60a49ddSsethdelliott return (-1); 394e99faeaeSBrian Tierney } 395f1b3bd81Ssethdelliott 396f1b3bd81Ssethdelliott /* Perform callbacks */ 397f1b3bd81Ssethdelliott if (timer_expired(test->stats_timer)) { 398f1b3bd81Ssethdelliott test->stats_callback(test); 399b60a49ddSsethdelliott if (update_timer(test->stats_timer, test->stats_interval, 0) < 0) 400b60a49ddSsethdelliott return (-1); 401f1b3bd81Ssethdelliott } 402f1b3bd81Ssethdelliott if (timer_expired(test->reporter_timer)) { 403f1b3bd81Ssethdelliott test->reporter_callback(test); 404b60a49ddSsethdelliott if (update_timer(test->reporter_timer, test->reporter_interval, 0) < 0) 405b60a49ddSsethdelliott return (-1); 406f1b3bd81Ssethdelliott } 407f1b3bd81Ssethdelliott } 408a951c980SBrian Tierney } 409982c704aSsethdelliott } 410e99faeaeSBrian Tierney 411efdc02f7Ssethdelliott /* Clean up the last test */ 412efdc02f7Ssethdelliott iperf_test_reset(test); 413efdc02f7Ssethdelliott printf("\n"); 414efdc02f7Ssethdelliott 415efdc02f7Ssethdelliott } 416efdc02f7Ssethdelliott 417b60a49ddSsethdelliott return (0); 418a3281a3dSBrian Tierney } 419a3281a3dSBrian Tierney 420