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 { 505c01581bSJef Poskanzer retry: 51f99bd3b2Ssethdelliott if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { 525c01581bSJef Poskanzer if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) { 535c01581bSJef Poskanzer /* If we get "Address family not supported by protocol", that 545c01581bSJef Poskanzer ** probably means we were compiled with IPv6 but the running 555c01581bSJef Poskanzer ** kernel does not actually do IPv6. This is not too unusual, 565c01581bSJef Poskanzer ** v6 support is and perhaps always will be spotty. 575c01581bSJef Poskanzer */ 585c01581bSJef Poskanzer warning("this system does not seem to support IPv6 - trying IPv4"); 595c01581bSJef Poskanzer test->settings->domain = AF_INET; 605c01581bSJef Poskanzer goto retry; 615c01581bSJef Poskanzer } else { 62b60a49ddSsethdelliott i_errno = IELISTEN; 63ec2d0670SJef Poskanzer return -1; 64982c704aSsethdelliott } 655c01581bSJef Poskanzer } 66982c704aSsethdelliott 679bfb54c0SJef Poskanzer if (!test->json_output) { 68982c704aSsethdelliott printf("-----------------------------------------------------------\n"); 69982c704aSsethdelliott printf("Server listening on %d\n", test->server_port); 709bfb54c0SJef Poskanzer } 71982c704aSsethdelliott 72982c704aSsethdelliott // This needs to be changed to reflect if client has different window size 73982c704aSsethdelliott // make sure we got what we asked for 74ba2672a2Ssethdelliott /* XXX: This needs to be moved to the stream listener 7566ce7ad4Ssethdelliott if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) { 76982c704aSsethdelliott // Needs to set some sort of error number/message 77982c704aSsethdelliott perror("SO_RCVBUF"); 78982c704aSsethdelliott return -1; 79982c704aSsethdelliott } 80ba2672a2Ssethdelliott */ 81982c704aSsethdelliott 82ba2672a2Ssethdelliott // XXX: This code needs to be moved to after parameter exhange 83c81883bfSsethdelliott /* 8498ce496bSjef char ubuf[UNIT_LEN]; 8598ce496bSjef int x; 8698ce496bSjef 8766ce7ad4Ssethdelliott if (test->protocol->id == Ptcp) { 88112a907cSsethdelliott if (test->settings->socket_bufsize > 0) { 89982c704aSsethdelliott unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A'); 90*f8bd11afSJef Poskanzer if (!test->json_output) 91982c704aSsethdelliott printf("TCP window size: %s\n", ubuf); 92982c704aSsethdelliott } else { 93*f8bd11afSJef Poskanzer if (!test->json_output) 94982c704aSsethdelliott printf("Using TCP Autotuning\n"); 95982c704aSsethdelliott } 96982c704aSsethdelliott } 97c81883bfSsethdelliott */ 989bfb54c0SJef Poskanzer if (!test->json_output) 99982c704aSsethdelliott printf("-----------------------------------------------------------\n"); 100982c704aSsethdelliott 101982c704aSsethdelliott FD_ZERO(&test->read_set); 102efdc02f7Ssethdelliott FD_ZERO(&test->write_set); 10366ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 10466ce7ad4Ssethdelliott test->max_fd = (test->listener > test->max_fd) ? test->listener : test->max_fd; 105982c704aSsethdelliott 106982c704aSsethdelliott return 0; 107982c704aSsethdelliott } 108982c704aSsethdelliott 109982c704aSsethdelliott int 110982c704aSsethdelliott iperf_accept(struct iperf_test *test) 111982c704aSsethdelliott { 112982c704aSsethdelliott int s; 113465b565cSsethdelliott int rbuf = ACCESS_DENIED; 114af70b448Ssethdelliott char cookie[COOKIE_SIZE]; 115982c704aSsethdelliott socklen_t len; 11612d474e2SJef Poskanzer struct sockaddr_storage addr; 117982c704aSsethdelliott 118b68ac00eSsethdelliott len = sizeof(addr); 11966ce7ad4Ssethdelliott if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { 120b60a49ddSsethdelliott i_errno = IEACCEPT; 121ec2d0670SJef Poskanzer return -1; 122982c704aSsethdelliott } 123af70b448Ssethdelliott 124af70b448Ssethdelliott if (test->ctrl_sck == -1) { 125af70b448Ssethdelliott /* Server free, accept new client */ 126112a907cSsethdelliott if (Nread(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { 127b60a49ddSsethdelliott i_errno = IERECVCOOKIE; 128ec2d0670SJef Poskanzer return -1; 129af70b448Ssethdelliott } 130af70b448Ssethdelliott 131465b565cSsethdelliott FD_SET(s, &test->read_set); 132465b565cSsethdelliott FD_SET(s, &test->write_set); 133465b565cSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 134465b565cSsethdelliott test->ctrl_sck = s; 135982c704aSsethdelliott 136c9693599SJef Poskanzer if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0) 137ec2d0670SJef Poskanzer return -1; 1388bdc8fffSJef Poskanzer if (iperf_exchange_parameters(test) < 0) 139ec2d0670SJef Poskanzer return -1; 1408bdc8fffSJef Poskanzer if (test->on_connect) 1414df383f6Ssethdelliott test->on_connect(test); 142982c704aSsethdelliott } else { 143111645edSJef Poskanzer /* XXX: Do we even need to receive cookie if we're just going to deny anyways? */ 144af70b448Ssethdelliott if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { 145b60a49ddSsethdelliott i_errno = IERECVCOOKIE; 146ec2d0670SJef Poskanzer return -1; 147465b565cSsethdelliott } 148987b4323SJef Poskanzer if (Nwrite(s, (char*) &rbuf, sizeof(int), Ptcp) < 0) { 149b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 150ec2d0670SJef Poskanzer return -1; 151465b565cSsethdelliott } 152465b565cSsethdelliott close(s); 153982c704aSsethdelliott } 154982c704aSsethdelliott 155ec2d0670SJef Poskanzer return 0; 156af70b448Ssethdelliott } 157af70b448Ssethdelliott 158b68ac00eSsethdelliott 159a951c980SBrian Tierney /**************************************************************************/ 160982c704aSsethdelliott int 161465b565cSsethdelliott iperf_handle_message_server(struct iperf_test *test) 162982c704aSsethdelliott { 163b68ac00eSsethdelliott int rval; 164efdc02f7Ssethdelliott struct iperf_stream *sp; 165efdc02f7Ssethdelliott 166b60a49ddSsethdelliott // XXX: Need to rethink how this behaves to fit API 16701943402SJef Poskanzer if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp)) <= 0) { 168b68ac00eSsethdelliott if (rval == 0) { 169b5e0751fSJef Poskanzer iperf_err(test, "the client has unexpectedly closed the connection"); 170b60a49ddSsethdelliott i_errno = IECTRLCLOSE; 171b68ac00eSsethdelliott test->state = IPERF_DONE; 172ec2d0670SJef Poskanzer return 0; 173b68ac00eSsethdelliott } else { 174b60a49ddSsethdelliott i_errno = IERECVMESSAGE; 175ec2d0670SJef Poskanzer return -1; 176982c704aSsethdelliott } 177b68ac00eSsethdelliott } 178982c704aSsethdelliott 179982c704aSsethdelliott switch(test->state) { 180ba2672a2Ssethdelliott case TEST_START: 181ba2672a2Ssethdelliott break; 182465b565cSsethdelliott case TEST_END: 1833331e801Ssethdelliott cpu_util(&test->cpu_util); 184f1b3bd81Ssethdelliott test->stats_callback(test); 185dd4bc008Ssethdelliott SLIST_FOREACH(sp, &test->streams, streams) { 186efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->read_set); 187efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->write_set); 188efdc02f7Ssethdelliott close(sp->socket); 189efdc02f7Ssethdelliott } 190c9693599SJef Poskanzer if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0) 191ec2d0670SJef Poskanzer return -1; 19269bdbfd3SJef Poskanzer if (iperf_sum_results(test) < 0) 19369bdbfd3SJef Poskanzer return -1; 194b60a49ddSsethdelliott if (iperf_exchange_results(test) < 0) 195ec2d0670SJef Poskanzer return -1; 196c9693599SJef Poskanzer if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0) 197ec2d0670SJef Poskanzer return -1; 1984df383f6Ssethdelliott if (test->on_test_finish) 1994df383f6Ssethdelliott test->on_test_finish(test); 200181d61afSsethdelliott test->reporter_callback(test); 201465b565cSsethdelliott break; 202873952e3Ssethdelliott case IPERF_DONE: 203873952e3Ssethdelliott break; 204465b565cSsethdelliott case CLIENT_TERMINATE: 205ffdcc7d4Ssethdelliott i_errno = IECLIENTTERM; 206ffdcc7d4Ssethdelliott 207ffdcc7d4Ssethdelliott // XXX: Remove this line below! 208b5e0751fSJef Poskanzer iperf_err(test, "the client has terminated"); 209dd4bc008Ssethdelliott SLIST_FOREACH(sp, &test->streams, streams) { 2101ac522ecSsethdelliott FD_CLR(sp->socket, &test->read_set); 2111ac522ecSsethdelliott FD_CLR(sp->socket, &test->write_set); 2121ac522ecSsethdelliott close(sp->socket); 2131ac522ecSsethdelliott } 2141ac522ecSsethdelliott test->state = IPERF_DONE; 2151ac522ecSsethdelliott break; 216ba2672a2Ssethdelliott default: 217b60a49ddSsethdelliott i_errno = IEMESSAGE; 218ec2d0670SJef Poskanzer return -1; 219982c704aSsethdelliott } 220982c704aSsethdelliott 221ec2d0670SJef Poskanzer return 0; 222982c704aSsethdelliott } 223982c704aSsethdelliott 2240bd8d9daSsethdelliott /* XXX: This function is not used anymore */ 225efdc02f7Ssethdelliott void 226efdc02f7Ssethdelliott iperf_test_reset(struct iperf_test *test) 227efdc02f7Ssethdelliott { 2280bd8d9daSsethdelliott struct iperf_stream *sp; 229efdc02f7Ssethdelliott 230efdc02f7Ssethdelliott close(test->ctrl_sck); 231efdc02f7Ssethdelliott 232efdc02f7Ssethdelliott /* Free streams */ 233dd4bc008Ssethdelliott while (!SLIST_EMPTY(&test->streams)) { 234dd4bc008Ssethdelliott sp = SLIST_FIRST(&test->streams); 235dd4bc008Ssethdelliott SLIST_REMOVE_HEAD(&test->streams, streams); 236dd4bc008Ssethdelliott iperf_free_stream(sp); 237dd4bc008Ssethdelliott } 238ec2d0670SJef Poskanzer if (test->timer != NULL) { 239ec2d0670SJef Poskanzer tmr_cancel(test->timer); 240f1b3bd81Ssethdelliott test->timer = NULL; 241ec2d0670SJef Poskanzer } 242ec2d0670SJef Poskanzer if (test->stats_timer != NULL) { 243ec2d0670SJef Poskanzer tmr_cancel(test->stats_timer); 244f1b3bd81Ssethdelliott test->stats_timer = NULL; 245ec2d0670SJef Poskanzer } 246ec2d0670SJef Poskanzer if (test->reporter_timer != NULL) { 247ec2d0670SJef Poskanzer tmr_cancel(test->reporter_timer); 248f1b3bd81Ssethdelliott test->reporter_timer = NULL; 249ec2d0670SJef Poskanzer } 250efdc02f7Ssethdelliott 251dd4bc008Ssethdelliott SLIST_INIT(&test->streams); 25232885561Ssethdelliott 253efdc02f7Ssethdelliott test->role = 's'; 25466ce7ad4Ssethdelliott set_protocol(test, Ptcp); 25557892604SJef Poskanzer test->omit = OMIT; 25632885561Ssethdelliott test->duration = DURATION; 25732885561Ssethdelliott test->state = 0; 25832885561Ssethdelliott test->server_hostname = NULL; 25932885561Ssethdelliott 26032885561Ssethdelliott test->ctrl_sck = -1; 26166ce7ad4Ssethdelliott test->prot_listener = -1; 26232885561Ssethdelliott 263f1b3bd81Ssethdelliott test->bytes_sent = 0; 264f1b3bd81Ssethdelliott 26532885561Ssethdelliott test->reverse = 0; 2662c042fd4SJef Poskanzer test->sender = 0; 26769bdbfd3SJef Poskanzer test->sender_has_retransmits = 0; 268b68ac00eSsethdelliott test->no_delay = 0; 26932885561Ssethdelliott 270efdc02f7Ssethdelliott FD_ZERO(&test->read_set); 271efdc02f7Ssethdelliott FD_ZERO(&test->write_set); 27266ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 27366ce7ad4Ssethdelliott test->max_fd = test->listener; 27432885561Ssethdelliott 27532885561Ssethdelliott test->num_streams = 1; 276112a907cSsethdelliott test->settings->socket_bufsize = 0; 277112a907cSsethdelliott test->settings->blksize = DEFAULT_TCP_BLKSIZE; 278d611f13eSJef Poskanzer test->settings->rate = 0; 279112a907cSsethdelliott test->settings->mss = 0; 280112a907cSsethdelliott memset(test->cookie, 0, COOKIE_SIZE); 281efdc02f7Ssethdelliott } 282efdc02f7Ssethdelliott 283c9693599SJef Poskanzer static void 28457892604SJef Poskanzer server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP) 285c9693599SJef Poskanzer { 286c9693599SJef Poskanzer struct iperf_test *test = client_data.p; 287c9693599SJef Poskanzer 28857892604SJef Poskanzer test->omit_timer = NULL; 28957892604SJef Poskanzer test->omitting = 0; 290c9693599SJef Poskanzer iperf_reset_stats(test); 291c9693599SJef Poskanzer if (test->verbose && !test->json_output) 29257892604SJef Poskanzer printf("Finished omit period, starting real test\n"); 293c9693599SJef Poskanzer } 294c9693599SJef Poskanzer 295c9693599SJef Poskanzer static int 29657892604SJef Poskanzer create_server_omit_timer(struct iperf_test * test) 297c9693599SJef Poskanzer { 298c9693599SJef Poskanzer struct timeval now; 299c9693599SJef Poskanzer TimerClientData cd; 300c9693599SJef Poskanzer 301c9693599SJef Poskanzer if (gettimeofday(&now, NULL) < 0) { 302c9693599SJef Poskanzer i_errno = IEINITTEST; 303c9693599SJef Poskanzer return -1; 304c9693599SJef Poskanzer } 30557892604SJef Poskanzer test->omitting = 1; 306c9693599SJef Poskanzer cd.p = test; 30757892604SJef Poskanzer test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0); 30857892604SJef Poskanzer if (test->omit_timer == NULL) { 309c9693599SJef Poskanzer i_errno = IEINITTEST; 310c9693599SJef Poskanzer return -1; 311c9693599SJef Poskanzer } 312c9693599SJef Poskanzer return 0; 313c9693599SJef Poskanzer } 314c9693599SJef Poskanzer 315c9693599SJef Poskanzer static void 316c9693599SJef Poskanzer cleanup_server(struct iperf_test *test) 317c9693599SJef Poskanzer { 318c9693599SJef Poskanzer /* Close open test sockets */ 319c9693599SJef Poskanzer close(test->ctrl_sck); 320c9693599SJef Poskanzer close(test->listener); 321c9693599SJef Poskanzer } 322c9693599SJef Poskanzer 3237fa9f68fSsethdelliott int 324a951c980SBrian Tierney iperf_run_server(struct iperf_test *test) 325a951c980SBrian Tierney { 326112a907cSsethdelliott int result, s, streams_accepted; 3276177a7f1SJef Poskanzer fd_set read_set, write_set; 3288a0b5a5dSsethdelliott struct iperf_stream *sp; 329ec2d0670SJef Poskanzer struct timeval now; 330a951c980SBrian Tierney 331e96ab740SJef Poskanzer if (test->json_output) 332e96ab740SJef Poskanzer if (iperf_json_start(test) < 0) 333e96ab740SJef Poskanzer return -1; 334e96ab740SJef Poskanzer 335e96ab740SJef Poskanzer if (test->json_output) { 336e96ab740SJef Poskanzer cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version)); 337e96ab740SJef Poskanzer cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info())); 338e96ab740SJef Poskanzer } else if (test->verbose) { 339e96ab740SJef Poskanzer printf("%s\n", version); 340e96ab740SJef Poskanzer system("uname -a"); 341e96ab740SJef Poskanzer } 342e96ab740SJef Poskanzer 343982c704aSsethdelliott // Open socket and listen 344982c704aSsethdelliott if (iperf_server_listen(test) < 0) { 345ec2d0670SJef Poskanzer return -1; 346e99faeaeSBrian Tierney } 347a951c980SBrian Tierney 3483331e801Ssethdelliott // Begin calculating CPU utilization 3493331e801Ssethdelliott cpu_util(NULL); 3503331e801Ssethdelliott 351efdc02f7Ssethdelliott test->state = IPERF_START; 352112a907cSsethdelliott streams_accepted = 0; 353a951c980SBrian Tierney 354ec2d0670SJef Poskanzer (void) gettimeofday(&now, NULL); 355873952e3Ssethdelliott while (test->state != IPERF_DONE) { 356982c704aSsethdelliott 3576177a7f1SJef Poskanzer memcpy(&read_set, &test->read_set, sizeof(fd_set)); 3586177a7f1SJef Poskanzer memcpy(&write_set, &test->write_set, sizeof(fd_set)); 359982c704aSsethdelliott 3606177a7f1SJef Poskanzer result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now)); 361982c704aSsethdelliott if (result < 0 && errno != EINTR) { 362c9693599SJef Poskanzer cleanup_server(test); 363b60a49ddSsethdelliott i_errno = IESELECT; 364ec2d0670SJef Poskanzer return -1; 365ec2d0670SJef Poskanzer } 366ec2d0670SJef Poskanzer if (result > 0) { 3676177a7f1SJef Poskanzer if (FD_ISSET(test->listener, &read_set)) { 368b68ac00eSsethdelliott if (test->state != CREATE_STREAMS) { 369465b565cSsethdelliott if (iperf_accept(test) < 0) { 370c9693599SJef Poskanzer cleanup_server(test); 371ec2d0670SJef Poskanzer return -1; 372982c704aSsethdelliott } 3736177a7f1SJef Poskanzer FD_CLR(test->listener, &read_set); 374982c704aSsethdelliott } 375b68ac00eSsethdelliott } 3766177a7f1SJef Poskanzer if (FD_ISSET(test->ctrl_sck, &read_set)) { 377c9693599SJef Poskanzer if (iperf_handle_message_server(test) < 0) { 378c9693599SJef Poskanzer cleanup_server(test); 379ec2d0670SJef Poskanzer return -1; 380c9693599SJef Poskanzer } 3816177a7f1SJef Poskanzer FD_CLR(test->ctrl_sck, &read_set); 382982c704aSsethdelliott } 383465b565cSsethdelliott 384465b565cSsethdelliott if (test->state == CREATE_STREAMS) { 3856177a7f1SJef Poskanzer if (FD_ISSET(test->prot_listener, &read_set)) { 3868a0b5a5dSsethdelliott 387c9693599SJef Poskanzer if ((s = test->protocol->accept(test)) < 0) { 388c9693599SJef Poskanzer cleanup_server(test); 389ec2d0670SJef Poskanzer return -1; 390c9693599SJef Poskanzer } 3918a0b5a5dSsethdelliott 3928a0b5a5dSsethdelliott if (!is_closed(s)) { 39366ce7ad4Ssethdelliott sp = iperf_new_stream(test, s); 394c9693599SJef Poskanzer if (!sp) { 395c9693599SJef Poskanzer cleanup_server(test); 396ec2d0670SJef Poskanzer return -1; 397c9693599SJef Poskanzer } 39866ce7ad4Ssethdelliott 3998a0b5a5dSsethdelliott FD_SET(s, &test->read_set); 4008a0b5a5dSsethdelliott FD_SET(s, &test->write_set); 4018a0b5a5dSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 40266ce7ad4Ssethdelliott 403112a907cSsethdelliott streams_accepted++; 4044df383f6Ssethdelliott if (test->on_new_stream) 4054df383f6Ssethdelliott test->on_new_stream(sp); 406b68ac00eSsethdelliott } 4076177a7f1SJef Poskanzer FD_CLR(test->prot_listener, &read_set); 408b68ac00eSsethdelliott } 4098a0b5a5dSsethdelliott 410112a907cSsethdelliott if (streams_accepted == test->num_streams) { 41166ce7ad4Ssethdelliott if (test->protocol->id != Ptcp) { 4128a0b5a5dSsethdelliott FD_CLR(test->prot_listener, &test->read_set); 4138a0b5a5dSsethdelliott close(test->prot_listener); 41466ce7ad4Ssethdelliott } else { 4150bd8d9daSsethdelliott if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { 41666ce7ad4Ssethdelliott FD_CLR(test->listener, &test->read_set); 41766ce7ad4Ssethdelliott close(test->listener); 418f99bd3b2Ssethdelliott if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { 419c9693599SJef Poskanzer cleanup_server(test); 420b60a49ddSsethdelliott i_errno = IELISTEN; 421ec2d0670SJef Poskanzer return -1; 422c81883bfSsethdelliott } 42366ce7ad4Ssethdelliott test->listener = s; 424c81883bfSsethdelliott test->max_fd = (s > test->max_fd ? s : test->max_fd); 42566ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 426c81883bfSsethdelliott } 4278556db5dSsethdelliott } 4288a0b5a5dSsethdelliott test->prot_listener = -1; 429c9693599SJef Poskanzer if (iperf_set_send_state(test, TEST_START) != 0) { 430c9693599SJef Poskanzer cleanup_server(test); 431ec2d0670SJef Poskanzer return -1; 432982c704aSsethdelliott } 433c9693599SJef Poskanzer if (iperf_init_test(test) < 0) { 434c9693599SJef Poskanzer cleanup_server(test); 435ec2d0670SJef Poskanzer return -1; 436c9693599SJef Poskanzer } 43757892604SJef Poskanzer if (create_server_omit_timer(test) < 0) { 438c9693599SJef Poskanzer cleanup_server(test); 439c9693599SJef Poskanzer return -1; 440c9693599SJef Poskanzer } 4418bdc8fffSJef Poskanzer if (test->reverse) 4428bdc8fffSJef Poskanzer if (iperf_create_send_timers(test) < 0) { 4438bdc8fffSJef Poskanzer cleanup_server(test); 4448bdc8fffSJef Poskanzer return -1; 4458bdc8fffSJef Poskanzer } 446c9693599SJef Poskanzer if (iperf_set_send_state(test, TEST_RUNNING) != 0) { 447c9693599SJef Poskanzer cleanup_server(test); 448ec2d0670SJef Poskanzer return -1; 449f1b3bd81Ssethdelliott } 450982c704aSsethdelliott } 451982c704aSsethdelliott } 452982c704aSsethdelliott 453f1b3bd81Ssethdelliott if (test->state == TEST_RUNNING) { 454465b565cSsethdelliott if (test->reverse) { 455465b565cSsethdelliott // Reverse mode. Server sends. 456c9693599SJef Poskanzer if (iperf_send(test, &write_set) < 0) { 457c9693599SJef Poskanzer cleanup_server(test); 458ec2d0670SJef Poskanzer return -1; 459c9693599SJef Poskanzer } 460982c704aSsethdelliott } else { 461465b565cSsethdelliott // Regular mode. Server receives. 462c9693599SJef Poskanzer if (iperf_recv(test, &read_set) < 0) { 463c9693599SJef Poskanzer cleanup_server(test); 464ec2d0670SJef Poskanzer return -1; 465e99faeaeSBrian Tierney } 466c9693599SJef Poskanzer } 467f1b3bd81Ssethdelliott 468ec2d0670SJef Poskanzer /* Run the timers. */ 469ec2d0670SJef Poskanzer (void) gettimeofday(&now, NULL); 470ec2d0670SJef Poskanzer tmr_run(&now); 471f1b3bd81Ssethdelliott } 472a951c980SBrian Tierney } 473982c704aSsethdelliott } 474e99faeaeSBrian Tierney 475c9693599SJef Poskanzer cleanup_server(test); 476efdc02f7Ssethdelliott 477e96ab740SJef Poskanzer if (test->json_output) { 478e96ab740SJef Poskanzer if (iperf_json_finish(test) < 0) 479e96ab740SJef Poskanzer return -1; 480e96ab740SJef Poskanzer } 481e96ab740SJef Poskanzer 482ec2d0670SJef Poskanzer return 0; 483a3281a3dSBrian Tierney } 484