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 124c9693599SJef Poskanzer if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0) 125ec2d0670SJef Poskanzer return -1; 126b60a49ddSsethdelliott if (iperf_exchange_parameters(test) < 0) { 127ec2d0670SJef Poskanzer return -1; 128b60a49ddSsethdelliott } 1294df383f6Ssethdelliott if (test->on_connect) { 1304df383f6Ssethdelliott test->on_connect(test); 1314df383f6Ssethdelliott } 132982c704aSsethdelliott } else { 133111645edSJef Poskanzer /* XXX: Do we even need to receive cookie if we're just going to deny anyways? */ 134af70b448Ssethdelliott if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { 135b60a49ddSsethdelliott i_errno = IERECVCOOKIE; 136ec2d0670SJef Poskanzer return -1; 137465b565cSsethdelliott } 138987b4323SJef Poskanzer if (Nwrite(s, (char*) &rbuf, sizeof(int), Ptcp) < 0) { 139b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 140ec2d0670SJef Poskanzer return -1; 141465b565cSsethdelliott } 142465b565cSsethdelliott close(s); 143982c704aSsethdelliott } 144982c704aSsethdelliott 145ec2d0670SJef Poskanzer return 0; 146af70b448Ssethdelliott } 147af70b448Ssethdelliott 148b68ac00eSsethdelliott 149a951c980SBrian Tierney /**************************************************************************/ 150982c704aSsethdelliott int 151465b565cSsethdelliott iperf_handle_message_server(struct iperf_test *test) 152982c704aSsethdelliott { 153b68ac00eSsethdelliott int rval; 154efdc02f7Ssethdelliott struct iperf_stream *sp; 155efdc02f7Ssethdelliott 156b60a49ddSsethdelliott // XXX: Need to rethink how this behaves to fit API 157b60a49ddSsethdelliott if ((rval = Nread(test->ctrl_sck, &test->state, sizeof(char), Ptcp)) <= 0) { 158b68ac00eSsethdelliott if (rval == 0) { 159b5e0751fSJef Poskanzer iperf_err(test, "the client has unexpectedly closed the connection"); 160b60a49ddSsethdelliott i_errno = IECTRLCLOSE; 161b68ac00eSsethdelliott test->state = IPERF_DONE; 162ec2d0670SJef Poskanzer return 0; 163b68ac00eSsethdelliott } else { 164b60a49ddSsethdelliott i_errno = IERECVMESSAGE; 165ec2d0670SJef Poskanzer return -1; 166982c704aSsethdelliott } 167b68ac00eSsethdelliott } 168982c704aSsethdelliott 169982c704aSsethdelliott switch(test->state) { 170ba2672a2Ssethdelliott case TEST_START: 171ba2672a2Ssethdelliott break; 172465b565cSsethdelliott case TEST_END: 1733331e801Ssethdelliott cpu_util(&test->cpu_util); 174f1b3bd81Ssethdelliott test->stats_callback(test); 175dd4bc008Ssethdelliott SLIST_FOREACH(sp, &test->streams, streams) { 176efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->read_set); 177efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->write_set); 178efdc02f7Ssethdelliott close(sp->socket); 179efdc02f7Ssethdelliott } 180c9693599SJef Poskanzer if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0) 181ec2d0670SJef Poskanzer return -1; 18269bdbfd3SJef Poskanzer if (iperf_sum_results(test) < 0) 18369bdbfd3SJef Poskanzer return -1; 184b60a49ddSsethdelliott if (iperf_exchange_results(test) < 0) 185ec2d0670SJef Poskanzer return -1; 186c9693599SJef Poskanzer if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0) 187ec2d0670SJef Poskanzer return -1; 1884df383f6Ssethdelliott if (test->on_test_finish) 1894df383f6Ssethdelliott test->on_test_finish(test); 190181d61afSsethdelliott test->reporter_callback(test); 191465b565cSsethdelliott break; 192873952e3Ssethdelliott case IPERF_DONE: 193873952e3Ssethdelliott break; 194465b565cSsethdelliott case CLIENT_TERMINATE: 195ffdcc7d4Ssethdelliott i_errno = IECLIENTTERM; 196ffdcc7d4Ssethdelliott 197ffdcc7d4Ssethdelliott // XXX: Remove this line below! 198b5e0751fSJef Poskanzer iperf_err(test, "the client has terminated"); 199dd4bc008Ssethdelliott SLIST_FOREACH(sp, &test->streams, streams) { 2001ac522ecSsethdelliott FD_CLR(sp->socket, &test->read_set); 2011ac522ecSsethdelliott FD_CLR(sp->socket, &test->write_set); 2021ac522ecSsethdelliott close(sp->socket); 2031ac522ecSsethdelliott } 2041ac522ecSsethdelliott test->state = IPERF_DONE; 2051ac522ecSsethdelliott break; 206ba2672a2Ssethdelliott default: 207b60a49ddSsethdelliott i_errno = IEMESSAGE; 208ec2d0670SJef Poskanzer return -1; 209982c704aSsethdelliott } 210982c704aSsethdelliott 211ec2d0670SJef Poskanzer return 0; 212982c704aSsethdelliott } 213982c704aSsethdelliott 2140bd8d9daSsethdelliott /* XXX: This function is not used anymore */ 215efdc02f7Ssethdelliott void 216efdc02f7Ssethdelliott iperf_test_reset(struct iperf_test *test) 217efdc02f7Ssethdelliott { 2180bd8d9daSsethdelliott struct iperf_stream *sp; 219efdc02f7Ssethdelliott 220efdc02f7Ssethdelliott close(test->ctrl_sck); 221efdc02f7Ssethdelliott 222efdc02f7Ssethdelliott /* Free streams */ 223dd4bc008Ssethdelliott while (!SLIST_EMPTY(&test->streams)) { 224dd4bc008Ssethdelliott sp = SLIST_FIRST(&test->streams); 225dd4bc008Ssethdelliott SLIST_REMOVE_HEAD(&test->streams, streams); 226dd4bc008Ssethdelliott iperf_free_stream(sp); 227dd4bc008Ssethdelliott } 228ec2d0670SJef Poskanzer if (test->timer != NULL) { 229ec2d0670SJef Poskanzer tmr_cancel(test->timer); 230f1b3bd81Ssethdelliott test->timer = NULL; 231ec2d0670SJef Poskanzer } 232ec2d0670SJef Poskanzer if (test->stats_timer != NULL) { 233ec2d0670SJef Poskanzer tmr_cancel(test->stats_timer); 234f1b3bd81Ssethdelliott test->stats_timer = NULL; 235ec2d0670SJef Poskanzer } 236ec2d0670SJef Poskanzer if (test->reporter_timer != NULL) { 237ec2d0670SJef Poskanzer tmr_cancel(test->reporter_timer); 238f1b3bd81Ssethdelliott test->reporter_timer = NULL; 239ec2d0670SJef Poskanzer } 240efdc02f7Ssethdelliott 241dd4bc008Ssethdelliott SLIST_INIT(&test->streams); 24232885561Ssethdelliott 243efdc02f7Ssethdelliott test->role = 's'; 24466ce7ad4Ssethdelliott set_protocol(test, Ptcp); 24557892604SJef Poskanzer test->omit = OMIT; 24632885561Ssethdelliott test->duration = DURATION; 24732885561Ssethdelliott test->state = 0; 24832885561Ssethdelliott test->server_hostname = NULL; 24932885561Ssethdelliott 25032885561Ssethdelliott test->ctrl_sck = -1; 25166ce7ad4Ssethdelliott test->prot_listener = -1; 25232885561Ssethdelliott 253f1b3bd81Ssethdelliott test->bytes_sent = 0; 254f1b3bd81Ssethdelliott 25532885561Ssethdelliott test->reverse = 0; 2562c042fd4SJef Poskanzer test->sender = 0; 25769bdbfd3SJef Poskanzer test->sender_has_retransmits = 0; 258b68ac00eSsethdelliott test->no_delay = 0; 25932885561Ssethdelliott 260efdc02f7Ssethdelliott FD_ZERO(&test->read_set); 261efdc02f7Ssethdelliott FD_ZERO(&test->write_set); 26266ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 26366ce7ad4Ssethdelliott test->max_fd = test->listener; 26432885561Ssethdelliott 26532885561Ssethdelliott test->num_streams = 1; 266112a907cSsethdelliott test->settings->socket_bufsize = 0; 267112a907cSsethdelliott test->settings->blksize = DEFAULT_TCP_BLKSIZE; 268*d611f13eSJef Poskanzer test->settings->rate = 0; 269112a907cSsethdelliott test->settings->mss = 0; 270112a907cSsethdelliott memset(test->cookie, 0, COOKIE_SIZE); 271efdc02f7Ssethdelliott } 272efdc02f7Ssethdelliott 273c9693599SJef Poskanzer static void 27457892604SJef Poskanzer server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP) 275c9693599SJef Poskanzer { 276c9693599SJef Poskanzer struct iperf_test *test = client_data.p; 277c9693599SJef Poskanzer 27857892604SJef Poskanzer test->omit_timer = NULL; 27957892604SJef Poskanzer test->omitting = 0; 280c9693599SJef Poskanzer iperf_reset_stats(test); 281c9693599SJef Poskanzer if (test->verbose && !test->json_output) 28257892604SJef Poskanzer printf("Finished omit period, starting real test\n"); 283c9693599SJef Poskanzer } 284c9693599SJef Poskanzer 285c9693599SJef Poskanzer static int 28657892604SJef Poskanzer create_server_omit_timer(struct iperf_test * test) 287c9693599SJef Poskanzer { 288c9693599SJef Poskanzer struct timeval now; 289c9693599SJef Poskanzer TimerClientData cd; 290c9693599SJef Poskanzer 291c9693599SJef Poskanzer if (gettimeofday(&now, NULL) < 0) { 292c9693599SJef Poskanzer i_errno = IEINITTEST; 293c9693599SJef Poskanzer return -1; 294c9693599SJef Poskanzer } 29557892604SJef Poskanzer test->omitting = 1; 296c9693599SJef Poskanzer cd.p = test; 29757892604SJef Poskanzer test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0); 29857892604SJef Poskanzer if (test->omit_timer == NULL) { 299c9693599SJef Poskanzer i_errno = IEINITTEST; 300c9693599SJef Poskanzer return -1; 301c9693599SJef Poskanzer } 302c9693599SJef Poskanzer return 0; 303c9693599SJef Poskanzer } 304c9693599SJef Poskanzer 305c9693599SJef Poskanzer static void 306c9693599SJef Poskanzer cleanup_server(struct iperf_test *test) 307c9693599SJef Poskanzer { 308c9693599SJef Poskanzer /* Close open test sockets */ 309c9693599SJef Poskanzer close(test->ctrl_sck); 310c9693599SJef Poskanzer close(test->listener); 311c9693599SJef Poskanzer } 312c9693599SJef Poskanzer 3137fa9f68fSsethdelliott int 314a951c980SBrian Tierney iperf_run_server(struct iperf_test *test) 315a951c980SBrian Tierney { 316112a907cSsethdelliott int result, s, streams_accepted; 3176177a7f1SJef Poskanzer fd_set read_set, write_set; 3188a0b5a5dSsethdelliott struct iperf_stream *sp; 319ec2d0670SJef Poskanzer struct timeval now; 320a951c980SBrian Tierney 321e96ab740SJef Poskanzer if (test->json_output) 322e96ab740SJef Poskanzer if (iperf_json_start(test) < 0) 323e96ab740SJef Poskanzer return -1; 324e96ab740SJef Poskanzer 325e96ab740SJef Poskanzer if (test->json_output) { 326e96ab740SJef Poskanzer cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version)); 327e96ab740SJef Poskanzer cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info())); 328e96ab740SJef Poskanzer } else if (test->verbose) { 329e96ab740SJef Poskanzer printf("%s\n", version); 330e96ab740SJef Poskanzer system("uname -a"); 331e96ab740SJef Poskanzer } 332e96ab740SJef Poskanzer 333982c704aSsethdelliott // Open socket and listen 334982c704aSsethdelliott if (iperf_server_listen(test) < 0) { 335ec2d0670SJef Poskanzer return -1; 336e99faeaeSBrian Tierney } 337a951c980SBrian Tierney 3383331e801Ssethdelliott // Begin calculating CPU utilization 3393331e801Ssethdelliott cpu_util(NULL); 3403331e801Ssethdelliott 341efdc02f7Ssethdelliott test->state = IPERF_START; 342112a907cSsethdelliott streams_accepted = 0; 343a951c980SBrian Tierney 344ec2d0670SJef Poskanzer (void) gettimeofday(&now, NULL); 345873952e3Ssethdelliott while (test->state != IPERF_DONE) { 346982c704aSsethdelliott 3476177a7f1SJef Poskanzer memcpy(&read_set, &test->read_set, sizeof(fd_set)); 3486177a7f1SJef Poskanzer memcpy(&write_set, &test->write_set, sizeof(fd_set)); 349982c704aSsethdelliott 3506177a7f1SJef Poskanzer result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now)); 351982c704aSsethdelliott if (result < 0 && errno != EINTR) { 352c9693599SJef Poskanzer cleanup_server(test); 353b60a49ddSsethdelliott i_errno = IESELECT; 354ec2d0670SJef Poskanzer return -1; 355ec2d0670SJef Poskanzer } 356ec2d0670SJef Poskanzer if (result > 0) { 3576177a7f1SJef Poskanzer if (FD_ISSET(test->listener, &read_set)) { 358b68ac00eSsethdelliott if (test->state != CREATE_STREAMS) { 359465b565cSsethdelliott if (iperf_accept(test) < 0) { 360c9693599SJef Poskanzer cleanup_server(test); 361ec2d0670SJef Poskanzer return -1; 362982c704aSsethdelliott } 3636177a7f1SJef Poskanzer FD_CLR(test->listener, &read_set); 364982c704aSsethdelliott } 365b68ac00eSsethdelliott } 3666177a7f1SJef Poskanzer if (FD_ISSET(test->ctrl_sck, &read_set)) { 367c9693599SJef Poskanzer if (iperf_handle_message_server(test) < 0) { 368c9693599SJef Poskanzer cleanup_server(test); 369ec2d0670SJef Poskanzer return -1; 370c9693599SJef Poskanzer } 3716177a7f1SJef Poskanzer FD_CLR(test->ctrl_sck, &read_set); 372982c704aSsethdelliott } 373465b565cSsethdelliott 374465b565cSsethdelliott if (test->state == CREATE_STREAMS) { 3756177a7f1SJef Poskanzer if (FD_ISSET(test->prot_listener, &read_set)) { 3768a0b5a5dSsethdelliott 377c9693599SJef Poskanzer if ((s = test->protocol->accept(test)) < 0) { 378c9693599SJef Poskanzer cleanup_server(test); 379ec2d0670SJef Poskanzer return -1; 380c9693599SJef Poskanzer } 3818a0b5a5dSsethdelliott 3828a0b5a5dSsethdelliott if (!is_closed(s)) { 38366ce7ad4Ssethdelliott sp = iperf_new_stream(test, s); 384c9693599SJef Poskanzer if (!sp) { 385c9693599SJef Poskanzer cleanup_server(test); 386ec2d0670SJef Poskanzer return -1; 387c9693599SJef Poskanzer } 38866ce7ad4Ssethdelliott 3898a0b5a5dSsethdelliott FD_SET(s, &test->read_set); 3908a0b5a5dSsethdelliott FD_SET(s, &test->write_set); 3918a0b5a5dSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 39266ce7ad4Ssethdelliott 393112a907cSsethdelliott streams_accepted++; 3944df383f6Ssethdelliott if (test->on_new_stream) 3954df383f6Ssethdelliott test->on_new_stream(sp); 396b68ac00eSsethdelliott } 3976177a7f1SJef Poskanzer FD_CLR(test->prot_listener, &read_set); 398b68ac00eSsethdelliott } 3998a0b5a5dSsethdelliott 400112a907cSsethdelliott if (streams_accepted == test->num_streams) { 40166ce7ad4Ssethdelliott if (test->protocol->id != Ptcp) { 4028a0b5a5dSsethdelliott FD_CLR(test->prot_listener, &test->read_set); 4038a0b5a5dSsethdelliott close(test->prot_listener); 40466ce7ad4Ssethdelliott } else { 4050bd8d9daSsethdelliott if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { 40666ce7ad4Ssethdelliott FD_CLR(test->listener, &test->read_set); 40766ce7ad4Ssethdelliott close(test->listener); 408f99bd3b2Ssethdelliott if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { 409c9693599SJef Poskanzer cleanup_server(test); 410b60a49ddSsethdelliott i_errno = IELISTEN; 411ec2d0670SJef Poskanzer return -1; 412c81883bfSsethdelliott } 41366ce7ad4Ssethdelliott test->listener = s; 414c81883bfSsethdelliott test->max_fd = (s > test->max_fd ? s : test->max_fd); 41566ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 416c81883bfSsethdelliott } 4178556db5dSsethdelliott } 4188a0b5a5dSsethdelliott test->prot_listener = -1; 419c9693599SJef Poskanzer if (iperf_set_send_state(test, TEST_START) != 0) { 420c9693599SJef Poskanzer cleanup_server(test); 421ec2d0670SJef Poskanzer return -1; 422982c704aSsethdelliott } 423c9693599SJef Poskanzer if (iperf_init_test(test) < 0) { 424c9693599SJef Poskanzer cleanup_server(test); 425ec2d0670SJef Poskanzer return -1; 426c9693599SJef Poskanzer } 42757892604SJef Poskanzer if (create_server_omit_timer(test) < 0) { 428c9693599SJef Poskanzer cleanup_server(test); 429c9693599SJef Poskanzer return -1; 430c9693599SJef Poskanzer } 431c9693599SJef Poskanzer if (iperf_set_send_state(test, TEST_RUNNING) != 0) { 432c9693599SJef Poskanzer cleanup_server(test); 433ec2d0670SJef Poskanzer return -1; 434f1b3bd81Ssethdelliott } 435982c704aSsethdelliott } 436982c704aSsethdelliott } 437982c704aSsethdelliott 438f1b3bd81Ssethdelliott if (test->state == TEST_RUNNING) { 439465b565cSsethdelliott if (test->reverse) { 440465b565cSsethdelliott // Reverse mode. Server sends. 441c9693599SJef Poskanzer if (iperf_send(test, &write_set) < 0) { 442c9693599SJef Poskanzer cleanup_server(test); 443ec2d0670SJef Poskanzer return -1; 444c9693599SJef Poskanzer } 445982c704aSsethdelliott } else { 446465b565cSsethdelliott // Regular mode. Server receives. 447c9693599SJef Poskanzer if (iperf_recv(test, &read_set) < 0) { 448c9693599SJef Poskanzer cleanup_server(test); 449ec2d0670SJef Poskanzer return -1; 450e99faeaeSBrian Tierney } 451c9693599SJef Poskanzer } 452f1b3bd81Ssethdelliott 453ec2d0670SJef Poskanzer /* Run the timers. */ 454ec2d0670SJef Poskanzer (void) gettimeofday(&now, NULL); 455ec2d0670SJef Poskanzer tmr_run(&now); 456f1b3bd81Ssethdelliott } 457a951c980SBrian Tierney } 458982c704aSsethdelliott } 459e99faeaeSBrian Tierney 460c9693599SJef Poskanzer cleanup_server(test); 461efdc02f7Ssethdelliott 462e96ab740SJef Poskanzer if (test->json_output) { 463e96ab740SJef Poskanzer if (iperf_json_finish(test) < 0) 464e96ab740SJef Poskanzer return -1; 465e96ab740SJef Poskanzer } 466e96ab740SJef Poskanzer 467ec2d0670SJef Poskanzer return 0; 468a3281a3dSBrian Tierney } 469