1 /* 2 * Copyright (c) 2009-2011, The Regents of the University of California, 3 * through Lawrence Berkeley National Laboratory (subject to receipt of any 4 * required approvals from the U.S. Dept. of Energy). All rights reserved. 5 * 6 * This code is distributed under a BSD style license, see the LICENSE file 7 * for complete information. 8 */ 9 10 /* iperf_server_api.c: Functions to be used by an iperf server 11 */ 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <getopt.h> 17 #include <errno.h> 18 #include <unistd.h> 19 #include <assert.h> 20 #include <fcntl.h> 21 #include <sys/socket.h> 22 #include <sys/types.h> 23 #include <netinet/in.h> 24 #include <arpa/inet.h> 25 #include <netdb.h> 26 #include <pthread.h> 27 #include <stdint.h> 28 #include <netinet/tcp.h> 29 #include <sys/time.h> 30 #include <sys/resource.h> 31 #include <sched.h> 32 #include <setjmp.h> 33 34 #include "iperf.h" 35 #include "iperf_server_api.h" 36 #include "iperf_api.h" 37 #include "iperf_udp.h" 38 #include "iperf_tcp.h" 39 #include "iperf_error.h" 40 #include "iperf_util.h" 41 #include "timer.h" 42 #include "net.h" 43 #include "units.h" 44 #include "tcp_window_size.h" 45 #include "iperf_util.h" 46 #include "locale.h" 47 48 49 int 50 iperf_server_listen(struct iperf_test *test) 51 { 52 char ubuf[UNIT_LEN]; 53 int x; 54 55 if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { 56 i_errno = IELISTEN; 57 return (-1); 58 } 59 60 printf("-----------------------------------------------------------\n"); 61 printf("Server listening on %d\n", test->server_port); 62 63 // This needs to be changed to reflect if client has different window size 64 // make sure we got what we asked for 65 /* XXX: This needs to be moved to the stream listener 66 if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) { 67 // Needs to set some sort of error number/message 68 perror("SO_RCVBUF"); 69 return -1; 70 } 71 */ 72 73 // XXX: This code needs to be moved to after parameter exhange 74 /* 75 if (test->protocol->id == Ptcp) { 76 if (test->settings->socket_bufsize > 0) { 77 unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A'); 78 printf("TCP window size: %s\n", ubuf); 79 } else { 80 printf("Using TCP Autotuning\n"); 81 } 82 } 83 */ 84 printf("-----------------------------------------------------------\n"); 85 86 FD_ZERO(&test->read_set); 87 FD_ZERO(&test->write_set); 88 FD_SET(test->listener, &test->read_set); 89 test->max_fd = (test->listener > test->max_fd) ? test->listener : test->max_fd; 90 91 return 0; 92 } 93 94 int 95 iperf_accept(struct iperf_test *test) 96 { 97 int s; 98 int rbuf = ACCESS_DENIED; 99 char cookie[COOKIE_SIZE]; 100 socklen_t len; 101 struct sockaddr_in addr; 102 103 len = sizeof(addr); 104 if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { 105 i_errno = IEACCEPT; 106 return (-1); 107 } 108 109 if (test->ctrl_sck == -1) { 110 /* Server free, accept new client */ 111 if (Nread(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { 112 i_errno = IERECVCOOKIE; 113 return (-1); 114 } 115 116 FD_SET(s, &test->read_set); 117 FD_SET(s, &test->write_set); 118 test->max_fd = (s > test->max_fd) ? s : test->max_fd; 119 test->ctrl_sck = s; 120 121 test->state = PARAM_EXCHANGE; 122 if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 123 i_errno = IESENDMESSAGE; 124 return (-1); 125 } 126 if (iperf_exchange_parameters(test) < 0) { 127 return (-1); 128 } 129 if (test->on_connect) { 130 test->on_connect(test); 131 } 132 } else { 133 // XXX: Do we even need to receive cookie if we're just going to deny anyways? 134 if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { 135 i_errno = IERECVCOOKIE; 136 return (-1); 137 } 138 if (Nwrite(s, &rbuf, sizeof(int), Ptcp) < 0) { 139 i_errno = IESENDMESSAGE; 140 return (-1); 141 } 142 close(s); 143 } 144 145 return (0); 146 } 147 148 149 /**************************************************************************/ 150 int 151 iperf_handle_message_server(struct iperf_test *test) 152 { 153 int rval; 154 struct iperf_stream *sp; 155 156 // XXX: Need to rethink how this behaves to fit API 157 if ((rval = Nread(test->ctrl_sck, &test->state, sizeof(char), Ptcp)) <= 0) { 158 if (rval == 0) { 159 fprintf(stderr, "The client has unexpectedly closed the connection.\n"); 160 i_errno = IECTRLCLOSE; 161 test->state = IPERF_DONE; 162 return (0); 163 } else { 164 i_errno = IERECVMESSAGE; 165 return (-1); 166 } 167 } 168 169 switch(test->state) { 170 case TEST_START: 171 break; 172 case TEST_END: 173 cpu_util(&test->cpu_util); 174 test->stats_callback(test); 175 SLIST_FOREACH(sp, &test->streams, streams) { 176 FD_CLR(sp->socket, &test->read_set); 177 FD_CLR(sp->socket, &test->write_set); 178 close(sp->socket); 179 } 180 test->state = EXCHANGE_RESULTS; 181 if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 182 i_errno = IESENDMESSAGE; 183 return (-1); 184 } 185 if (iperf_exchange_results(test) < 0) 186 return (-1); 187 test->state = DISPLAY_RESULTS; 188 if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 189 i_errno = IESENDMESSAGE; 190 return (-1); 191 } 192 if (test->on_test_finish) 193 test->on_test_finish(test); 194 test->reporter_callback(test); 195 break; 196 case IPERF_DONE: 197 break; 198 case CLIENT_TERMINATE: 199 i_errno = IECLIENTTERM; 200 201 // XXX: Remove this line below! 202 fprintf(stderr, "The client has terminated.\n"); 203 SLIST_FOREACH(sp, &test->streams, streams) { 204 FD_CLR(sp->socket, &test->read_set); 205 FD_CLR(sp->socket, &test->write_set); 206 close(sp->socket); 207 } 208 test->state = IPERF_DONE; 209 break; 210 default: 211 i_errno = IEMESSAGE; 212 return (-1); 213 } 214 215 return (0); 216 } 217 218 /* XXX: This function is not used anymore */ 219 void 220 iperf_test_reset(struct iperf_test *test) 221 { 222 struct iperf_stream *sp; 223 224 close(test->ctrl_sck); 225 226 /* Free streams */ 227 while (!SLIST_EMPTY(&test->streams)) { 228 sp = SLIST_FIRST(&test->streams); 229 SLIST_REMOVE_HEAD(&test->streams, streams); 230 iperf_free_stream(sp); 231 } 232 free_timer(test->timer); 233 free_timer(test->stats_timer); 234 free_timer(test->reporter_timer); 235 test->timer = NULL; 236 test->stats_timer = NULL; 237 test->reporter_timer = NULL; 238 239 SLIST_INIT(&test->streams); 240 241 test->role = 's'; 242 set_protocol(test, Ptcp); 243 test->duration = DURATION; 244 test->state = 0; 245 test->server_hostname = NULL; 246 247 test->ctrl_sck = -1; 248 test->prot_listener = -1; 249 250 test->bytes_sent = 0; 251 252 test->reverse = 0; 253 test->no_delay = 0; 254 255 FD_ZERO(&test->read_set); 256 FD_ZERO(&test->write_set); 257 FD_SET(test->listener, &test->read_set); 258 test->max_fd = test->listener; 259 260 test->num_streams = 1; 261 test->settings->socket_bufsize = 0; 262 test->settings->blksize = DEFAULT_TCP_BLKSIZE; 263 test->settings->rate = RATE; /* UDP only */ 264 test->settings->mss = 0; 265 memset(test->cookie, 0, COOKIE_SIZE); 266 } 267 268 int 269 iperf_run_server(struct iperf_test *test) 270 { 271 int result, s, streams_accepted; 272 fd_set temp_read_set, temp_write_set; 273 struct iperf_stream *sp; 274 struct timeval tv; 275 time_t sec, usec; 276 277 // Open socket and listen 278 if (iperf_server_listen(test) < 0) { 279 return (-1); 280 } 281 282 // Begin calculating CPU utilization 283 cpu_util(NULL); 284 285 test->state = IPERF_START; 286 streams_accepted = 0; 287 288 while (test->state != IPERF_DONE) { 289 290 memcpy(&temp_read_set, &test->read_set, sizeof(fd_set)); 291 memcpy(&temp_write_set, &test->write_set, sizeof(fd_set)); 292 tv.tv_sec = 15; 293 tv.tv_usec = 0; 294 295 result = select(test->max_fd + 1, &temp_read_set, &temp_write_set, NULL, &tv); 296 if (result < 0 && errno != EINTR) { 297 i_errno = IESELECT; 298 return (-1); 299 } else if (result > 0) { 300 if (FD_ISSET(test->listener, &temp_read_set)) { 301 if (test->state != CREATE_STREAMS) { 302 if (iperf_accept(test) < 0) { 303 return (-1); 304 } 305 FD_CLR(test->listener, &temp_read_set); 306 } 307 } 308 if (FD_ISSET(test->ctrl_sck, &temp_read_set)) { 309 if (iperf_handle_message_server(test) < 0) 310 return (-1); 311 FD_CLR(test->ctrl_sck, &temp_read_set); 312 } 313 314 if (test->state == CREATE_STREAMS) { 315 if (FD_ISSET(test->prot_listener, &temp_read_set)) { 316 317 if ((s = test->protocol->accept(test)) < 0) 318 return (-1); 319 320 if (!is_closed(s)) { 321 sp = iperf_new_stream(test, s); 322 if (!sp) 323 return (-1); 324 325 FD_SET(s, &test->read_set); 326 FD_SET(s, &test->write_set); 327 test->max_fd = (s > test->max_fd) ? s : test->max_fd; 328 329 streams_accepted++; 330 if (test->on_new_stream) 331 test->on_new_stream(sp); 332 } 333 FD_CLR(test->prot_listener, &temp_read_set); 334 } 335 336 if (streams_accepted == test->num_streams) { 337 if (test->protocol->id != Ptcp) { 338 FD_CLR(test->prot_listener, &test->read_set); 339 close(test->prot_listener); 340 } else { 341 if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) { 342 FD_CLR(test->listener, &test->read_set); 343 close(test->listener); 344 if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) { 345 i_errno = IELISTEN; 346 return (-1); 347 } 348 test->listener = s; 349 test->max_fd = (s > test->max_fd ? s : test->max_fd); 350 FD_SET(test->listener, &test->read_set); 351 } 352 } 353 test->prot_listener = -1; 354 test->state = TEST_START; 355 if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 356 i_errno = IESENDMESSAGE; 357 return (-1); 358 } 359 if (iperf_init_test(test) < 0) 360 return (-1); 361 test->state = TEST_RUNNING; 362 if (Nwrite(test->ctrl_sck, &test->state, sizeof(char), Ptcp) < 0) { 363 i_errno = IESENDMESSAGE; 364 return (-1); 365 } 366 } 367 } 368 369 if (test->state == TEST_RUNNING) { 370 if (test->reverse) { 371 // Reverse mode. Server sends. 372 if (iperf_send(test) < 0) 373 return (-1); 374 } else { 375 // Regular mode. Server receives. 376 if (iperf_recv(test) < 0) 377 return (-1); 378 } 379 380 /* Perform callbacks */ 381 if (timer_expired(test->stats_timer)) { 382 test->stats_callback(test); 383 sec = (time_t) test->stats_interval; 384 usec = (test->stats_interval - sec) * SEC_TO_US; 385 if (update_timer(test->stats_timer, sec, usec) < 0) 386 return (-1); 387 } 388 if (timer_expired(test->reporter_timer)) { 389 test->reporter_callback(test); 390 sec = (time_t) test->reporter_interval; 391 usec = (test->reporter_interval - sec) * SEC_TO_US; 392 if (update_timer(test->reporter_timer, sec, usec) < 0) 393 return (-1); 394 } 395 } 396 } 397 } 398 399 /* Close open test sockets */ 400 close(test->ctrl_sck); 401 close(test->listener); 402 403 return (0); 404 } 405 406