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 55*f99bd3b2Ssethdelliott if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, 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) { 76112a907cSsethdelliott 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; 99af70b448Ssethdelliott char cookie[COOKIE_SIZE]; 100982c704aSsethdelliott socklen_t len; 101982c704aSsethdelliott struct sockaddr_in addr; 102982c704aSsethdelliott 103b68ac00eSsethdelliott len = sizeof(addr); 10466ce7ad4Ssethdelliott if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { 105b60a49ddSsethdelliott i_errno = IEACCEPT; 106b60a49ddSsethdelliott return (-1); 107982c704aSsethdelliott } 108af70b448Ssethdelliott 109af70b448Ssethdelliott if (test->ctrl_sck == -1) { 110af70b448Ssethdelliott /* Server free, accept new client */ 111112a907cSsethdelliott if (Nread(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { 112b60a49ddSsethdelliott i_errno = IERECVCOOKIE; 113b60a49ddSsethdelliott return (-1); 114af70b448Ssethdelliott } 115af70b448Ssethdelliott 116465b565cSsethdelliott FD_SET(s, &test->read_set); 117465b565cSsethdelliott FD_SET(s, &test->write_set); 118465b565cSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 119465b565cSsethdelliott test->ctrl_sck = s; 120982c704aSsethdelliott 121af70b448Ssethdelliott test->state = PARAM_EXCHANGE; 122af70b448Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 123b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 124b60a49ddSsethdelliott return (-1); 125af70b448Ssethdelliott } 126b60a49ddSsethdelliott if (iperf_exchange_parameters(test) < 0) { 127b60a49ddSsethdelliott return (-1); 128b60a49ddSsethdelliott } 1294df383f6Ssethdelliott if (test->on_connect) { 1304df383f6Ssethdelliott test->on_connect(test); 1314df383f6Ssethdelliott } 132982c704aSsethdelliott } else { 133b60a49ddSsethdelliott // 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; 136b60a49ddSsethdelliott return (-1); 137465b565cSsethdelliott } 138efb7bbe4Ssethdelliott if (Nwrite(s, &rbuf, sizeof(int), Ptcp) < 0) { 139b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 140b60a49ddSsethdelliott return (-1); 141465b565cSsethdelliott } 142465b565cSsethdelliott close(s); 143982c704aSsethdelliott } 144982c704aSsethdelliott 145b60a49ddSsethdelliott 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) { 159b68ac00eSsethdelliott fprintf(stderr, "The client has unexpectedly closed the connection.\n"); 160b60a49ddSsethdelliott i_errno = IECTRLCLOSE; 161b68ac00eSsethdelliott test->state = IPERF_DONE; 162b60a49ddSsethdelliott return (0); 163b68ac00eSsethdelliott } else { 164b60a49ddSsethdelliott i_errno = IERECVMESSAGE; 165b60a49ddSsethdelliott return (-1); 166982c704aSsethdelliott } 167b68ac00eSsethdelliott } 168982c704aSsethdelliott 169982c704aSsethdelliott switch(test->state) { 170ba2672a2Ssethdelliott case TEST_START: 171ba2672a2Ssethdelliott break; 172465b565cSsethdelliott case TEST_END: 173f1b3bd81Ssethdelliott test->stats_callback(test); 174efdc02f7Ssethdelliott for (sp = test->streams; sp; sp = sp->next) { 175efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->read_set); 176efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->write_set); 177efdc02f7Ssethdelliott close(sp->socket); 178efdc02f7Ssethdelliott } 179181d61afSsethdelliott test->state = EXCHANGE_RESULTS; 180efb7bbe4Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 181b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 182b60a49ddSsethdelliott return (-1); 183181d61afSsethdelliott } 184b60a49ddSsethdelliott if (iperf_exchange_results(test) < 0) 185b60a49ddSsethdelliott return (-1); 186873952e3Ssethdelliott test->state = DISPLAY_RESULTS; 187efb7bbe4Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 188b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 189b60a49ddSsethdelliott return (-1); 190465b565cSsethdelliott } 1914df383f6Ssethdelliott if (test->on_test_finish) 1924df383f6Ssethdelliott test->on_test_finish(test); 193181d61afSsethdelliott test->reporter_callback(test); 194465b565cSsethdelliott break; 195873952e3Ssethdelliott case IPERF_DONE: 196873952e3Ssethdelliott break; 197465b565cSsethdelliott case CLIENT_TERMINATE: 1981ac522ecSsethdelliott fprintf(stderr, "The client has terminated.\n"); 1991ac522ecSsethdelliott for (sp = test->streams; sp; sp = sp->next) { 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; 208b60a49ddSsethdelliott return (-1); 209982c704aSsethdelliott } 210982c704aSsethdelliott 211b60a49ddSsethdelliott return (0); 212982c704aSsethdelliott } 213982c704aSsethdelliott 214efdc02f7Ssethdelliott void 215efdc02f7Ssethdelliott iperf_test_reset(struct iperf_test *test) 216efdc02f7Ssethdelliott { 217efdc02f7Ssethdelliott struct iperf_stream *sp, *np; 218efdc02f7Ssethdelliott 219efdc02f7Ssethdelliott close(test->ctrl_sck); 220efdc02f7Ssethdelliott 221efdc02f7Ssethdelliott /* Free streams */ 222efdc02f7Ssethdelliott for (sp = test->streams; sp; sp = np) { 223efdc02f7Ssethdelliott np = sp->next; 224efdc02f7Ssethdelliott iperf_free_stream(sp); 225efdc02f7Ssethdelliott } 226f1b3bd81Ssethdelliott free_timer(test->timer); 227f1b3bd81Ssethdelliott free_timer(test->stats_timer); 228f1b3bd81Ssethdelliott free_timer(test->reporter_timer); 229f1b3bd81Ssethdelliott test->timer = NULL; 230f1b3bd81Ssethdelliott test->stats_timer = NULL; 231f1b3bd81Ssethdelliott test->reporter_timer = NULL; 232efdc02f7Ssethdelliott 23332885561Ssethdelliott test->streams = NULL; 23432885561Ssethdelliott 235efdc02f7Ssethdelliott test->role = 's'; 23666ce7ad4Ssethdelliott set_protocol(test, Ptcp); 23732885561Ssethdelliott test->duration = DURATION; 23832885561Ssethdelliott test->state = 0; 23932885561Ssethdelliott test->server_hostname = NULL; 24032885561Ssethdelliott 24132885561Ssethdelliott test->ctrl_sck = -1; 24266ce7ad4Ssethdelliott test->prot_listener = -1; 24332885561Ssethdelliott 244f1b3bd81Ssethdelliott test->bytes_sent = 0; 245f1b3bd81Ssethdelliott 24632885561Ssethdelliott test->reverse = 0; 247b68ac00eSsethdelliott test->no_delay = 0; 24832885561Ssethdelliott 249efdc02f7Ssethdelliott FD_ZERO(&test->read_set); 250efdc02f7Ssethdelliott FD_ZERO(&test->write_set); 25166ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 25266ce7ad4Ssethdelliott test->max_fd = test->listener; 25332885561Ssethdelliott 25432885561Ssethdelliott test->num_streams = 1; 255112a907cSsethdelliott test->settings->socket_bufsize = 0; 256112a907cSsethdelliott test->settings->blksize = DEFAULT_TCP_BLKSIZE; 257112a907cSsethdelliott test->settings->rate = RATE; /* UDP only */ 258112a907cSsethdelliott test->settings->mss = 0; 259112a907cSsethdelliott memset(test->cookie, 0, COOKIE_SIZE); 260efdc02f7Ssethdelliott } 261efdc02f7Ssethdelliott 2627fa9f68fSsethdelliott int 263a951c980SBrian Tierney iperf_run_server(struct iperf_test *test) 264a951c980SBrian Tierney { 265112a907cSsethdelliott int result, s, streams_accepted; 266efdc02f7Ssethdelliott fd_set temp_read_set, temp_write_set; 2678a0b5a5dSsethdelliott struct iperf_stream *sp; 2687fa9f68fSsethdelliott struct timeval tv; 269a951c980SBrian Tierney 270982c704aSsethdelliott // Open socket and listen 271982c704aSsethdelliott if (iperf_server_listen(test) < 0) { 272b60a49ddSsethdelliott return (-1); 273e99faeaeSBrian Tierney } 274a951c980SBrian Tierney 275465b565cSsethdelliott signal(SIGINT, sig_handler); 276465b565cSsethdelliott if (setjmp(env)) { 277465b565cSsethdelliott test->state = SERVER_TERMINATE; 278465b565cSsethdelliott if (test->ctrl_sck >= 0) { 279efb7bbe4Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 280b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 281b60a49ddSsethdelliott return (-1); 282465b565cSsethdelliott } 283465b565cSsethdelliott } 28466ce7ad4Ssethdelliott return (0); 285465b565cSsethdelliott } 286465b565cSsethdelliott 287efdc02f7Ssethdelliott for ( ; ; ) { 288efdc02f7Ssethdelliott 289efdc02f7Ssethdelliott test->state = IPERF_START; 290112a907cSsethdelliott streams_accepted = 0; 291a951c980SBrian Tierney 292873952e3Ssethdelliott while (test->state != IPERF_DONE) { 293982c704aSsethdelliott 294efdc02f7Ssethdelliott memcpy(&temp_read_set, &test->read_set, sizeof(fd_set)); 295efdc02f7Ssethdelliott memcpy(&temp_write_set, &test->write_set, sizeof(fd_set)); 296982c704aSsethdelliott tv.tv_sec = 15; 297982c704aSsethdelliott tv.tv_usec = 0; 298982c704aSsethdelliott 299efdc02f7Ssethdelliott result = select(test->max_fd + 1, &temp_read_set, &temp_write_set, NULL, &tv); 300982c704aSsethdelliott if (result < 0 && errno != EINTR) { 301b60a49ddSsethdelliott i_errno = IESELECT; 302b60a49ddSsethdelliott return (-1); 303982c704aSsethdelliott } else if (result > 0) { 30466ce7ad4Ssethdelliott if (FD_ISSET(test->listener, &temp_read_set)) { 305b68ac00eSsethdelliott if (test->state != CREATE_STREAMS) { 306465b565cSsethdelliott if (iperf_accept(test) < 0) { 307b60a49ddSsethdelliott return (-1); 308982c704aSsethdelliott } 30966ce7ad4Ssethdelliott FD_CLR(test->listener, &temp_read_set); 310982c704aSsethdelliott } 311b68ac00eSsethdelliott } 312efdc02f7Ssethdelliott if (FD_ISSET(test->ctrl_sck, &temp_read_set)) { 313b60a49ddSsethdelliott if (iperf_handle_message_server(test) < 0) 314b60a49ddSsethdelliott return (-1); 315efdc02f7Ssethdelliott FD_CLR(test->ctrl_sck, &temp_read_set); 316982c704aSsethdelliott } 317465b565cSsethdelliott 318465b565cSsethdelliott if (test->state == CREATE_STREAMS) { 3198a0b5a5dSsethdelliott if (FD_ISSET(test->prot_listener, &temp_read_set)) { 3208a0b5a5dSsethdelliott 32166ce7ad4Ssethdelliott if ((s = test->protocol->accept(test)) < 0) 322b60a49ddSsethdelliott return (-1); 3238a0b5a5dSsethdelliott 3248a0b5a5dSsethdelliott if (!is_closed(s)) { 32566ce7ad4Ssethdelliott sp = iperf_new_stream(test, s); 3268a0b5a5dSsethdelliott if (!sp) 327b60a49ddSsethdelliott return (-1); 32866ce7ad4Ssethdelliott 3298a0b5a5dSsethdelliott FD_SET(s, &test->read_set); 3308a0b5a5dSsethdelliott FD_SET(s, &test->write_set); 3318a0b5a5dSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 33266ce7ad4Ssethdelliott 333112a907cSsethdelliott streams_accepted++; 3344df383f6Ssethdelliott if (test->on_new_stream) 3354df383f6Ssethdelliott test->on_new_stream(sp); 336b68ac00eSsethdelliott } 3378a0b5a5dSsethdelliott FD_CLR(test->prot_listener, &temp_read_set); 338b68ac00eSsethdelliott } 3398a0b5a5dSsethdelliott 340112a907cSsethdelliott if (streams_accepted == test->num_streams) { 34166ce7ad4Ssethdelliott if (test->protocol->id != Ptcp) { 3428a0b5a5dSsethdelliott FD_CLR(test->prot_listener, &test->read_set); 3438a0b5a5dSsethdelliott close(test->prot_listener); 34466ce7ad4Ssethdelliott } else { 345112a907cSsethdelliott if (test->no_delay || test->settings->mss) { 34666ce7ad4Ssethdelliott FD_CLR(test->listener, &test->read_set); 34766ce7ad4Ssethdelliott close(test->listener); 348*f99bd3b2Ssethdelliott if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { 349b60a49ddSsethdelliott i_errno = IELISTEN; 350c81883bfSsethdelliott return (-1); 351c81883bfSsethdelliott } 35266ce7ad4Ssethdelliott test->listener = s; 353c81883bfSsethdelliott test->max_fd = (s > test->max_fd ? s : test->max_fd); 35466ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set); 355c81883bfSsethdelliott } 3568556db5dSsethdelliott } 3578a0b5a5dSsethdelliott test->prot_listener = -1; 358465b565cSsethdelliott test->state = TEST_START; 359b68ac00eSsethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 360b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 361b60a49ddSsethdelliott return (-1); 362982c704aSsethdelliott } 363b60a49ddSsethdelliott if (iperf_init_test(test) < 0) 364b60a49ddSsethdelliott return (-1); 365f1b3bd81Ssethdelliott test->state = TEST_RUNNING; 366f1b3bd81Ssethdelliott if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 367b60a49ddSsethdelliott i_errno = IESENDMESSAGE; 368b60a49ddSsethdelliott return (-1); 369f1b3bd81Ssethdelliott } 370982c704aSsethdelliott } 371982c704aSsethdelliott } 372982c704aSsethdelliott 373f1b3bd81Ssethdelliott if (test->state == TEST_RUNNING) { 374465b565cSsethdelliott if (test->reverse) { 375465b565cSsethdelliott // Reverse mode. Server sends. 376b60a49ddSsethdelliott if (iperf_send(test) < 0) 377b60a49ddSsethdelliott return (-1); 378982c704aSsethdelliott } else { 379465b565cSsethdelliott // Regular mode. Server receives. 380b60a49ddSsethdelliott if (iperf_recv(test) < 0) 381b60a49ddSsethdelliott return (-1); 382e99faeaeSBrian Tierney } 383f1b3bd81Ssethdelliott 384f1b3bd81Ssethdelliott /* Perform callbacks */ 385f1b3bd81Ssethdelliott if (timer_expired(test->stats_timer)) { 386f1b3bd81Ssethdelliott test->stats_callback(test); 387b60a49ddSsethdelliott if (update_timer(test->stats_timer, test->stats_interval, 0) < 0) 388b60a49ddSsethdelliott return (-1); 389f1b3bd81Ssethdelliott } 390f1b3bd81Ssethdelliott if (timer_expired(test->reporter_timer)) { 391f1b3bd81Ssethdelliott test->reporter_callback(test); 392b60a49ddSsethdelliott if (update_timer(test->reporter_timer, test->reporter_interval, 0) < 0) 393b60a49ddSsethdelliott return (-1); 394f1b3bd81Ssethdelliott } 395f1b3bd81Ssethdelliott } 396a951c980SBrian Tierney } 397982c704aSsethdelliott } 398e99faeaeSBrian Tierney 399efdc02f7Ssethdelliott /* Clean up the last test */ 400efdc02f7Ssethdelliott iperf_test_reset(test); 401efdc02f7Ssethdelliott printf("\n"); 402efdc02f7Ssethdelliott 403efdc02f7Ssethdelliott } 404efdc02f7Ssethdelliott 405b60a49ddSsethdelliott return (0); 406a3281a3dSBrian Tierney } 407a3281a3dSBrian Tierney 408