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 46a3281a3dSBrian Tierney void handle_message(struct iperf_test * test, int m, struct iperf_stream * sp); 47a3281a3dSBrian Tierney 48a951c980SBrian Tierney /*********************************************************************/ 49a951c980SBrian Tierney /** 50a951c980SBrian Tierney * param_received - handles the param_Exchange part for server 51a951c980SBrian Tierney * returns state on success, -1 on failure 52a951c980SBrian Tierney * 53a951c980SBrian Tierney */ 54a951c980SBrian Tierney 55a951c980SBrian Tierney int 56a951c980SBrian Tierney param_received(struct iperf_stream * sp, struct param_exchange * param) 57a951c980SBrian Tierney { 58a951c980SBrian Tierney int result; 59a951c980SBrian Tierney char *buf = (char *) malloc(sizeof(struct param_exchange)); 60a951c980SBrian Tierney 61a951c980SBrian Tierney if (sp->settings->cookie[0] == '\0' || 628f4e66c9SBrian Tierney (strncmp(param->cookie, sp->settings->cookie, COOKIE_SIZE) == 0)) 63a951c980SBrian Tierney { 648f4e66c9SBrian Tierney strncpy(sp->settings->cookie, param->cookie, COOKIE_SIZE); 65a951c980SBrian Tierney sp->settings->blksize = param->blksize; 66a951c980SBrian Tierney sp->settings->socket_bufsize = param->recv_window; 67a951c980SBrian Tierney sp->settings->unit_format = param->format; 68a951c980SBrian Tierney printf("Got params from client: block size = %d, recv_window = %d cookie = %s\n", 69a951c980SBrian Tierney sp->settings->blksize, sp->settings->socket_bufsize, sp->settings->cookie); 70a951c980SBrian Tierney param->state = TEST_START; 71a951c980SBrian Tierney buf[0] = TEST_START; 72a951c980SBrian Tierney 73a951c980SBrian Tierney } else 74a951c980SBrian Tierney { 758f4e66c9SBrian Tierney fprintf(stderr, "Connection from new client denied.\n"); 768f4e66c9SBrian Tierney printf("cookie still set to %s \n", sp->settings->cookie); 77a951c980SBrian Tierney param->state = ACCESS_DENIED; 78a951c980SBrian Tierney buf[0] = ACCESS_DENIED; 79a951c980SBrian Tierney } 808f4e66c9SBrian Tierney memcpy(sp->buffer, buf, sizeof(struct param_exchange));; 81*97887027SBrian Tierney //printf("param_received: Sending message (%d) back to client \n", sp->buffer[0]); 828f4e66c9SBrian Tierney result = Nwrite(sp->socket, sp->buffer, sizeof(struct param_exchange), Ptcp); 83a951c980SBrian Tierney if (result < 0) 84a951c980SBrian Tierney perror("param_received: Error sending param ack to client"); 858f4e66c9SBrian Tierney free(buf); 86a951c980SBrian Tierney return param->state; 87a951c980SBrian Tierney } 88a951c980SBrian Tierney 89a951c980SBrian Tierney /*************************************************************/ 90a951c980SBrian Tierney 91a951c980SBrian Tierney /** 92a951c980SBrian Tierney * send_result_to_client - sends result string from server to client 93a951c980SBrian Tierney */ 94a951c980SBrian Tierney 95a951c980SBrian Tierney void 96a951c980SBrian Tierney send_result_to_client(struct iperf_stream * sp) 97a951c980SBrian Tierney { 98a951c980SBrian Tierney int result; 99a951c980SBrian Tierney int size = sp->settings->blksize; 100a951c980SBrian Tierney 101a951c980SBrian Tierney char *buf = (char *) malloc(size); 102a951c980SBrian Tierney 103a951c980SBrian Tierney if (!buf) 104a951c980SBrian Tierney { 105a951c980SBrian Tierney perror("malloc: unable to allocate transmit buffer"); 106a951c980SBrian Tierney } 107a951c980SBrian Tierney /* adding the string terminator to the message */ 108a951c980SBrian Tierney buf[strlen((char *) sp->data)] = '\0'; 109a951c980SBrian Tierney 110a951c980SBrian Tierney memcpy(buf, sp->data, strlen((char *) sp->data)); 111a951c980SBrian Tierney 112a951c980SBrian Tierney printf("send_result_to_client: sending %d bytes \n", (int) strlen((char *) sp->data)); 113a951c980SBrian Tierney result = send(sp->socket, buf, size, 0); 114a951c980SBrian Tierney printf("RESULT SENT TO CLIENT\n"); 115a951c980SBrian Tierney 116a951c980SBrian Tierney free(buf); 117a951c980SBrian Tierney } 118a951c980SBrian Tierney 119a951c980SBrian Tierney /**************************************************************************/ 120a951c980SBrian Tierney void 121a951c980SBrian Tierney iperf_run_server(struct iperf_test * test) 122a951c980SBrian Tierney { 123a951c980SBrian Tierney struct timeval tv; 124a3281a3dSBrian Tierney struct iperf_stream *np; 1255083c489SBrian Tierney struct timer *stats_interval, *reporter_interval; 1265083c489SBrian Tierney char *result_string = NULL; 127a3281a3dSBrian Tierney int j = 0, result = 0, message = 0; 128a3281a3dSBrian Tierney int nfd = 0; 129a951c980SBrian Tierney 130*97887027SBrian Tierney //printf("in iperf_run_server \n"); 131150a09e9SBrian Tierney 132a951c980SBrian Tierney FD_ZERO(&test->read_set); 133e99faeaeSBrian Tierney FD_ZERO(&test->temp_set); 134e99faeaeSBrian Tierney if (test->protocol == Ptcp) 135e99faeaeSBrian Tierney { 136e99faeaeSBrian Tierney /* add listener to the master set */ 137a951c980SBrian Tierney FD_SET(test->listener_sock_tcp, &test->read_set); 138e99faeaeSBrian Tierney test->max_fd = test->listener_sock_tcp; 139e99faeaeSBrian Tierney } else 140e99faeaeSBrian Tierney { 141a951c980SBrian Tierney FD_SET(test->listener_sock_udp, &test->read_set); 142e99faeaeSBrian Tierney test->max_fd = test->listener_sock_udp; 143e99faeaeSBrian Tierney } 144a951c980SBrian Tierney 1458f4e66c9SBrian Tierney //printf("iperf_run_server: max_fd set to %d \n", test->max_fd); 146a951c980SBrian Tierney 147a951c980SBrian Tierney test->num_streams = 0; 148a951c980SBrian Tierney test->default_settings->state = TEST_RUNNING; 149a951c980SBrian Tierney 1505083c489SBrian Tierney 151a951c980SBrian Tierney printf("iperf_run_server: Waiting for client connect.... \n"); 152150a09e9SBrian Tierney 153a951c980SBrian Tierney while (test->default_settings->state != TEST_END) 154a951c980SBrian Tierney { 155a951c980SBrian Tierney memcpy(&test->temp_set, &test->read_set, sizeof(test->read_set)); 156a951c980SBrian Tierney tv.tv_sec = 15; 157a951c980SBrian Tierney tv.tv_usec = 0; 158a951c980SBrian Tierney 159a951c980SBrian Tierney /* using select to check on multiple descriptors. */ 160c27f38e5SBrian Tierney //printf("calling select.. sock = %d \n", test->max_fd + 1); 161a951c980SBrian Tierney result = select(test->max_fd + 1, &test->temp_set, NULL, NULL, &tv); 162a951c980SBrian Tierney if (result == 0) 163a951c980SBrian Tierney { 164a951c980SBrian Tierney //printf("SERVER IDLE : %d sec\n", (int) tv.tv_sec); 165a951c980SBrian Tierney continue; 166a951c980SBrian Tierney } else if (result < 0 && errno != EINTR) 167a951c980SBrian Tierney { 168c27f38e5SBrian Tierney printf("Error in select(): %s, socket = %d\n", strerror(errno), test->max_fd + 1); 169a951c980SBrian Tierney exit(0); 170a951c980SBrian Tierney } else if (result > 0) 171a951c980SBrian Tierney { 172e99faeaeSBrian Tierney if (test->protocol == Ptcp) 173e99faeaeSBrian Tierney { 174a951c980SBrian Tierney /* Accept a new TCP connection */ 175a951c980SBrian Tierney if (FD_ISSET(test->listener_sock_tcp, &test->temp_set)) 176a951c980SBrian Tierney { 177a951c980SBrian Tierney test->protocol = Ptcp; 178a951c980SBrian Tierney test->accept = iperf_tcp_accept; 179a3281a3dSBrian Tierney if (test->accept < 0) 180a3281a3dSBrian Tierney return; 181a951c980SBrian Tierney test->new_stream = iperf_new_tcp_stream; 182a951c980SBrian Tierney test->accept(test); 183a951c980SBrian Tierney test->default_settings->state = TEST_RUNNING; 184a951c980SBrian Tierney FD_CLR(test->listener_sock_tcp, &test->temp_set); 185c27f38e5SBrian Tierney printf("iperf_run_server: accepted TCP connection \n"); 186d44c04d4SBrian Tierney test->num_streams++; 187a951c980SBrian Tierney } 188e99faeaeSBrian Tierney } else 189e99faeaeSBrian Tierney { 190a951c980SBrian Tierney /* Accept a new UDP connection */ 191e99faeaeSBrian Tierney if (FD_ISSET(test->listener_sock_udp, &test->temp_set)) 192a951c980SBrian Tierney { 193a951c980SBrian Tierney test->protocol = Pudp; 194a951c980SBrian Tierney test->accept = iperf_udp_accept; 195a3281a3dSBrian Tierney if (test->accept < 0) 196a3281a3dSBrian Tierney return; 197a951c980SBrian Tierney test->new_stream = iperf_new_udp_stream; 198a951c980SBrian Tierney test->accept(test); 199a951c980SBrian Tierney test->default_settings->state = TEST_RUNNING; 200a951c980SBrian Tierney FD_CLR(test->listener_sock_udp, &test->temp_set); 201e99faeaeSBrian Tierney printf("iperf_run_server: accepted UDP connection \n"); 202e99faeaeSBrian Tierney } 203a951c980SBrian Tierney } 204a951c980SBrian Tierney /* Process the sockets for read operation */ 205a3281a3dSBrian Tierney nfd = test->max_fd + 1; 206a3281a3dSBrian Tierney for (j = 0; j <= test->max_fd; j++) 207a951c980SBrian Tierney { 208a3281a3dSBrian Tierney //printf("Checking socket %d \n", j); 209a951c980SBrian Tierney if (FD_ISSET(j, &test->temp_set)) 210a951c980SBrian Tierney { 211a3281a3dSBrian Tierney //printf("iperf_run_server: data ready on socket %d \n", j); 212e99faeaeSBrian Tierney /* find the correct stream - possibly time consuming? */ 213a951c980SBrian Tierney np = find_stream_by_socket(test, j); 214c27f38e5SBrian Tierney message = np->rcv(np); /* get data from client using 215c27f38e5SBrian Tierney * receiver callback */ 216a3281a3dSBrian Tierney if (message < 0) 217a3281a3dSBrian Tierney goto done; 218a3281a3dSBrian Tierney handle_message(test, message, np); 219a3281a3dSBrian Tierney if (message == TEST_END) 220a3281a3dSBrian Tierney break; /* test done, so break out of loop */ 221e99faeaeSBrian Tierney 222a3281a3dSBrian Tierney } /* end if (FD_ISSET(j, &temp_set)) */ 223a3281a3dSBrian Tierney } /* end for (j=0;...) */ 2245083c489SBrian Tierney 225*97887027SBrian Tierney if (message == PARAM_EXCHANGE) 226*97887027SBrian Tierney { 227*97887027SBrian Tierney /* start timer at end of PARAM_EXCHANGE */ 228*97887027SBrian Tierney if (test->stats_interval != 0) 229*97887027SBrian Tierney stats_interval = new_timer(test->stats_interval, 0); 230*97887027SBrian Tierney if (test->reporter_interval != 0) 231*97887027SBrian Tierney reporter_interval = new_timer(test->reporter_interval, 0); 232*97887027SBrian Tierney } 233*97887027SBrian Tierney if ((message == STREAM_BEGIN) || (message == STREAM_RUNNING)) 234*97887027SBrian Tierney { 235*97887027SBrian Tierney /* 236*97887027SBrian Tierney * XXX: is this right? Might there be cases where we want 237*97887027SBrian Tierney * stats for while in another state? 238*97887027SBrian Tierney */ 2395083c489SBrian Tierney if ((test->stats_interval != 0) && stats_interval->expired(stats_interval)) 2405083c489SBrian Tierney { 2415083c489SBrian Tierney test->stats_callback(test); 2425083c489SBrian Tierney update_timer(stats_interval, test->stats_interval, 0); 2435083c489SBrian Tierney } 2445083c489SBrian Tierney if ((test->reporter_interval != 0) && reporter_interval->expired(reporter_interval)) 2455083c489SBrian Tierney { 2465083c489SBrian Tierney result_string = test->reporter_callback(test); 2475083c489SBrian Tierney //printf("interval expired: printing results: \n"); 2485083c489SBrian Tierney puts(result_string); 2495083c489SBrian Tierney update_timer(reporter_interval, test->reporter_interval, 0); 2505083c489SBrian Tierney } 251*97887027SBrian Tierney } 252*97887027SBrian Tierney } /* end else (result>0) */ 253a3281a3dSBrian Tierney } /* end while */ 254a3281a3dSBrian Tierney 255a3281a3dSBrian Tierney done: 256a3281a3dSBrian Tierney printf("Test Complete. \n\n"); 2575083c489SBrian Tierney 258a3281a3dSBrian Tierney /* reset cookie when client is finished */ 259a3281a3dSBrian Tierney memset(test->streams->settings->cookie, '\0', COOKIE_SIZE); 260a3281a3dSBrian Tierney return; 261a3281a3dSBrian Tierney } 262a3281a3dSBrian Tierney 263a3281a3dSBrian Tierney /********************************************************/ 264a3281a3dSBrian Tierney 265a3281a3dSBrian Tierney void 266a3281a3dSBrian Tierney handle_message(struct iperf_test * test, int message, struct iperf_stream * sp) 267a3281a3dSBrian Tierney { 268a3281a3dSBrian Tierney char *results_string = NULL; 269a3281a3dSBrian Tierney struct iperf_stream *tp1 = NULL; 270a3281a3dSBrian Tierney struct iperf_stream *tp2 = NULL; 271a3281a3dSBrian Tierney 272a3281a3dSBrian Tierney //printf("handle_message: %d \n", message); 273c27f38e5SBrian Tierney if (message < 0) 274c27f38e5SBrian Tierney { 275c27f38e5SBrian Tierney printf("Error reading data from client \n"); 276a3281a3dSBrian Tierney close(sp->socket); 277c27f38e5SBrian Tierney return; 278c27f38e5SBrian Tierney } 279a3281a3dSBrian Tierney sp->settings->state = message; 280a951c980SBrian Tierney 281a951c980SBrian Tierney if (message == PARAM_EXCHANGE) 282a951c980SBrian Tierney { 283a951c980SBrian Tierney /* copy the received settings into test */ 284a951c980SBrian Tierney memcpy(test->default_settings, test->streams->settings, sizeof(struct iperf_settings)); 285a951c980SBrian Tierney } 286c27f38e5SBrian Tierney if (message == ACCESS_DENIED) /* this might get set by 287c27f38e5SBrian Tierney * PARAM_EXCHANGE */ 288a951c980SBrian Tierney { 289a951c980SBrian Tierney /* XXX: test this! */ 290a3281a3dSBrian Tierney close(sp->socket); 291a3281a3dSBrian Tierney FD_CLR(sp->socket, &test->read_set); 292a3281a3dSBrian Tierney iperf_free_stream(sp); 293a951c980SBrian Tierney } 294a951c980SBrian Tierney if (message == STREAM_END) 295a951c980SBrian Tierney { 296a3281a3dSBrian Tierney /* get final timestamp for all streams */ 297a3281a3dSBrian Tierney tp1 = test->streams; 298a3281a3dSBrian Tierney do 299a3281a3dSBrian Tierney { 300a3281a3dSBrian Tierney gettimeofday(&tp1->result->end_time, NULL); 301a3281a3dSBrian Tierney tp1 = tp1->next; 302a3281a3dSBrian Tierney } while (tp1 != NULL); 303a951c980SBrian Tierney } 304a951c980SBrian Tierney if (message == RESULT_REQUEST) 305a951c980SBrian Tierney { 306a3281a3dSBrian Tierney sp->settings->state = RESULT_RESPOND; 307a951c980SBrian Tierney results_string = test->reporter_callback(test); 308a3281a3dSBrian Tierney sp->data = results_string; 309a3281a3dSBrian Tierney send_result_to_client(sp); 310a951c980SBrian Tierney } 311a951c980SBrian Tierney if (message == ALL_STREAMS_END) 312a951c980SBrian Tierney { 313a3281a3dSBrian Tierney printf("client sent ALL_STREAMS_END message, printing results \n"); 314a951c980SBrian Tierney /* print server results */ 315a951c980SBrian Tierney results_string = test->reporter_callback(test); 316a951c980SBrian Tierney puts(results_string); /* send to stdio */ 317a951c980SBrian Tierney } 318a951c980SBrian Tierney if (message == TEST_END) 319a951c980SBrian Tierney { 320a3281a3dSBrian Tierney printf("client sent TEST_END message, shuting down sockets.. \n"); 321a951c980SBrian Tierney /* FREE ALL STREAMS */ 322a3281a3dSBrian Tierney tp1 = test->streams; 323a951c980SBrian Tierney do 324a951c980SBrian Tierney { 325a3281a3dSBrian Tierney tp2 = tp1; 3265083c489SBrian Tierney //printf(" closing socket: %d \n", tp2->socket); 327a3281a3dSBrian Tierney close(tp2->socket); 328a3281a3dSBrian Tierney FD_CLR(tp2->socket, &test->read_set); 329a3281a3dSBrian Tierney tp1 = tp2->next; /* get next pointer before freeing */ 330a3281a3dSBrian Tierney iperf_free_stream(tp2); 331a3281a3dSBrian Tierney } while (tp1 != NULL); 332a951c980SBrian Tierney 333a951c980SBrian Tierney test->default_settings->state = TEST_END; 3348f4e66c9SBrian Tierney memset(test->default_settings->cookie, '\0', COOKIE_SIZE); 335a951c980SBrian Tierney } 336a951c980SBrian Tierney } 3375083c489SBrian Tierney 3385083c489SBrian Tierney /**************************************************************************/ 3395083c489SBrian Tierney 3405083c489SBrian Tierney /** 3415083c489SBrian Tierney * find_stream_by_socket -- finds the stream based on socket ID 3425083c489SBrian Tierney * simple sequential scan: not more effiecient, but should be fine 3435083c489SBrian Tierney * for a small number of streams. 3445083c489SBrian Tierney * 3455083c489SBrian Tierney *returns stream 3465083c489SBrian Tierney * 3475083c489SBrian Tierney */ 3485083c489SBrian Tierney 3495083c489SBrian Tierney struct iperf_stream * 3505083c489SBrian Tierney find_stream_by_socket(struct iperf_test * test, int sock) 3515083c489SBrian Tierney { 3525083c489SBrian Tierney struct iperf_stream *n; 3535083c489SBrian Tierney 3545083c489SBrian Tierney n = test->streams; 3555083c489SBrian Tierney while (1) 3565083c489SBrian Tierney { 3575083c489SBrian Tierney if (n->socket == sock) 3585083c489SBrian Tierney break; 3595083c489SBrian Tierney if (n->next == NULL) 3605083c489SBrian Tierney break; 3615083c489SBrian Tierney 3625083c489SBrian Tierney n = n->next; 3635083c489SBrian Tierney } 3645083c489SBrian Tierney return n; 3655083c489SBrian Tierney } 366