Annotation of embedaddon/iperf/src/iperf_server_api.c, revision 1.1.1.1
1.1 misho 1: /*
2: * iperf, Copyright (c) 2014, 2015, The Regents of the University of
3: * California, through Lawrence Berkeley National Laboratory (subject
4: * to receipt of any required approvals from the U.S. Dept. of
5: * Energy). All rights reserved.
6: *
7: * If you have questions about your rights to use or distribute this
8: * software, please contact Berkeley Lab's Technology Transfer
9: * Department at TTD@lbl.gov.
10: *
11: * NOTICE. This software is owned by the U.S. Department of Energy.
12: * As such, the U.S. Government has been granted for itself and others
13: * acting on its behalf a paid-up, nonexclusive, irrevocable,
14: * worldwide license in the Software to reproduce, prepare derivative
15: * works, and perform publicly and display publicly. Beginning five
16: * (5) years after the date permission to assert copyright is obtained
17: * from the U.S. Department of Energy, and subject to any subsequent
18: * five (5) year renewals, the U.S. Government is granted for itself
19: * and others acting on its behalf a paid-up, nonexclusive,
20: * irrevocable, worldwide license in the Software to reproduce,
21: * prepare derivative works, distribute copies to the public, perform
22: * publicly and display publicly, and to permit others to do so.
23: *
24: * This code is distributed under a BSD style license, see the LICENSE
25: * file for complete information.
26: */
27: /* iperf_server_api.c: Functions to be used by an iperf server
28: */
29:
30: #include <stdio.h>
31: #include <stdlib.h>
32: #include <string.h>
33: #include <getopt.h>
34: #include <errno.h>
35: #include <unistd.h>
36: #include <assert.h>
37: #include <fcntl.h>
38: #include <sys/socket.h>
39: #include <sys/types.h>
40: #include <netinet/in.h>
41: #include <arpa/inet.h>
42: #include <netdb.h>
43: #include <pthread.h>
44: #ifdef HAVE_STDINT_H
45: #include <stdint.h>
46: #endif
47: #include <netinet/tcp.h>
48: #include <sys/time.h>
49: #include <sys/resource.h>
50: #include <sched.h>
51: #include <setjmp.h>
52:
53: #include "iperf.h"
54: #include "iperf_api.h"
55: #include "iperf_udp.h"
56: #include "iperf_tcp.h"
57: #include "iperf_util.h"
58: #include "timer.h"
59: #include "net.h"
60: #include "units.h"
61: #include "tcp_window_size.h"
62: #include "iperf_util.h"
63: #include "iperf_locale.h"
64:
65:
66: int
67: iperf_server_listen(struct iperf_test *test)
68: {
69: retry:
70: if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
71: if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) {
72: /* If we get "Address family not supported by protocol", that
73: ** probably means we were compiled with IPv6 but the running
74: ** kernel does not actually do IPv6. This is not too unusual,
75: ** v6 support is and perhaps always will be spotty.
76: */
77: warning("this system does not seem to support IPv6 - trying IPv4");
78: test->settings->domain = AF_INET;
79: goto retry;
80: } else {
81: i_errno = IELISTEN;
82: return -1;
83: }
84: }
85:
86: if (!test->json_output) {
87: iprintf(test, "-----------------------------------------------------------\n");
88: iprintf(test, "Server listening on %d\n", test->server_port);
89: }
90:
91: // This needs to be changed to reflect if client has different window size
92: // make sure we got what we asked for
93: /* XXX: This needs to be moved to the stream listener
94: if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) {
95: // Needs to set some sort of error number/message
96: perror("SO_RCVBUF");
97: return -1;
98: }
99: */
100:
101: // XXX: This code needs to be moved to after parameter exhange
102: /*
103: char ubuf[UNIT_LEN];
104: int x;
105:
106: if (test->protocol->id == Ptcp) {
107: if (test->settings->socket_bufsize > 0) {
108: unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A');
109: if (!test->json_output)
110: iprintf(test, report_window, ubuf);
111: } else {
112: if (!test->json_output)
113: iprintf(test, "%s", report_autotune);
114: }
115: }
116: */
117: if (!test->json_output)
118: iprintf(test, "-----------------------------------------------------------\n");
119:
120: FD_ZERO(&test->read_set);
121: FD_ZERO(&test->write_set);
122: FD_SET(test->listener, &test->read_set);
123: if (test->listener > test->max_fd) test->max_fd = test->listener;
124:
125: return 0;
126: }
127:
128: int
129: iperf_accept(struct iperf_test *test)
130: {
131: int s;
132: signed char rbuf = ACCESS_DENIED;
133: socklen_t len;
134: struct sockaddr_storage addr;
135:
136: len = sizeof(addr);
137: if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
138: i_errno = IEACCEPT;
139: return -1;
140: }
141:
142: if (test->ctrl_sck == -1) {
143: /* Server free, accept new client */
144: test->ctrl_sck = s;
145: if (Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
146: i_errno = IERECVCOOKIE;
147: return -1;
148: }
149: FD_SET(test->ctrl_sck, &test->read_set);
150: if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;
151:
152: if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0)
153: return -1;
154: if (iperf_exchange_parameters(test) < 0)
155: return -1;
156: if (test->server_affinity != -1)
157: if (iperf_setaffinity(test, test->server_affinity) != 0)
158: return -1;
159: if (test->on_connect)
160: test->on_connect(test);
161: } else {
162: /*
163: * Don't try to read from the socket. It could block an ongoing test.
164: * Just send ACCESS_DENIED.
165: */
166: if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
167: i_errno = IESENDMESSAGE;
168: return -1;
169: }
170: close(s);
171: }
172:
173: return 0;
174: }
175:
176:
177: /**************************************************************************/
178: int
179: iperf_handle_message_server(struct iperf_test *test)
180: {
181: int rval;
182: struct iperf_stream *sp;
183:
184: // XXX: Need to rethink how this behaves to fit API
185: if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp)) <= 0) {
186: if (rval == 0) {
187: iperf_err(test, "the client has unexpectedly closed the connection");
188: i_errno = IECTRLCLOSE;
189: test->state = IPERF_DONE;
190: return 0;
191: } else {
192: i_errno = IERECVMESSAGE;
193: return -1;
194: }
195: }
196:
197: switch(test->state) {
198: case TEST_START:
199: break;
200: case TEST_END:
201: test->done = 1;
202: cpu_util(test->cpu_util);
203: test->stats_callback(test);
204: SLIST_FOREACH(sp, &test->streams, streams) {
205: FD_CLR(sp->socket, &test->read_set);
206: FD_CLR(sp->socket, &test->write_set);
207: close(sp->socket);
208: }
209: test->reporter_callback(test);
210: if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0)
211: return -1;
212: if (iperf_exchange_results(test) < 0)
213: return -1;
214: if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0)
215: return -1;
216: if (test->on_test_finish)
217: test->on_test_finish(test);
218: break;
219: case IPERF_DONE:
220: break;
221: case CLIENT_TERMINATE:
222: i_errno = IECLIENTTERM;
223:
224: // Temporarily be in DISPLAY_RESULTS phase so we can get
225: // ending summary statistics.
226: signed char oldstate = test->state;
227: cpu_util(test->cpu_util);
228: test->state = DISPLAY_RESULTS;
229: test->reporter_callback(test);
230: test->state = oldstate;
231:
232: // XXX: Remove this line below!
233: iperf_err(test, "the client has terminated");
234: SLIST_FOREACH(sp, &test->streams, streams) {
235: FD_CLR(sp->socket, &test->read_set);
236: FD_CLR(sp->socket, &test->write_set);
237: close(sp->socket);
238: }
239: test->state = IPERF_DONE;
240: break;
241: default:
242: i_errno = IEMESSAGE;
243: return -1;
244: }
245:
246: return 0;
247: }
248:
249: /* XXX: This function is not used anymore */
250: void
251: iperf_test_reset(struct iperf_test *test)
252: {
253: struct iperf_stream *sp;
254:
255: close(test->ctrl_sck);
256:
257: /* Free streams */
258: while (!SLIST_EMPTY(&test->streams)) {
259: sp = SLIST_FIRST(&test->streams);
260: SLIST_REMOVE_HEAD(&test->streams, streams);
261: iperf_free_stream(sp);
262: }
263: if (test->timer != NULL) {
264: tmr_cancel(test->timer);
265: test->timer = NULL;
266: }
267: if (test->stats_timer != NULL) {
268: tmr_cancel(test->stats_timer);
269: test->stats_timer = NULL;
270: }
271: if (test->reporter_timer != NULL) {
272: tmr_cancel(test->reporter_timer);
273: test->reporter_timer = NULL;
274: }
275: test->done = 0;
276:
277: SLIST_INIT(&test->streams);
278:
279: test->role = 's';
280: set_protocol(test, Ptcp);
281: test->omit = OMIT;
282: test->duration = DURATION;
283: test->diskfile_name = (char*) 0;
284: test->affinity = -1;
285: test->server_affinity = -1;
286: test->title = NULL;
287: test->congestion = NULL;
288: test->state = 0;
289: test->server_hostname = NULL;
290:
291: test->ctrl_sck = -1;
292: test->prot_listener = -1;
293:
294: test->bytes_sent = 0;
295:
296: test->reverse = 0;
297: test->sender = 0;
298: test->sender_has_retransmits = 0;
299: test->no_delay = 0;
300:
301: FD_ZERO(&test->read_set);
302: FD_ZERO(&test->write_set);
303: FD_SET(test->listener, &test->read_set);
304: test->max_fd = test->listener;
305:
306: test->num_streams = 1;
307: test->settings->socket_bufsize = 0;
308: test->settings->blksize = DEFAULT_TCP_BLKSIZE;
309: test->settings->rate = 0;
310: test->settings->mss = 0;
311: memset(test->cookie, 0, COOKIE_SIZE);
312: }
313:
314: static void
315: server_stats_timer_proc(TimerClientData client_data, struct timeval *nowP)
316: {
317: struct iperf_test *test = client_data.p;
318:
319: if (test->done)
320: return;
321: if (test->stats_callback)
322: test->stats_callback(test);
323: }
324:
325: static void
326: server_reporter_timer_proc(TimerClientData client_data, struct timeval *nowP)
327: {
328: struct iperf_test *test = client_data.p;
329:
330: if (test->done)
331: return;
332: if (test->reporter_callback)
333: test->reporter_callback(test);
334: }
335:
336: static int
337: create_server_timers(struct iperf_test * test)
338: {
339: struct timeval now;
340: TimerClientData cd;
341:
342: if (gettimeofday(&now, NULL) < 0) {
343: i_errno = IEINITTEST;
344: return -1;
345: }
346: cd.p = test;
347: test->stats_timer = test->reporter_timer = NULL;
348: if (test->stats_interval != 0) {
349: test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
350: if (test->stats_timer == NULL) {
351: i_errno = IEINITTEST;
352: return -1;
353: }
354: }
355: if (test->reporter_interval != 0) {
356: test->reporter_timer = tmr_create(&now, server_reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1);
357: if (test->reporter_timer == NULL) {
358: i_errno = IEINITTEST;
359: return -1;
360: }
361: }
362: return 0;
363: }
364:
365: static void
366: server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP)
367: {
368: struct iperf_test *test = client_data.p;
369:
370: test->omit_timer = NULL;
371: test->omitting = 0;
372: iperf_reset_stats(test);
373: if (test->verbose && !test->json_output && test->reporter_interval == 0)
374: iprintf(test, "%s", report_omit_done);
375:
376: /* Reset the timers. */
377: if (test->stats_timer != NULL)
378: tmr_reset(nowP, test->stats_timer);
379: if (test->reporter_timer != NULL)
380: tmr_reset(nowP, test->reporter_timer);
381: }
382:
383: static int
384: create_server_omit_timer(struct iperf_test * test)
385: {
386: struct timeval now;
387: TimerClientData cd;
388:
389: if (test->omit == 0) {
390: test->omit_timer = NULL;
391: test->omitting = 0;
392: } else {
393: if (gettimeofday(&now, NULL) < 0) {
394: i_errno = IEINITTEST;
395: return -1;
396: }
397: test->omitting = 1;
398: cd.p = test;
399: test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
400: if (test->omit_timer == NULL) {
401: i_errno = IEINITTEST;
402: return -1;
403: }
404: }
405:
406: return 0;
407: }
408:
409: static void
410: cleanup_server(struct iperf_test *test)
411: {
412: /* Close open test sockets */
413: close(test->ctrl_sck);
414: close(test->listener);
415:
416: /* Cancel any remaining timers. */
417: if (test->stats_timer != NULL) {
418: tmr_cancel(test->stats_timer);
419: test->stats_timer = NULL;
420: }
421: if (test->reporter_timer != NULL) {
422: tmr_cancel(test->reporter_timer);
423: test->reporter_timer = NULL;
424: }
425: if (test->omit_timer != NULL) {
426: tmr_cancel(test->omit_timer);
427: test->omit_timer = NULL;
428: }
429: }
430:
431:
432: int
433: iperf_run_server(struct iperf_test *test)
434: {
435: int result, s, streams_accepted;
436: fd_set read_set, write_set;
437: struct iperf_stream *sp;
438: struct timeval now;
439: struct timeval* timeout;
440:
441: if (test->affinity != -1)
442: if (iperf_setaffinity(test, test->affinity) != 0)
443: return -2;
444:
445: if (test->json_output)
446: if (iperf_json_start(test) < 0)
447: return -2;
448:
449: if (test->json_output) {
450: cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
451: cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
452: } else if (test->verbose) {
453: iprintf(test, "%s\n", version);
454: iprintf(test, "%s", "");
455: iprintf(test, "%s\n", get_system_info());
456: iflush(test);
457: }
458:
459: // Open socket and listen
460: if (iperf_server_listen(test) < 0) {
461: return -2;
462: }
463:
464: // Begin calculating CPU utilization
465: cpu_util(NULL);
466:
467: test->state = IPERF_START;
468: streams_accepted = 0;
469:
470: while (test->state != IPERF_DONE) {
471:
472: memcpy(&read_set, &test->read_set, sizeof(fd_set));
473: memcpy(&write_set, &test->write_set, sizeof(fd_set));
474:
475: (void) gettimeofday(&now, NULL);
476: timeout = tmr_timeout(&now);
477: result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
478: if (result < 0 && errno != EINTR) {
479: cleanup_server(test);
480: i_errno = IESELECT;
481: return -1;
482: }
483: if (result > 0) {
484: if (FD_ISSET(test->listener, &read_set)) {
485: if (test->state != CREATE_STREAMS) {
486: if (iperf_accept(test) < 0) {
487: cleanup_server(test);
488: return -1;
489: }
490: FD_CLR(test->listener, &read_set);
491: }
492: }
493: if (FD_ISSET(test->ctrl_sck, &read_set)) {
494: if (iperf_handle_message_server(test) < 0) {
495: cleanup_server(test);
496: return -1;
497: }
498: FD_CLR(test->ctrl_sck, &read_set);
499: }
500:
501: if (test->state == CREATE_STREAMS) {
502: if (FD_ISSET(test->prot_listener, &read_set)) {
503:
504: if ((s = test->protocol->accept(test)) < 0) {
505: cleanup_server(test);
506: return -1;
507: }
508:
509: if (!is_closed(s)) {
510: sp = iperf_new_stream(test, s);
511: if (!sp) {
512: cleanup_server(test);
513: return -1;
514: }
515:
516: if (test->sender)
517: FD_SET(s, &test->write_set);
518: else
519: FD_SET(s, &test->read_set);
520: if (s > test->max_fd) test->max_fd = s;
521:
522: /*
523: * If the protocol isn't UDP, or even if it is but
524: * we're the receiver, set nonblocking sockets.
525: * We need this to allow a server receiver to
526: * maintain interactivity with the control channel.
527: */
528: if (test->protocol->id != Pudp ||
529: !test->sender) {
530: setnonblocking(s, 1);
531: }
532:
533: streams_accepted++;
534: if (test->on_new_stream)
535: test->on_new_stream(sp);
536: }
537: FD_CLR(test->prot_listener, &read_set);
538: }
539:
540: if (streams_accepted == test->num_streams) {
541: if (test->protocol->id != Ptcp) {
542: FD_CLR(test->prot_listener, &test->read_set);
543: close(test->prot_listener);
544: } else {
545: if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
546: FD_CLR(test->listener, &test->read_set);
547: close(test->listener);
548: if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
549: cleanup_server(test);
550: i_errno = IELISTEN;
551: return -1;
552: }
553: test->listener = s;
554: FD_SET(test->listener, &test->read_set);
555: if (test->listener > test->max_fd) test->max_fd = test->listener;
556: }
557: }
558: test->prot_listener = -1;
559: if (iperf_set_send_state(test, TEST_START) != 0) {
560: cleanup_server(test);
561: return -1;
562: }
563: if (iperf_init_test(test) < 0) {
564: cleanup_server(test);
565: return -1;
566: }
567: if (create_server_timers(test) < 0) {
568: cleanup_server(test);
569: return -1;
570: }
571: if (create_server_omit_timer(test) < 0) {
572: cleanup_server(test);
573: return -1;
574: }
575: if (test->reverse)
576: if (iperf_create_send_timers(test) < 0) {
577: cleanup_server(test);
578: return -1;
579: }
580: if (iperf_set_send_state(test, TEST_RUNNING) != 0) {
581: cleanup_server(test);
582: return -1;
583: }
584: }
585: }
586:
587: if (test->state == TEST_RUNNING) {
588: if (test->reverse) {
589: // Reverse mode. Server sends.
590: if (iperf_send(test, &write_set) < 0) {
591: cleanup_server(test);
592: return -1;
593: }
594: } else {
595: // Regular mode. Server receives.
596: if (iperf_recv(test, &read_set) < 0) {
597: cleanup_server(test);
598: return -1;
599: }
600: }
601: }
602: }
603:
604: if (result == 0 ||
605: (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) {
606: /* Run the timers. */
607: (void) gettimeofday(&now, NULL);
608: tmr_run(&now);
609: }
610: }
611:
612: cleanup_server(test);
613:
614: if (test->json_output) {
615: if (iperf_json_finish(test) < 0)
616: return -1;
617: }
618:
619: iflush(test);
620:
621: if (test->server_affinity != -1)
622: if (iperf_clearaffinity(test) != 0)
623: return -1;
624:
625: return 0;
626: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>