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' || 60*8f4e66c9SBrian Tierney (strncmp(param->cookie, sp->settings->cookie, COOKIE_SIZE) == 0)) 61a951c980SBrian Tierney { 62*8f4e66c9SBrian 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 { 73*8f4e66c9SBrian Tierney fprintf(stderr, "Connection from new client denied.\n"); 74*8f4e66c9SBrian 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 } 78*8f4e66c9SBrian Tierney memcpy(sp->buffer, buf, sizeof(struct param_exchange));; 79*8f4e66c9SBrian Tierney printf("param_received: Sending message (%d) back to client \n", sp->buffer[0]); 80*8f4e66c9SBrian 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"); 83*8f4e66c9SBrian 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; 123a951c980SBrian Tierney int j, result, message; 124a951c980SBrian Tierney char *results_string = NULL; 125a951c980SBrian Tierney 126c27f38e5SBrian Tierney printf("in iperf_run_server \n"); 127a951c980SBrian Tierney FD_ZERO(&test->read_set); 128a951c980SBrian Tierney FD_SET(test->listener_sock_tcp, &test->read_set); 129a951c980SBrian Tierney FD_SET(test->listener_sock_udp, &test->read_set); 130a951c980SBrian Tierney 131a951c980SBrian Tierney test->max_fd = test->listener_sock_tcp > test->listener_sock_udp ? test->listener_sock_tcp : test->listener_sock_udp; 132*8f4e66c9SBrian Tierney //printf("iperf_run_server: max_fd set to %d \n", test->max_fd); 133a951c980SBrian Tierney 134a951c980SBrian Tierney test->num_streams = 0; 135a951c980SBrian Tierney test->default_settings->state = TEST_RUNNING; 136a951c980SBrian Tierney 137a951c980SBrian Tierney printf("iperf_run_server: Waiting for client connect.... \n"); 138a951c980SBrian Tierney while (test->default_settings->state != TEST_END) 139a951c980SBrian Tierney { 140a951c980SBrian Tierney memcpy(&test->temp_set, &test->read_set, sizeof(test->read_set)); 141a951c980SBrian Tierney tv.tv_sec = 15; 142a951c980SBrian Tierney tv.tv_usec = 0; 143a951c980SBrian Tierney 144a951c980SBrian Tierney /* using select to check on multiple descriptors. */ 145c27f38e5SBrian Tierney //printf("calling select.. sock = %d \n", test->max_fd + 1); 146a951c980SBrian Tierney result = select(test->max_fd + 1, &test->temp_set, NULL, NULL, &tv); 147a951c980SBrian Tierney if (result == 0) 148a951c980SBrian Tierney { 149a951c980SBrian Tierney //printf("SERVER IDLE : %d sec\n", (int) tv.tv_sec); 150a951c980SBrian Tierney continue; 151a951c980SBrian Tierney } else if (result < 0 && errno != EINTR) 152a951c980SBrian Tierney { 153c27f38e5SBrian Tierney printf("Error in select(): %s, socket = %d\n", strerror(errno), test->max_fd + 1); 154a951c980SBrian Tierney exit(0); 155a951c980SBrian Tierney } else if (result > 0) 156a951c980SBrian Tierney { 157a951c980SBrian Tierney /* Accept a new TCP connection */ 158a951c980SBrian Tierney if (FD_ISSET(test->listener_sock_tcp, &test->temp_set)) 159a951c980SBrian Tierney { 160a951c980SBrian Tierney test->protocol = Ptcp; 161a951c980SBrian Tierney test->accept = iperf_tcp_accept; 162a951c980SBrian Tierney test->new_stream = iperf_new_tcp_stream; 163a951c980SBrian Tierney test->accept(test); 164a951c980SBrian Tierney test->default_settings->state = TEST_RUNNING; 165a951c980SBrian Tierney FD_CLR(test->listener_sock_tcp, &test->temp_set); 166c27f38e5SBrian Tierney printf("iperf_run_server: accepted TCP connection \n"); 167a951c980SBrian Tierney } 168a951c980SBrian Tierney /* Accept a new UDP connection */ 169a951c980SBrian Tierney else if (FD_ISSET(test->listener_sock_udp, &test->temp_set)) 170a951c980SBrian Tierney { 171a951c980SBrian Tierney test->protocol = Pudp; 172a951c980SBrian Tierney test->accept = iperf_udp_accept; 173a951c980SBrian Tierney test->new_stream = iperf_new_udp_stream; 174a951c980SBrian Tierney test->accept(test); 175a951c980SBrian Tierney test->default_settings->state = TEST_RUNNING; 176a951c980SBrian Tierney FD_CLR(test->listener_sock_udp, &test->temp_set); 177a951c980SBrian Tierney } 178a951c980SBrian Tierney /* Process the sockets for read operation */ 179*8f4e66c9SBrian Tierney /* XXX: Need to try to read equal amounts from each socket, so keep 180*8f4e66c9SBrian Tierney track of last socket read from, and always start with the next 181*8f4e66c9SBrian Tierney socket 182*8f4e66c9SBrian Tierney */ 183a951c980SBrian Tierney for (j = 0; j < test->max_fd + 1; j++) 184a951c980SBrian Tierney { 185a951c980SBrian Tierney if (FD_ISSET(j, &test->temp_set)) 186a951c980SBrian Tierney { 187a951c980SBrian Tierney /* find the correct stream - possibly time consuming */ 188a951c980SBrian Tierney np = find_stream_by_socket(test, j); 189c27f38e5SBrian Tierney message = np->rcv(np); /* get data from client using 190c27f38e5SBrian Tierney * receiver callback */ 191a951c980SBrian Tierney //printf("iperf_run_server: iperf_tcp_recv returned %d \n", message); 192c27f38e5SBrian Tierney if (message < 0) 193c27f38e5SBrian Tierney { 194c27f38e5SBrian Tierney printf("Error reading data from client \n"); 195c27f38e5SBrian Tierney close(np->socket); 196c27f38e5SBrian Tierney return; 197c27f38e5SBrian Tierney } 198a951c980SBrian Tierney np->settings->state = message; 199a951c980SBrian Tierney 200a951c980SBrian Tierney if (message == PARAM_EXCHANGE) 201a951c980SBrian Tierney { 202a951c980SBrian Tierney /* copy the received settings into test */ 203a951c980SBrian Tierney memcpy(test->default_settings, test->streams->settings, sizeof(struct iperf_settings)); 204a951c980SBrian Tierney } 205c27f38e5SBrian Tierney if (message == ACCESS_DENIED) /* this might get set by 206c27f38e5SBrian Tierney * PARAM_EXCHANGE */ 207a951c980SBrian Tierney { 208a951c980SBrian Tierney /* XXX: test this! */ 209a951c980SBrian Tierney close(np->socket); 2108d41fbd7SBrian Tierney FD_CLR(np->socket, &test->read_set); 211a36921c2SBrian Tierney iperf_free_stream(np); 212a951c980SBrian Tierney } 213a951c980SBrian Tierney if (message == STREAM_END) 214a951c980SBrian Tierney { 215a951c980SBrian Tierney gettimeofday(&np->result->end_time, NULL); 216a951c980SBrian Tierney } 217a951c980SBrian Tierney if (message == RESULT_REQUEST) 218a951c980SBrian Tierney { 219a951c980SBrian Tierney np->settings->state = RESULT_RESPOND; 220a951c980SBrian Tierney results_string = test->reporter_callback(test); 221a951c980SBrian Tierney np->data = results_string; 222a951c980SBrian Tierney send_result_to_client(np); 223a951c980SBrian Tierney } 224a951c980SBrian Tierney if (message == ALL_STREAMS_END) 225a951c980SBrian Tierney { 226*8f4e66c9SBrian Tierney printf("client send ALL_STREAMS_END message, printing results \n"); 227a951c980SBrian Tierney /* print server results */ 228a951c980SBrian Tierney results_string = test->reporter_callback(test); 229a951c980SBrian Tierney puts(results_string); /* send to stdio */ 230a951c980SBrian Tierney } 231a951c980SBrian Tierney if (message == TEST_END) 232a951c980SBrian Tierney { 233a951c980SBrian Tierney /* FREE ALL STREAMS */ 234a951c980SBrian Tierney np = test->streams; 235a951c980SBrian Tierney do 236a951c980SBrian Tierney { 237a951c980SBrian Tierney sp = np; 238c27f38e5SBrian Tierney //printf(" closing socket: %d \n", sp->socket); 239a951c980SBrian Tierney close(sp->socket); 240c27f38e5SBrian Tierney FD_CLR(sp->socket, &test->read_set); 241c27f38e5SBrian Tierney np = sp->next; /* get next pointer before 242c27f38e5SBrian Tierney * freeing */ 243a36921c2SBrian Tierney iperf_free_stream(sp); 244a951c980SBrian Tierney } while (np != NULL); 245a951c980SBrian Tierney 246a951c980SBrian Tierney test->default_settings->state = TEST_END; 247c27f38e5SBrian Tierney /* reset cookie when client is finished */ 248*8f4e66c9SBrian Tierney printf("got TEST_END message, reseting cookie \n"); 249*8f4e66c9SBrian Tierney memset(test->default_settings->cookie, '\0', COOKIE_SIZE); 250c27f38e5SBrian Tierney break; /* always break out of for loop on TEST_END message */ 251a951c980SBrian Tierney } 252a951c980SBrian Tierney } /* end if (FD_ISSET(j, &temp_set)) */ 253a951c980SBrian Tierney } /* end for (j=0;...) */ 254a951c980SBrian Tierney 255a951c980SBrian Tierney } /* end else (result>0) */ 256a951c980SBrian Tierney } /* end while */ 257c27f38e5SBrian Tierney printf("Test Complete. \n\n"); 258c27f38e5SBrian Tierney return; 259a951c980SBrian Tierney 260a951c980SBrian Tierney } 261