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'); 90f8bd11afSJef Poskanzer if (!test->json_output) 91982c704aSsethdelliott printf("TCP window size: %s\n", ubuf); 92982c704aSsethdelliott } else { 93f8bd11afSJef 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; 113*4e2ef507SJef Poskanzer signed char 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; 1408a7e01ebSJef Poskanzer if (test->server_affinity != -1) 1418a7e01ebSJef Poskanzer if (iperf_setaffinity(test->server_affinity) != 0) 1428a7e01ebSJef Poskanzer return -1; 1438bdc8fffSJef Poskanzer if (test->on_connect) 1444df383f6Ssethdelliott test->on_connect(test); 145982c704aSsethdelliott } else { 146111645edSJef Poskanzer /* XXX: Do we even need to receive cookie if we're just going to deny anyways? */ 147af70b448Ssethdelliott if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { 148b60a49ddSsethdelliott i_errno = IERECVCOOKIE; 149ec2d0670SJef Poskanzer return -1; 150465b565cSsethdelliott } 151*4e2ef507SJef Poskanzer if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) { 152b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 153ec2d0670SJef Poskanzer return -1; 154465b565cSsethdelliott } 155465b565cSsethdelliott close(s); 156982c704aSsethdelliott } 157982c704aSsethdelliott 158ec2d0670SJef Poskanzer return 0; 159af70b448Ssethdelliott } 160af70b448Ssethdelliott 161b68ac00eSsethdelliott 162a951c980SBrian Tierney /**************************************************************************/ 163982c704aSsethdelliott int 164465b565cSsethdelliott iperf_handle_message_server(struct iperf_test *test) 165982c704aSsethdelliott { 166b68ac00eSsethdelliott int rval; 167efdc02f7Ssethdelliott struct iperf_stream *sp; 168efdc02f7Ssethdelliott 169b60a49ddSsethdelliott // XXX: Need to rethink how this behaves to fit API 17001943402SJef Poskanzer if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp)) <= 0) { 171b68ac00eSsethdelliott if (rval == 0) { 172b5e0751fSJef Poskanzer iperf_err(test, "the client has unexpectedly closed the connection"); 173b60a49ddSsethdelliott i_errno = IECTRLCLOSE; 174b68ac00eSsethdelliott test->state = IPERF_DONE; 175ec2d0670SJef Poskanzer return 0; 176b68ac00eSsethdelliott } else { 177b60a49ddSsethdelliott i_errno = IERECVMESSAGE; 178ec2d0670SJef Poskanzer return -1; 179982c704aSsethdelliott } 180b68ac00eSsethdelliott } 181982c704aSsethdelliott 182982c704aSsethdelliott switch(test->state) { 183ba2672a2Ssethdelliott case TEST_START: 184ba2672a2Ssethdelliott break; 185465b565cSsethdelliott case TEST_END: 1863331e801Ssethdelliott cpu_util(&test->cpu_util); 187f1b3bd81Ssethdelliott test->stats_callback(test); 188dd4bc008Ssethdelliott SLIST_FOREACH(sp, &test->streams, streams) { 189efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->read_set); 190efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->write_set); 191efdc02f7Ssethdelliott close(sp->socket); 192efdc02f7Ssethdelliott } 193c9693599SJef Poskanzer if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0) 194ec2d0670SJef Poskanzer return -1; 195b60a49ddSsethdelliott if (iperf_exchange_results(test) < 0) 196ec2d0670SJef Poskanzer return -1; 197c9693599SJef Poskanzer if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0) 198ec2d0670SJef Poskanzer return -1; 1994df383f6Ssethdelliott if (test->on_test_finish) 2004df383f6Ssethdelliott test->on_test_finish(test); 201181d61afSsethdelliott test->reporter_callback(test); 202465b565cSsethdelliott break; 203873952e3Ssethdelliott case IPERF_DONE: 204873952e3Ssethdelliott break; 205465b565cSsethdelliott case CLIENT_TERMINATE: 206ffdcc7d4Ssethdelliott i_errno = IECLIENTTERM; 207ffdcc7d4Ssethdelliott 208ffdcc7d4Ssethdelliott // XXX: Remove this line below! 209b5e0751fSJef Poskanzer iperf_err(test, "the client has terminated"); 210dd4bc008Ssethdelliott SLIST_FOREACH(sp, &test->streams, streams) { 2111ac522ecSsethdelliott FD_CLR(sp->socket, &test->read_set); 2121ac522ecSsethdelliott FD_CLR(sp->socket, &test->write_set); 2131ac522ecSsethdelliott close(sp->socket); 2141ac522ecSsethdelliott } 2151ac522ecSsethdelliott test->state = IPERF_DONE; 2161ac522ecSsethdelliott break; 217ba2672a2Ssethdelliott default: 218b60a49ddSsethdelliott i_errno = IEMESSAGE; 219ec2d0670SJef Poskanzer return -1; 220982c704aSsethdelliott } 221982c704aSsethdelliott 222ec2d0670SJef Poskanzer return 0; 223982c704aSsethdelliott } 224982c704aSsethdelliott 2250bd8d9daSsethdelliott /* XXX: This function is not used anymore */ 226efdc02f7Ssethdelliott void 227efdc02f7Ssethdelliott iperf_test_reset(struct iperf_test *test) 228efdc02f7Ssethdelliott { 2290bd8d9daSsethdelliott struct iperf_stream *sp; 230efdc02f7Ssethdelliott 231efdc02f7Ssethdelliott close(test->ctrl_sck); 232efdc02f7Ssethdelliott 233efdc02f7Ssethdelliott /* Free streams */ 234dd4bc008Ssethdelliott while (!SLIST_EMPTY(&test->streams)) { 235dd4bc008Ssethdelliott sp = SLIST_FIRST(&test->streams); 236dd4bc008Ssethdelliott SLIST_REMOVE_HEAD(&test->streams, streams); 237dd4bc008Ssethdelliott iperf_free_stream(sp); 238dd4bc008Ssethdelliott } 239ec2d0670SJef Poskanzer if (test->timer != NULL) { 240ec2d0670SJef Poskanzer tmr_cancel(test->timer); 241f1b3bd81Ssethdelliott test->timer = NULL; 242ec2d0670SJef Poskanzer } 243ec2d0670SJef Poskanzer if (test->stats_timer != NULL) { 244ec2d0670SJef Poskanzer tmr_cancel(test->stats_timer); 245f1b3bd81Ssethdelliott test->stats_timer = NULL; 246ec2d0670SJef Poskanzer } 247ec2d0670SJef Poskanzer if (test->reporter_timer != NULL) { 248ec2d0670SJef Poskanzer tmr_cancel(test->reporter_timer); 249f1b3bd81Ssethdelliott test->reporter_timer = NULL; 250ec2d0670SJef Poskanzer } 251efdc02f7Ssethdelliott 252dd4bc008Ssethdelliott SLIST_INIT(&test->streams); 25332885561Ssethdelliott 254efdc02f7Ssethdelliott test->role = 's'; 25566ce7ad4Ssethdelliott set_protocol(test, Ptcp); 25657892604SJef Poskanzer test->omit = OMIT; 25732885561Ssethdelliott test->duration = DURATION; 258e32a7bcdSJef Poskanzer test->diskfile_name = (char*) 0; 2598a7e01ebSJef Poskanzer test->affinity = -1; 2608a7e01ebSJef Poskanzer test->server_affinity = -1; 26132885561Ssethdelliott test->state = 0; 26232885561Ssethdelliott test->server_hostname = NULL; 26332885561Ssethdelliott 26432885561Ssethdelliott test->ctrl_sck = -1; 26566ce7ad4Ssethdelliott test->prot_listener = -1; 26632885561Ssethdelliott 267f1b3bd81Ssethdelliott test->bytes_sent = 0; 268f1b3bd81Ssethdelliott 26932885561Ssethdelliott test->reverse = 0; 2702c042fd4SJef Poskanzer test->sender = 0; 27169bdbfd3SJef Poskanzer test->sender_has_retransmits = 0; 272b68ac00eSsethdelliott test->no_delay = 0; 27332885561Ssethdelliott 274efdc02f7Ssethdelliott FD_ZERO(&test->read_set); 275efdc02f7Ssethdelliott FD_ZERO(&test->write_set); 27666ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 27766ce7ad4Ssethdelliott test->max_fd = test->listener; 27832885561Ssethdelliott 27932885561Ssethdelliott test->num_streams = 1; 280112a907cSsethdelliott test->settings->socket_bufsize = 0; 281112a907cSsethdelliott test->settings->blksize = DEFAULT_TCP_BLKSIZE; 282d611f13eSJef Poskanzer test->settings->rate = 0; 283112a907cSsethdelliott test->settings->mss = 0; 284112a907cSsethdelliott memset(test->cookie, 0, COOKIE_SIZE); 285efdc02f7Ssethdelliott } 286efdc02f7Ssethdelliott 287c9693599SJef Poskanzer static void 28838917b1fSJef Poskanzer server_stats_timer_proc(TimerClientData client_data, struct timeval *nowP) 28938917b1fSJef Poskanzer { 29038917b1fSJef Poskanzer struct iperf_test *test = client_data.p; 29138917b1fSJef Poskanzer 29238917b1fSJef Poskanzer if (test->done) 29338917b1fSJef Poskanzer return; 29438917b1fSJef Poskanzer if (test->stats_callback) 29538917b1fSJef Poskanzer test->stats_callback(test); 29638917b1fSJef Poskanzer } 29738917b1fSJef Poskanzer 29838917b1fSJef Poskanzer static void 29938917b1fSJef Poskanzer server_reporter_timer_proc(TimerClientData client_data, struct timeval *nowP) 30038917b1fSJef Poskanzer { 30138917b1fSJef Poskanzer struct iperf_test *test = client_data.p; 30238917b1fSJef Poskanzer 30338917b1fSJef Poskanzer if (test->done) 30438917b1fSJef Poskanzer return; 30538917b1fSJef Poskanzer if (test->reporter_callback) 30638917b1fSJef Poskanzer test->reporter_callback(test); 30738917b1fSJef Poskanzer } 30838917b1fSJef Poskanzer 30938917b1fSJef Poskanzer static int 31038917b1fSJef Poskanzer create_server_timers(struct iperf_test * test) 31138917b1fSJef Poskanzer { 31238917b1fSJef Poskanzer struct timeval now; 31338917b1fSJef Poskanzer TimerClientData cd; 31438917b1fSJef Poskanzer 31538917b1fSJef Poskanzer if (gettimeofday(&now, NULL) < 0) { 31638917b1fSJef Poskanzer i_errno = IEINITTEST; 31738917b1fSJef Poskanzer return -1; 31838917b1fSJef Poskanzer } 31938917b1fSJef Poskanzer cd.p = test; 32038917b1fSJef Poskanzer test->stats_timer = test->reporter_timer = NULL; 32138917b1fSJef Poskanzer if (test->stats_interval != 0) { 32238917b1fSJef Poskanzer test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1); 32338917b1fSJef Poskanzer if (test->stats_timer == NULL) { 32438917b1fSJef Poskanzer i_errno = IEINITTEST; 32538917b1fSJef Poskanzer return -1; 32638917b1fSJef Poskanzer } 32738917b1fSJef Poskanzer } 32838917b1fSJef Poskanzer if (test->reporter_interval != 0) { 32938917b1fSJef Poskanzer test->reporter_timer = tmr_create(&now, server_reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1); 33038917b1fSJef Poskanzer if (test->reporter_timer == NULL) { 33138917b1fSJef Poskanzer i_errno = IEINITTEST; 33238917b1fSJef Poskanzer return -1; 33338917b1fSJef Poskanzer } 33438917b1fSJef Poskanzer } 33538917b1fSJef Poskanzer return 0; 33638917b1fSJef Poskanzer } 33738917b1fSJef Poskanzer 33838917b1fSJef Poskanzer static void 33957892604SJef Poskanzer server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP) 340c9693599SJef Poskanzer { 341c9693599SJef Poskanzer struct iperf_test *test = client_data.p; 342c9693599SJef Poskanzer 34357892604SJef Poskanzer test->omit_timer = NULL; 34457892604SJef Poskanzer test->omitting = 0; 345c9693599SJef Poskanzer iperf_reset_stats(test); 346a953f5aaSJef Poskanzer if (test->verbose && !test->json_output && test->reporter_interval == 0) 34757892604SJef Poskanzer printf("Finished omit period, starting real test\n"); 34838917b1fSJef Poskanzer 34938917b1fSJef Poskanzer /* Reset the timers. */ 35038917b1fSJef Poskanzer if (test->stats_timer != NULL) 35138917b1fSJef Poskanzer tmr_reset(nowP, test->stats_timer); 35238917b1fSJef Poskanzer if (test->reporter_timer != NULL) 35338917b1fSJef Poskanzer tmr_reset(nowP, test->reporter_timer); 354c9693599SJef Poskanzer } 355c9693599SJef Poskanzer 356c9693599SJef Poskanzer static int 35757892604SJef Poskanzer create_server_omit_timer(struct iperf_test * test) 358c9693599SJef Poskanzer { 359c9693599SJef Poskanzer struct timeval now; 360c9693599SJef Poskanzer TimerClientData cd; 361c9693599SJef Poskanzer 362a953f5aaSJef Poskanzer if (test->omit == 0) { 363a953f5aaSJef Poskanzer test->omit_timer = NULL; 364a953f5aaSJef Poskanzer test->omitting = 0; 365a953f5aaSJef Poskanzer } else { 366c9693599SJef Poskanzer if (gettimeofday(&now, NULL) < 0) { 367c9693599SJef Poskanzer i_errno = IEINITTEST; 368c9693599SJef Poskanzer return -1; 369c9693599SJef Poskanzer } 37057892604SJef Poskanzer test->omitting = 1; 371c9693599SJef Poskanzer cd.p = test; 37257892604SJef Poskanzer test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0); 37357892604SJef Poskanzer if (test->omit_timer == NULL) { 374c9693599SJef Poskanzer i_errno = IEINITTEST; 375c9693599SJef Poskanzer return -1; 376c9693599SJef Poskanzer } 377a953f5aaSJef Poskanzer } 378a953f5aaSJef Poskanzer 379c9693599SJef Poskanzer return 0; 380c9693599SJef Poskanzer } 381c9693599SJef Poskanzer 382c9693599SJef Poskanzer static void 383c9693599SJef Poskanzer cleanup_server(struct iperf_test *test) 384c9693599SJef Poskanzer { 385c9693599SJef Poskanzer /* Close open test sockets */ 386c9693599SJef Poskanzer close(test->ctrl_sck); 387c9693599SJef Poskanzer close(test->listener); 38838917b1fSJef Poskanzer 38938917b1fSJef Poskanzer /* Cancel any remaining timers. */ 39038917b1fSJef Poskanzer if (test->stats_timer != NULL) { 39138917b1fSJef Poskanzer tmr_cancel(test->stats_timer); 39238917b1fSJef Poskanzer test->stats_timer = NULL; 39338917b1fSJef Poskanzer } 39438917b1fSJef Poskanzer if (test->reporter_timer != NULL) { 39538917b1fSJef Poskanzer tmr_cancel(test->reporter_timer); 39638917b1fSJef Poskanzer test->reporter_timer = NULL; 39738917b1fSJef Poskanzer } 39838917b1fSJef Poskanzer if (test->omit_timer != NULL) { 39938917b1fSJef Poskanzer tmr_cancel(test->omit_timer); 40038917b1fSJef Poskanzer test->omit_timer = NULL; 40138917b1fSJef Poskanzer } 402c9693599SJef Poskanzer } 403c9693599SJef Poskanzer 404afe6222aSJef Poskanzer 405afe6222aSJef Poskanzer static jmp_buf sigend_jmp_buf; 406afe6222aSJef Poskanzer 407afe6222aSJef Poskanzer static void 408afe6222aSJef Poskanzer sigend_handler(int sig) 409afe6222aSJef Poskanzer { 410afe6222aSJef Poskanzer longjmp(sigend_jmp_buf, 1); 411afe6222aSJef Poskanzer } 412afe6222aSJef Poskanzer 413afe6222aSJef Poskanzer 4147fa9f68fSsethdelliott int 415a951c980SBrian Tierney iperf_run_server(struct iperf_test *test) 416a951c980SBrian Tierney { 417112a907cSsethdelliott int result, s, streams_accepted; 4186177a7f1SJef Poskanzer fd_set read_set, write_set; 4198a0b5a5dSsethdelliott struct iperf_stream *sp; 420ec2d0670SJef Poskanzer struct timeval now; 421a951c980SBrian Tierney 422afe6222aSJef Poskanzer /* Termination signals. */ 423afe6222aSJef Poskanzer iperf_catch_sigend(sigend_handler); 424afe6222aSJef Poskanzer if (setjmp(sigend_jmp_buf)) 425afe6222aSJef Poskanzer iperf_got_sigend(test); 426afe6222aSJef Poskanzer 4278a7e01ebSJef Poskanzer if (test->affinity != -1) 4288a7e01ebSJef Poskanzer if (iperf_setaffinity(test->affinity) != 0) 4298a7e01ebSJef Poskanzer return -1; 4308a7e01ebSJef Poskanzer 431e96ab740SJef Poskanzer if (test->json_output) 432e96ab740SJef Poskanzer if (iperf_json_start(test) < 0) 433e96ab740SJef Poskanzer return -1; 434e96ab740SJef Poskanzer 435e96ab740SJef Poskanzer if (test->json_output) { 436e96ab740SJef Poskanzer cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version)); 437e96ab740SJef Poskanzer cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info())); 438e96ab740SJef Poskanzer } else if (test->verbose) { 439e96ab740SJef Poskanzer printf("%s\n", version); 440e96ab740SJef Poskanzer system("uname -a"); 441e96ab740SJef Poskanzer } 442e96ab740SJef Poskanzer 443982c704aSsethdelliott // Open socket and listen 444982c704aSsethdelliott if (iperf_server_listen(test) < 0) { 445ec2d0670SJef Poskanzer return -1; 446e99faeaeSBrian Tierney } 447a951c980SBrian Tierney 4483331e801Ssethdelliott // Begin calculating CPU utilization 4493331e801Ssethdelliott cpu_util(NULL); 4503331e801Ssethdelliott 451efdc02f7Ssethdelliott test->state = IPERF_START; 452112a907cSsethdelliott streams_accepted = 0; 453a951c980SBrian Tierney 454ec2d0670SJef Poskanzer (void) gettimeofday(&now, NULL); 455873952e3Ssethdelliott while (test->state != IPERF_DONE) { 456982c704aSsethdelliott 4576177a7f1SJef Poskanzer memcpy(&read_set, &test->read_set, sizeof(fd_set)); 4586177a7f1SJef Poskanzer memcpy(&write_set, &test->write_set, sizeof(fd_set)); 459982c704aSsethdelliott 4606177a7f1SJef Poskanzer result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now)); 461982c704aSsethdelliott if (result < 0 && errno != EINTR) { 462c9693599SJef Poskanzer cleanup_server(test); 463b60a49ddSsethdelliott i_errno = IESELECT; 464ec2d0670SJef Poskanzer return -1; 465ec2d0670SJef Poskanzer } 466ec2d0670SJef Poskanzer if (result > 0) { 4676177a7f1SJef Poskanzer if (FD_ISSET(test->listener, &read_set)) { 468b68ac00eSsethdelliott if (test->state != CREATE_STREAMS) { 469465b565cSsethdelliott if (iperf_accept(test) < 0) { 470c9693599SJef Poskanzer cleanup_server(test); 471ec2d0670SJef Poskanzer return -1; 472982c704aSsethdelliott } 4736177a7f1SJef Poskanzer FD_CLR(test->listener, &read_set); 474982c704aSsethdelliott } 475b68ac00eSsethdelliott } 4766177a7f1SJef Poskanzer if (FD_ISSET(test->ctrl_sck, &read_set)) { 477c9693599SJef Poskanzer if (iperf_handle_message_server(test) < 0) { 478c9693599SJef Poskanzer cleanup_server(test); 479ec2d0670SJef Poskanzer return -1; 480c9693599SJef Poskanzer } 4816177a7f1SJef Poskanzer FD_CLR(test->ctrl_sck, &read_set); 482982c704aSsethdelliott } 483465b565cSsethdelliott 484465b565cSsethdelliott if (test->state == CREATE_STREAMS) { 4856177a7f1SJef Poskanzer if (FD_ISSET(test->prot_listener, &read_set)) { 4868a0b5a5dSsethdelliott 487c9693599SJef Poskanzer if ((s = test->protocol->accept(test)) < 0) { 488c9693599SJef Poskanzer cleanup_server(test); 489ec2d0670SJef Poskanzer return -1; 490c9693599SJef Poskanzer } 4918a0b5a5dSsethdelliott 4928a0b5a5dSsethdelliott if (!is_closed(s)) { 49366ce7ad4Ssethdelliott sp = iperf_new_stream(test, s); 494c9693599SJef Poskanzer if (!sp) { 495c9693599SJef Poskanzer cleanup_server(test); 496ec2d0670SJef Poskanzer return -1; 497c9693599SJef Poskanzer } 49866ce7ad4Ssethdelliott 4998a0b5a5dSsethdelliott FD_SET(s, &test->read_set); 5008a0b5a5dSsethdelliott FD_SET(s, &test->write_set); 5018a0b5a5dSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 50266ce7ad4Ssethdelliott 503112a907cSsethdelliott streams_accepted++; 5044df383f6Ssethdelliott if (test->on_new_stream) 5054df383f6Ssethdelliott test->on_new_stream(sp); 506b68ac00eSsethdelliott } 5076177a7f1SJef Poskanzer FD_CLR(test->prot_listener, &read_set); 508b68ac00eSsethdelliott } 5098a0b5a5dSsethdelliott 510112a907cSsethdelliott if (streams_accepted == test->num_streams) { 51166ce7ad4Ssethdelliott if (test->protocol->id != Ptcp) { 5128a0b5a5dSsethdelliott FD_CLR(test->prot_listener, &test->read_set); 5138a0b5a5dSsethdelliott close(test->prot_listener); 51466ce7ad4Ssethdelliott } else { 5150bd8d9daSsethdelliott if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { 51666ce7ad4Ssethdelliott FD_CLR(test->listener, &test->read_set); 51766ce7ad4Ssethdelliott close(test->listener); 518f99bd3b2Ssethdelliott if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { 519c9693599SJef Poskanzer cleanup_server(test); 520b60a49ddSsethdelliott i_errno = IELISTEN; 521ec2d0670SJef Poskanzer return -1; 522c81883bfSsethdelliott } 52366ce7ad4Ssethdelliott test->listener = s; 524c81883bfSsethdelliott test->max_fd = (s > test->max_fd ? s : test->max_fd); 52566ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 526c81883bfSsethdelliott } 5278556db5dSsethdelliott } 5288a0b5a5dSsethdelliott test->prot_listener = -1; 529c9693599SJef Poskanzer if (iperf_set_send_state(test, TEST_START) != 0) { 530c9693599SJef Poskanzer cleanup_server(test); 531ec2d0670SJef Poskanzer return -1; 532982c704aSsethdelliott } 533c9693599SJef Poskanzer if (iperf_init_test(test) < 0) { 534c9693599SJef Poskanzer cleanup_server(test); 535ec2d0670SJef Poskanzer return -1; 536c9693599SJef Poskanzer } 53738917b1fSJef Poskanzer if (create_server_timers(test) < 0) { 53838917b1fSJef Poskanzer cleanup_server(test); 53938917b1fSJef Poskanzer return -1; 54038917b1fSJef Poskanzer } 54157892604SJef Poskanzer if (create_server_omit_timer(test) < 0) { 542c9693599SJef Poskanzer cleanup_server(test); 543c9693599SJef Poskanzer return -1; 544c9693599SJef Poskanzer } 5458bdc8fffSJef Poskanzer if (test->reverse) 5468bdc8fffSJef Poskanzer if (iperf_create_send_timers(test) < 0) { 5478bdc8fffSJef Poskanzer cleanup_server(test); 5488bdc8fffSJef Poskanzer return -1; 5498bdc8fffSJef Poskanzer } 550c9693599SJef Poskanzer if (iperf_set_send_state(test, TEST_RUNNING) != 0) { 551c9693599SJef Poskanzer cleanup_server(test); 552ec2d0670SJef Poskanzer return -1; 553f1b3bd81Ssethdelliott } 554982c704aSsethdelliott } 555982c704aSsethdelliott } 556982c704aSsethdelliott 557f1b3bd81Ssethdelliott if (test->state == TEST_RUNNING) { 558465b565cSsethdelliott if (test->reverse) { 559465b565cSsethdelliott // Reverse mode. Server sends. 560c9693599SJef Poskanzer if (iperf_send(test, &write_set) < 0) { 561c9693599SJef Poskanzer cleanup_server(test); 562ec2d0670SJef Poskanzer return -1; 563c9693599SJef Poskanzer } 564982c704aSsethdelliott } else { 565465b565cSsethdelliott // Regular mode. Server receives. 566c9693599SJef Poskanzer if (iperf_recv(test, &read_set) < 0) { 567c9693599SJef Poskanzer cleanup_server(test); 568ec2d0670SJef Poskanzer return -1; 569e99faeaeSBrian Tierney } 570c9693599SJef Poskanzer } 571f1b3bd81Ssethdelliott 572ec2d0670SJef Poskanzer /* Run the timers. */ 573ec2d0670SJef Poskanzer (void) gettimeofday(&now, NULL); 574ec2d0670SJef Poskanzer tmr_run(&now); 575f1b3bd81Ssethdelliott } 576a951c980SBrian Tierney } 577982c704aSsethdelliott } 578e99faeaeSBrian Tierney 579c9693599SJef Poskanzer cleanup_server(test); 580efdc02f7Ssethdelliott 581e96ab740SJef Poskanzer if (test->json_output) { 582e96ab740SJef Poskanzer if (iperf_json_finish(test) < 0) 583e96ab740SJef Poskanzer return -1; 584e96ab740SJef Poskanzer } 585e96ab740SJef Poskanzer 5868a7e01ebSJef Poskanzer if (test->server_affinity != -1) 5878a7e01ebSJef Poskanzer if (iperf_clearaffinity() != 0) 5888a7e01ebSJef Poskanzer return -1; 5898a7e01ebSJef Poskanzer 590ec2d0670SJef Poskanzer return 0; 591a3281a3dSBrian Tierney } 592