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