xref: /iperf/src/iperf_server_api.c (revision ba7b91d2)
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_api.h"
36 #include "iperf_udp.h"
37 #include "iperf_tcp.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     retry:
51     if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
52 	if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) {
53 	    /* If we get "Address family not supported by protocol", that
54 	    ** probably means we were compiled with IPv6 but the running
55 	    ** kernel does not actually do IPv6.  This is not too unusual,
56 	    ** v6 support is and perhaps always will be spotty.
57 	    */
58 	    warning("this system does not seem to support IPv6 - trying IPv4");
59 	    test->settings->domain = AF_INET;
60 	    goto retry;
61 	} else {
62 	    i_errno = IELISTEN;
63 	    return -1;
64 	}
65     }
66 
67     if (!test->json_output) {
68 	printf("-----------------------------------------------------------\n");
69 	printf("Server listening on %d\n", test->server_port);
70     }
71 
72     // This needs to be changed to reflect if client has different window size
73     // make sure we got what we asked for
74     /* XXX: This needs to be moved to the stream listener
75     if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) {
76         // Needs to set some sort of error number/message
77         perror("SO_RCVBUF");
78         return -1;
79     }
80     */
81 
82     // XXX: This code needs to be moved to after parameter exhange
83     /*
84     char ubuf[UNIT_LEN];
85     int x;
86 
87     if (test->protocol->id == Ptcp) {
88         if (test->settings->socket_bufsize > 0) {
89             unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A');
90 	    if (!test->json_output)
91 		iprintf(test, report_window, ubuf);
92         } else {
93 	    if (!test->json_output)
94 		iprintf(test, "%s", report_autotune);
95         }
96     }
97     */
98     if (!test->json_output)
99 	iprintf(test, "-----------------------------------------------------------\n");
100 
101     FD_ZERO(&test->read_set);
102     FD_ZERO(&test->write_set);
103     FD_SET(test->listener, &test->read_set);
104     if (test->listener > test->max_fd) test->max_fd = test->listener;
105 
106     return 0;
107 }
108 
109 int
110 iperf_accept(struct iperf_test *test)
111 {
112     int s;
113     signed char rbuf = ACCESS_DENIED;
114     char cookie[COOKIE_SIZE];
115     socklen_t len;
116     struct sockaddr_storage addr;
117 
118     len = sizeof(addr);
119     if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
120         i_errno = IEACCEPT;
121         return -1;
122     }
123 
124     if (test->ctrl_sck == -1) {
125         /* Server free, accept new client */
126         test->ctrl_sck = s;
127         if (Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
128             i_errno = IERECVCOOKIE;
129             return -1;
130         }
131 	FD_SET(test->ctrl_sck, &test->read_set);
132 	if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;
133 
134 	if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0)
135             return -1;
136         if (iperf_exchange_parameters(test) < 0)
137             return -1;
138 	if (test->server_affinity != -1)
139 	    if (iperf_setaffinity(test->server_affinity) != 0)
140 		return -1;
141         if (test->on_connect)
142             test->on_connect(test);
143     } else {
144         /* XXX: Do we even need to receive cookie if we're just going to deny anyways? */
145         if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
146             i_errno = IERECVCOOKIE;
147             return -1;
148         }
149         if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
150             i_errno = IESENDMESSAGE;
151             return -1;
152         }
153         close(s);
154     }
155 
156     return 0;
157 }
158 
159 
160 /**************************************************************************/
161 int
162 iperf_handle_message_server(struct iperf_test *test)
163 {
164     int rval;
165     struct iperf_stream *sp;
166 
167     // XXX: Need to rethink how this behaves to fit API
168     if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp)) <= 0) {
169         if (rval == 0) {
170 	    iperf_err(test, "the client has unexpectedly closed the connection");
171             i_errno = IECTRLCLOSE;
172             test->state = IPERF_DONE;
173             return 0;
174         } else {
175             i_errno = IERECVMESSAGE;
176             return -1;
177         }
178     }
179 
180     switch(test->state) {
181         case TEST_START:
182             break;
183         case TEST_END:
184             cpu_util(&test->cpu_util);
185             test->stats_callback(test);
186             SLIST_FOREACH(sp, &test->streams, streams) {
187                 FD_CLR(sp->socket, &test->read_set);
188                 FD_CLR(sp->socket, &test->write_set);
189                 close(sp->socket);
190             }
191 	    if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0)
192                 return -1;
193             if (iperf_exchange_results(test) < 0)
194                 return -1;
195 	    if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0)
196                 return -1;
197             if (test->on_test_finish)
198                 test->on_test_finish(test);
199             test->reporter_callback(test);
200             break;
201         case IPERF_DONE:
202             break;
203         case CLIENT_TERMINATE:
204             i_errno = IECLIENTTERM;
205 
206             // XXX: Remove this line below!
207 	    iperf_err(test, "the client has terminated");
208             SLIST_FOREACH(sp, &test->streams, streams) {
209                 FD_CLR(sp->socket, &test->read_set);
210                 FD_CLR(sp->socket, &test->write_set);
211                 close(sp->socket);
212             }
213             test->state = IPERF_DONE;
214             break;
215         default:
216             i_errno = IEMESSAGE;
217             return -1;
218     }
219 
220     return 0;
221 }
222 
223 /* XXX: This function is not used anymore */
224 void
225 iperf_test_reset(struct iperf_test *test)
226 {
227     struct iperf_stream *sp;
228 
229     close(test->ctrl_sck);
230 
231     /* Free streams */
232     while (!SLIST_EMPTY(&test->streams)) {
233         sp = SLIST_FIRST(&test->streams);
234         SLIST_REMOVE_HEAD(&test->streams, streams);
235         iperf_free_stream(sp);
236     }
237     if (test->timer != NULL) {
238 	tmr_cancel(test->timer);
239 	test->timer = NULL;
240     }
241     if (test->stats_timer != NULL) {
242 	tmr_cancel(test->stats_timer);
243 	test->stats_timer = NULL;
244     }
245     if (test->reporter_timer != NULL) {
246 	tmr_cancel(test->reporter_timer);
247 	test->reporter_timer = NULL;
248     }
249 
250     SLIST_INIT(&test->streams);
251 
252     test->role = 's';
253     set_protocol(test, Ptcp);
254     test->omit = OMIT;
255     test->duration = DURATION;
256     test->diskfile_name = (char*) 0;
257     test->affinity = -1;
258     test->server_affinity = -1;
259     test->title = NULL;
260     test->state = 0;
261     test->server_hostname = NULL;
262 
263     test->ctrl_sck = -1;
264     test->prot_listener = -1;
265 
266     test->bytes_sent = 0;
267 
268     test->reverse = 0;
269     test->sender = 0;
270     test->sender_has_retransmits = 0;
271     test->no_delay = 0;
272 
273     FD_ZERO(&test->read_set);
274     FD_ZERO(&test->write_set);
275     FD_SET(test->listener, &test->read_set);
276     test->max_fd = test->listener;
277 
278     test->num_streams = 1;
279     test->settings->socket_bufsize = 0;
280     test->settings->blksize = DEFAULT_TCP_BLKSIZE;
281     test->settings->rate = 0;
282     test->settings->mss = 0;
283     memset(test->cookie, 0, COOKIE_SIZE);
284 }
285 
286 static void
287 server_stats_timer_proc(TimerClientData client_data, struct timeval *nowP)
288 {
289     struct iperf_test *test = client_data.p;
290 
291     if (test->done)
292         return;
293     if (test->stats_callback)
294 	test->stats_callback(test);
295 }
296 
297 static void
298 server_reporter_timer_proc(TimerClientData client_data, struct timeval *nowP)
299 {
300     struct iperf_test *test = client_data.p;
301 
302     if (test->done)
303         return;
304     if (test->reporter_callback)
305 	test->reporter_callback(test);
306 }
307 
308 static int
309 create_server_timers(struct iperf_test * test)
310 {
311     struct timeval now;
312     TimerClientData cd;
313 
314     if (gettimeofday(&now, NULL) < 0) {
315 	i_errno = IEINITTEST;
316 	return -1;
317     }
318     cd.p = test;
319     test->stats_timer = test->reporter_timer = NULL;
320     if (test->stats_interval != 0) {
321         test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
322         if (test->stats_timer == NULL) {
323             i_errno = IEINITTEST;
324             return -1;
325 	}
326     }
327     if (test->reporter_interval != 0) {
328         test->reporter_timer = tmr_create(&now, server_reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1);
329         if (test->reporter_timer == NULL) {
330             i_errno = IEINITTEST;
331             return -1;
332 	}
333     }
334     return 0;
335 }
336 
337 static void
338 server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP)
339 {
340     struct iperf_test *test = client_data.p;
341 
342     test->omit_timer = NULL;
343     test->omitting = 0;
344     iperf_reset_stats(test);
345     if (test->verbose && !test->json_output && test->reporter_interval == 0)
346 	iprintf(test, "%s", report_omit_done);
347 
348     /* Reset the timers. */
349     if (test->stats_timer != NULL)
350 	tmr_reset(nowP, test->stats_timer);
351     if (test->reporter_timer != NULL)
352 	tmr_reset(nowP, test->reporter_timer);
353 }
354 
355 static int
356 create_server_omit_timer(struct iperf_test * test)
357 {
358     struct timeval now;
359     TimerClientData cd;
360 
361     if (test->omit == 0) {
362 	test->omit_timer = NULL;
363 	test->omitting = 0;
364     } else {
365 	if (gettimeofday(&now, NULL) < 0) {
366 	    i_errno = IEINITTEST;
367 	    return -1;
368 	}
369 	test->omitting = 1;
370 	cd.p = test;
371 	test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
372 	if (test->omit_timer == NULL) {
373 	    i_errno = IEINITTEST;
374 	    return -1;
375 	}
376     }
377 
378     return 0;
379 }
380 
381 static void
382 cleanup_server(struct iperf_test *test)
383 {
384     /* Close open test sockets */
385     close(test->ctrl_sck);
386     close(test->listener);
387 
388     /* Cancel any remaining timers. */
389     if (test->stats_timer != NULL) {
390 	tmr_cancel(test->stats_timer);
391 	test->stats_timer = NULL;
392     }
393     if (test->reporter_timer != NULL) {
394 	tmr_cancel(test->reporter_timer);
395 	test->reporter_timer = NULL;
396     }
397     if (test->omit_timer != NULL) {
398 	tmr_cancel(test->omit_timer);
399 	test->omit_timer = NULL;
400     }
401 }
402 
403 
404 static jmp_buf sigend_jmp_buf;
405 
406 static void
407 sigend_handler(int sig)
408 {
409     longjmp(sigend_jmp_buf, 1);
410 }
411 
412 
413 int
414 iperf_run_server(struct iperf_test *test)
415 {
416     int result, s, streams_accepted;
417     fd_set read_set, write_set;
418     struct iperf_stream *sp;
419     struct timeval now;
420     struct timeval* timeout;
421 
422     /* Termination signals. */
423     iperf_catch_sigend(sigend_handler);
424     if (setjmp(sigend_jmp_buf))
425 	iperf_got_sigend(test);
426 
427     if (test->affinity != -1)
428 	if (iperf_setaffinity(test->affinity) != 0)
429 	    return -1;
430 
431     if (test->json_output)
432 	if (iperf_json_start(test) < 0)
433 	    return -1;
434 
435     if (test->json_output) {
436 	cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
437 	cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
438     } else if (test->verbose) {
439 	iprintf(test, "%s\n", version);
440 	iprintf(test, "%s", "");
441 	fflush(stdout);
442 	system("uname -a");
443     }
444 
445     // Open socket and listen
446     if (iperf_server_listen(test) < 0) {
447         return -1;
448     }
449 
450     // Begin calculating CPU utilization
451     cpu_util(NULL);
452 
453     test->state = IPERF_START;
454     streams_accepted = 0;
455 
456     while (test->state != IPERF_DONE) {
457 
458         memcpy(&read_set, &test->read_set, sizeof(fd_set));
459         memcpy(&write_set, &test->write_set, sizeof(fd_set));
460 
461 	(void) gettimeofday(&now, NULL);
462 	timeout = tmr_timeout(&now);
463         result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
464         if (result < 0 && errno != EINTR) {
465 	    cleanup_server(test);
466             i_errno = IESELECT;
467             return -1;
468         }
469 	if (result > 0) {
470             if (FD_ISSET(test->listener, &read_set)) {
471                 if (test->state != CREATE_STREAMS) {
472                     if (iperf_accept(test) < 0) {
473 			cleanup_server(test);
474                         return -1;
475                     }
476                     FD_CLR(test->listener, &read_set);
477                 }
478             }
479             if (FD_ISSET(test->ctrl_sck, &read_set)) {
480                 if (iperf_handle_message_server(test) < 0) {
481 		    cleanup_server(test);
482                     return -1;
483 		}
484                 FD_CLR(test->ctrl_sck, &read_set);
485             }
486 
487             if (test->state == CREATE_STREAMS) {
488                 if (FD_ISSET(test->prot_listener, &read_set)) {
489 
490                     if ((s = test->protocol->accept(test)) < 0) {
491 			cleanup_server(test);
492                         return -1;
493 		    }
494 
495                     if (!is_closed(s)) {
496                         sp = iperf_new_stream(test, s);
497                         if (!sp) {
498 			    cleanup_server(test);
499                             return -1;
500 			}
501 
502 			if (test->sender)
503 			    FD_SET(s, &test->write_set);
504 			else
505 			    FD_SET(s, &test->read_set);
506 			if (s > test->max_fd) test->max_fd = s;
507 
508                         streams_accepted++;
509                         if (test->on_new_stream)
510                             test->on_new_stream(sp);
511                     }
512                     FD_CLR(test->prot_listener, &read_set);
513                 }
514 
515                 if (streams_accepted == test->num_streams) {
516                     if (test->protocol->id != Ptcp) {
517                         FD_CLR(test->prot_listener, &test->read_set);
518                         close(test->prot_listener);
519                     } else {
520                         if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
521                             FD_CLR(test->listener, &test->read_set);
522                             close(test->listener);
523                             if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
524 				cleanup_server(test);
525                                 i_errno = IELISTEN;
526                                 return -1;
527                             }
528                             test->listener = s;
529                             FD_SET(test->listener, &test->read_set);
530 			    if (test->listener > test->max_fd) test->max_fd = test->listener;
531                         }
532                     }
533                     test->prot_listener = -1;
534 		    if (iperf_set_send_state(test, TEST_START) != 0) {
535 			cleanup_server(test);
536                         return -1;
537 		    }
538                     if (iperf_init_test(test) < 0) {
539 			cleanup_server(test);
540                         return -1;
541 		    }
542 		    if (create_server_timers(test) < 0) {
543 			cleanup_server(test);
544                         return -1;
545 		    }
546 		    if (create_server_omit_timer(test) < 0) {
547 			cleanup_server(test);
548                         return -1;
549 		    }
550 		    if (test->reverse)
551 			if (iperf_create_send_timers(test) < 0) {
552 			    cleanup_server(test);
553 			    return -1;
554 			}
555 		    if (iperf_set_send_state(test, TEST_RUNNING) != 0) {
556 			cleanup_server(test);
557                         return -1;
558 		    }
559                 }
560             }
561 
562             if (test->state == TEST_RUNNING) {
563                 if (test->reverse) {
564                     // Reverse mode. Server sends.
565                     if (iperf_send(test, &write_set) < 0) {
566 			cleanup_server(test);
567                         return -1;
568 		    }
569                 } else {
570                     // Regular mode. Server receives.
571                     if (iperf_recv(test, &read_set) < 0) {
572 			cleanup_server(test);
573                         return -1;
574 		    }
575                 }
576 
577 		if (result == 0 ||
578 		    (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) {
579 		    /* Run the timers. */
580 		    (void) gettimeofday(&now, NULL);
581 		    tmr_run(&now);
582 		}
583             }
584         }
585     }
586 
587     cleanup_server(test);
588 
589     if (test->json_output) {
590 	if (iperf_json_finish(test) < 0)
591 	    return -1;
592     }
593 
594     if (test->server_affinity != -1)
595 	if (iperf_clearaffinity() != 0)
596 	    return -1;
597 
598     return 0;
599 }
600