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> 20a951c980SBrian Tierney #include <sys/socket.h> 21a951c980SBrian Tierney #include <sys/types.h> 22a951c980SBrian Tierney #include <netinet/in.h> 23a951c980SBrian Tierney #include <arpa/inet.h> 24a951c980SBrian Tierney #include <netdb.h> 25a951c980SBrian Tierney #include <pthread.h> 26a951c980SBrian Tierney #include <stdint.h> 27a951c980SBrian Tierney #include <netinet/tcp.h> 28a951c980SBrian Tierney #include <sys/time.h> 29a951c980SBrian Tierney #include <sys/resource.h> 30a951c980SBrian Tierney #include <sched.h> 31a951c980SBrian Tierney #include <signal.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" 39a951c980SBrian Tierney #include "timer.h" 40a951c980SBrian Tierney #include "net.h" 41a951c980SBrian Tierney #include "units.h" 42a951c980SBrian Tierney #include "tcp_window_size.h" 43a951c980SBrian Tierney #include "uuid.h" 44a951c980SBrian Tierney #include "locale.h" 45a951c980SBrian Tierney 46a951c980SBrian Tierney /*********************************************************************/ 47a951c980SBrian Tierney /** 48a951c980SBrian Tierney * param_received - handles the param_Exchange part for server 49a951c980SBrian Tierney * returns state on success, -1 on failure 50a951c980SBrian Tierney * 51a951c980SBrian Tierney */ 52a951c980SBrian Tierney 53a951c980SBrian Tierney int 54a951c980SBrian Tierney param_received(struct iperf_stream * sp, struct param_exchange * param) 55a951c980SBrian Tierney { 56a951c980SBrian Tierney int result; 57a951c980SBrian Tierney char *buf = (char *) malloc(sizeof(struct param_exchange)); 58a951c980SBrian Tierney 59a951c980SBrian Tierney if (sp->settings->cookie[0] == '\0' || 608f4e66c9SBrian Tierney (strncmp(param->cookie, sp->settings->cookie, COOKIE_SIZE) == 0)) 61a951c980SBrian Tierney { 628f4e66c9SBrian Tierney strncpy(sp->settings->cookie, param->cookie, COOKIE_SIZE); 63a951c980SBrian Tierney sp->settings->blksize = param->blksize; 64a951c980SBrian Tierney sp->settings->socket_bufsize = param->recv_window; 65a951c980SBrian Tierney sp->settings->unit_format = param->format; 66a951c980SBrian Tierney printf("Got params from client: block size = %d, recv_window = %d cookie = %s\n", 67a951c980SBrian Tierney sp->settings->blksize, sp->settings->socket_bufsize, sp->settings->cookie); 68a951c980SBrian Tierney param->state = TEST_START; 69a951c980SBrian Tierney buf[0] = TEST_START; 70a951c980SBrian Tierney 71a951c980SBrian Tierney } else 72a951c980SBrian Tierney { 738f4e66c9SBrian Tierney fprintf(stderr, "Connection from new client denied.\n"); 748f4e66c9SBrian Tierney printf("cookie still set to %s \n", sp->settings->cookie); 75a951c980SBrian Tierney param->state = ACCESS_DENIED; 76a951c980SBrian Tierney buf[0] = ACCESS_DENIED; 77a951c980SBrian Tierney } 788f4e66c9SBrian Tierney memcpy(sp->buffer, buf, sizeof(struct param_exchange));; 798f4e66c9SBrian Tierney printf("param_received: Sending message (%d) back to client \n", sp->buffer[0]); 808f4e66c9SBrian Tierney result = Nwrite(sp->socket, sp->buffer, sizeof(struct param_exchange), Ptcp); 81a951c980SBrian Tierney if (result < 0) 82a951c980SBrian Tierney perror("param_received: Error sending param ack to client"); 838f4e66c9SBrian Tierney free(buf); 84a951c980SBrian Tierney return param->state; 85a951c980SBrian Tierney } 86a951c980SBrian Tierney 87a951c980SBrian Tierney /*************************************************************/ 88a951c980SBrian Tierney 89a951c980SBrian Tierney /** 90a951c980SBrian Tierney * send_result_to_client - sends result string from server to client 91a951c980SBrian Tierney */ 92a951c980SBrian Tierney 93a951c980SBrian Tierney void 94a951c980SBrian Tierney send_result_to_client(struct iperf_stream * sp) 95a951c980SBrian Tierney { 96a951c980SBrian Tierney int result; 97a951c980SBrian Tierney int size = sp->settings->blksize; 98a951c980SBrian Tierney 99a951c980SBrian Tierney char *buf = (char *) malloc(size); 100a951c980SBrian Tierney 101a951c980SBrian Tierney if (!buf) 102a951c980SBrian Tierney { 103a951c980SBrian Tierney perror("malloc: unable to allocate transmit buffer"); 104a951c980SBrian Tierney } 105a951c980SBrian Tierney /* adding the string terminator to the message */ 106a951c980SBrian Tierney buf[strlen((char *) sp->data)] = '\0'; 107a951c980SBrian Tierney 108a951c980SBrian Tierney memcpy(buf, sp->data, strlen((char *) sp->data)); 109a951c980SBrian Tierney 110a951c980SBrian Tierney printf("send_result_to_client: sending %d bytes \n", (int) strlen((char *) sp->data)); 111a951c980SBrian Tierney result = send(sp->socket, buf, size, 0); 112a951c980SBrian Tierney printf("RESULT SENT TO CLIENT\n"); 113a951c980SBrian Tierney 114a951c980SBrian Tierney free(buf); 115a951c980SBrian Tierney } 116a951c980SBrian Tierney 117a951c980SBrian Tierney /**************************************************************************/ 118a951c980SBrian Tierney void 119a951c980SBrian Tierney iperf_run_server(struct iperf_test * test) 120a951c980SBrian Tierney { 121a951c980SBrian Tierney struct timeval tv; 122a951c980SBrian Tierney struct iperf_stream *np, *sp; 123*150a09e9SBrian Tierney int j, result=0, message, cnt=0; 124a951c980SBrian Tierney char *results_string = NULL; 125a951c980SBrian Tierney 126c27f38e5SBrian Tierney printf("in iperf_run_server \n"); 127*150a09e9SBrian Tierney 128a951c980SBrian Tierney FD_ZERO(&test->read_set); 129a951c980SBrian Tierney FD_SET(test->listener_sock_tcp, &test->read_set); 130a951c980SBrian Tierney FD_SET(test->listener_sock_udp, &test->read_set); 131a951c980SBrian Tierney 132a951c980SBrian Tierney test->max_fd = test->listener_sock_tcp > test->listener_sock_udp ? test->listener_sock_tcp : test->listener_sock_udp; 1338f4e66c9SBrian Tierney //printf("iperf_run_server: max_fd set to %d \n", test->max_fd); 134a951c980SBrian Tierney 135a951c980SBrian Tierney test->num_streams = 0; 136a951c980SBrian Tierney test->default_settings->state = TEST_RUNNING; 137a951c980SBrian Tierney 138a951c980SBrian Tierney printf("iperf_run_server: Waiting for client connect.... \n"); 139*150a09e9SBrian Tierney 140a951c980SBrian Tierney while (test->default_settings->state != TEST_END) 141a951c980SBrian Tierney { 142a951c980SBrian Tierney memcpy(&test->temp_set, &test->read_set, sizeof(test->read_set)); 143a951c980SBrian Tierney tv.tv_sec = 15; 144a951c980SBrian Tierney tv.tv_usec = 0; 145a951c980SBrian Tierney 146a951c980SBrian Tierney /* using select to check on multiple descriptors. */ 147c27f38e5SBrian Tierney //printf("calling select.. sock = %d \n", test->max_fd + 1); 148a951c980SBrian Tierney result = select(test->max_fd + 1, &test->temp_set, NULL, NULL, &tv); 149a951c980SBrian Tierney if (result == 0) 150a951c980SBrian Tierney { 151a951c980SBrian Tierney //printf("SERVER IDLE : %d sec\n", (int) tv.tv_sec); 152a951c980SBrian Tierney continue; 153a951c980SBrian Tierney } else if (result < 0 && errno != EINTR) 154a951c980SBrian Tierney { 155c27f38e5SBrian Tierney printf("Error in select(): %s, socket = %d\n", strerror(errno), test->max_fd + 1); 156a951c980SBrian Tierney exit(0); 157a951c980SBrian Tierney } else if (result > 0) 158a951c980SBrian Tierney { 159a951c980SBrian Tierney /* Accept a new TCP connection */ 160a951c980SBrian Tierney if (FD_ISSET(test->listener_sock_tcp, &test->temp_set)) 161a951c980SBrian Tierney { 162a951c980SBrian Tierney test->protocol = Ptcp; 163a951c980SBrian Tierney test->accept = iperf_tcp_accept; 164a951c980SBrian Tierney test->new_stream = iperf_new_tcp_stream; 165a951c980SBrian Tierney test->accept(test); 166a951c980SBrian Tierney test->default_settings->state = TEST_RUNNING; 167a951c980SBrian Tierney FD_CLR(test->listener_sock_tcp, &test->temp_set); 168c27f38e5SBrian Tierney printf("iperf_run_server: accepted TCP connection \n"); 169a951c980SBrian Tierney } 170a951c980SBrian Tierney /* Accept a new UDP connection */ 171a951c980SBrian Tierney else if (FD_ISSET(test->listener_sock_udp, &test->temp_set)) 172a951c980SBrian Tierney { 173a951c980SBrian Tierney test->protocol = Pudp; 174a951c980SBrian Tierney test->accept = iperf_udp_accept; 175a951c980SBrian Tierney test->new_stream = iperf_new_udp_stream; 176a951c980SBrian Tierney test->accept(test); 177a951c980SBrian Tierney test->default_settings->state = TEST_RUNNING; 178a951c980SBrian Tierney FD_CLR(test->listener_sock_udp, &test->temp_set); 179a951c980SBrian Tierney } 180a951c980SBrian Tierney /* Process the sockets for read operation */ 1818f4e66c9SBrian Tierney /* XXX: Need to try to read equal amounts from each socket, so keep 1828f4e66c9SBrian Tierney track of last socket read from, and always start with the next 1838f4e66c9SBrian Tierney socket 1848f4e66c9SBrian Tierney */ 185a951c980SBrian Tierney for (j = 0; j < test->max_fd + 1; j++) 186a951c980SBrian Tierney { 187a951c980SBrian Tierney if (FD_ISSET(j, &test->temp_set)) 188a951c980SBrian Tierney { 189a951c980SBrian Tierney /* find the correct stream - possibly time consuming */ 190a951c980SBrian Tierney np = find_stream_by_socket(test, j); 191c27f38e5SBrian Tierney message = np->rcv(np); /* get data from client using 192c27f38e5SBrian Tierney * receiver callback */ 193a951c980SBrian Tierney //printf("iperf_run_server: iperf_tcp_recv returned %d \n", message); 194c27f38e5SBrian Tierney if (message < 0) 195c27f38e5SBrian Tierney { 196c27f38e5SBrian Tierney printf("Error reading data from client \n"); 197c27f38e5SBrian Tierney close(np->socket); 198c27f38e5SBrian Tierney return; 199c27f38e5SBrian Tierney } 200a951c980SBrian Tierney np->settings->state = message; 201a951c980SBrian Tierney 202a951c980SBrian Tierney if (message == PARAM_EXCHANGE) 203a951c980SBrian Tierney { 204a951c980SBrian Tierney /* copy the received settings into test */ 205a951c980SBrian Tierney memcpy(test->default_settings, test->streams->settings, sizeof(struct iperf_settings)); 206a951c980SBrian Tierney } 207c27f38e5SBrian Tierney if (message == ACCESS_DENIED) /* this might get set by 208c27f38e5SBrian Tierney * PARAM_EXCHANGE */ 209a951c980SBrian Tierney { 210a951c980SBrian Tierney /* XXX: test this! */ 211a951c980SBrian Tierney close(np->socket); 2128d41fbd7SBrian Tierney FD_CLR(np->socket, &test->read_set); 213a36921c2SBrian Tierney iperf_free_stream(np); 214a951c980SBrian Tierney } 215a951c980SBrian Tierney if (message == STREAM_END) 216a951c980SBrian Tierney { 217a951c980SBrian Tierney gettimeofday(&np->result->end_time, NULL); 218a951c980SBrian Tierney } 219a951c980SBrian Tierney if (message == RESULT_REQUEST) 220a951c980SBrian Tierney { 221a951c980SBrian Tierney np->settings->state = RESULT_RESPOND; 222a951c980SBrian Tierney results_string = test->reporter_callback(test); 223a951c980SBrian Tierney np->data = results_string; 224a951c980SBrian Tierney send_result_to_client(np); 225a951c980SBrian Tierney } 226a951c980SBrian Tierney if (message == ALL_STREAMS_END) 227a951c980SBrian Tierney { 2288f4e66c9SBrian Tierney printf("client send ALL_STREAMS_END message, printing results \n"); 229a951c980SBrian Tierney /* print server results */ 230a951c980SBrian Tierney results_string = test->reporter_callback(test); 231a951c980SBrian Tierney puts(results_string); /* send to stdio */ 232a951c980SBrian Tierney } 233a951c980SBrian Tierney if (message == TEST_END) 234a951c980SBrian Tierney { 235a951c980SBrian Tierney /* FREE ALL STREAMS */ 236a951c980SBrian Tierney np = test->streams; 237a951c980SBrian Tierney do 238a951c980SBrian Tierney { 239a951c980SBrian Tierney sp = np; 240c27f38e5SBrian Tierney //printf(" closing socket: %d \n", sp->socket); 241a951c980SBrian Tierney close(sp->socket); 242c27f38e5SBrian Tierney FD_CLR(sp->socket, &test->read_set); 243c27f38e5SBrian Tierney np = sp->next; /* get next pointer before 244c27f38e5SBrian Tierney * freeing */ 245a36921c2SBrian Tierney iperf_free_stream(sp); 246a951c980SBrian Tierney } while (np != NULL); 247a951c980SBrian Tierney 248a951c980SBrian Tierney test->default_settings->state = TEST_END; 249c27f38e5SBrian Tierney /* reset cookie when client is finished */ 2508f4e66c9SBrian Tierney printf("got TEST_END message, reseting cookie \n"); 2518f4e66c9SBrian Tierney memset(test->default_settings->cookie, '\0', COOKIE_SIZE); 252c27f38e5SBrian Tierney break; /* always break out of for loop on TEST_END message */ 253a951c980SBrian Tierney } 254a951c980SBrian Tierney } /* end if (FD_ISSET(j, &temp_set)) */ 255a951c980SBrian Tierney } /* end for (j=0;...) */ 256a951c980SBrian Tierney 257a951c980SBrian Tierney } /* end else (result>0) */ 258a951c980SBrian Tierney } /* end while */ 259c27f38e5SBrian Tierney printf("Test Complete. \n\n"); 260c27f38e5SBrian Tierney return; 261a951c980SBrian Tierney 262a951c980SBrian Tierney } 263