xref: /iperf/src/iperf_server_api.c (revision 4e2ef507)
1a951c980SBrian Tierney /*
27d375156SJon Dugan  * Copyright (c) 2009-2011, The Regents of the University of California,
37d375156SJon Dugan  * through Lawrence Berkeley National Laboratory (subject to receipt of any
47d375156SJon Dugan  * required approvals from the U.S. Dept. of Energy).  All rights reserved.
57d375156SJon Dugan  *
67d375156SJon Dugan  * This code is distributed under a BSD style license, see the LICENSE file
77d375156SJon Dugan  * for complete information.
8a951c980SBrian Tierney  */
9a951c980SBrian Tierney 
10a951c980SBrian Tierney /* iperf_server_api.c: Functions to be used by an iperf server
11a951c980SBrian Tierney */
12a951c980SBrian Tierney 
13a951c980SBrian Tierney #include <stdio.h>
14a951c980SBrian Tierney #include <stdlib.h>
15a951c980SBrian Tierney #include <string.h>
16a951c980SBrian Tierney #include <getopt.h>
17a951c980SBrian Tierney #include <errno.h>
18a951c980SBrian Tierney #include <unistd.h>
19a951c980SBrian Tierney #include <assert.h>
20a951c980SBrian Tierney #include <fcntl.h>
21a951c980SBrian Tierney #include <sys/socket.h>
22a951c980SBrian Tierney #include <sys/types.h>
23a951c980SBrian Tierney #include <netinet/in.h>
24a951c980SBrian Tierney #include <arpa/inet.h>
25a951c980SBrian Tierney #include <netdb.h>
26a951c980SBrian Tierney #include <pthread.h>
27a951c980SBrian Tierney #include <stdint.h>
28a951c980SBrian Tierney #include <netinet/tcp.h>
29a951c980SBrian Tierney #include <sys/time.h>
30a951c980SBrian Tierney #include <sys/resource.h>
31a951c980SBrian Tierney #include <sched.h>
32a951c980SBrian Tierney #include <setjmp.h>
33a951c980SBrian Tierney 
34a951c980SBrian Tierney #include "iperf.h"
35a951c980SBrian Tierney #include "iperf_api.h"
36a951c980SBrian Tierney #include "iperf_udp.h"
37a951c980SBrian Tierney #include "iperf_tcp.h"
388a0b5a5dSsethdelliott #include "iperf_util.h"
39a951c980SBrian Tierney #include "timer.h"
40a951c980SBrian Tierney #include "net.h"
41a951c980SBrian Tierney #include "units.h"
42a951c980SBrian Tierney #include "tcp_window_size.h"
43b0b16b86SJon Dugan #include "iperf_util.h"
44a951c980SBrian Tierney #include "locale.h"
45a951c980SBrian Tierney 
46a3281a3dSBrian Tierney 
47982c704aSsethdelliott int
48982c704aSsethdelliott iperf_server_listen(struct iperf_test *test)
49982c704aSsethdelliott {
505c01581bSJef Poskanzer     retry:
51f99bd3b2Ssethdelliott     if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
525c01581bSJef Poskanzer 	if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) {
535c01581bSJef Poskanzer 	    /* If we get "Address family not supported by protocol", that
545c01581bSJef Poskanzer 	    ** probably means we were compiled with IPv6 but the running
555c01581bSJef Poskanzer 	    ** kernel does not actually do IPv6.  This is not too unusual,
565c01581bSJef Poskanzer 	    ** v6 support is and perhaps always will be spotty.
575c01581bSJef Poskanzer 	    */
585c01581bSJef Poskanzer 	    warning("this system does not seem to support IPv6 - trying IPv4");
595c01581bSJef Poskanzer 	    test->settings->domain = AF_INET;
605c01581bSJef Poskanzer 	    goto retry;
615c01581bSJef Poskanzer 	} else {
62b60a49ddSsethdelliott 	    i_errno = IELISTEN;
63ec2d0670SJef Poskanzer 	    return -1;
64982c704aSsethdelliott 	}
655c01581bSJef Poskanzer     }
66982c704aSsethdelliott 
679bfb54c0SJef Poskanzer     if (!test->json_output) {
68982c704aSsethdelliott 	printf("-----------------------------------------------------------\n");
69982c704aSsethdelliott 	printf("Server listening on %d\n", test->server_port);
709bfb54c0SJef Poskanzer     }
71982c704aSsethdelliott 
72982c704aSsethdelliott     // This needs to be changed to reflect if client has different window size
73982c704aSsethdelliott     // make sure we got what we asked for
74ba2672a2Ssethdelliott     /* XXX: This needs to be moved to the stream listener
7566ce7ad4Ssethdelliott     if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) {
76982c704aSsethdelliott         // Needs to set some sort of error number/message
77982c704aSsethdelliott         perror("SO_RCVBUF");
78982c704aSsethdelliott         return -1;
79982c704aSsethdelliott     }
80ba2672a2Ssethdelliott     */
81982c704aSsethdelliott 
82ba2672a2Ssethdelliott     // XXX: This code needs to be moved to after parameter exhange
83c81883bfSsethdelliott     /*
8498ce496bSjef     char ubuf[UNIT_LEN];
8598ce496bSjef     int x;
8698ce496bSjef 
8766ce7ad4Ssethdelliott     if (test->protocol->id == Ptcp) {
88112a907cSsethdelliott         if (test->settings->socket_bufsize > 0) {
89982c704aSsethdelliott             unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A');
90f8bd11afSJef Poskanzer 	    if (!test->json_output)
91982c704aSsethdelliott 		printf("TCP window size: %s\n", ubuf);
92982c704aSsethdelliott         } else {
93f8bd11afSJef Poskanzer 	    if (!test->json_output)
94982c704aSsethdelliott 		printf("Using TCP Autotuning\n");
95982c704aSsethdelliott         }
96982c704aSsethdelliott     }
97c81883bfSsethdelliott     */
989bfb54c0SJef Poskanzer     if (!test->json_output)
99982c704aSsethdelliott 	printf("-----------------------------------------------------------\n");
100982c704aSsethdelliott 
101982c704aSsethdelliott     FD_ZERO(&test->read_set);
102efdc02f7Ssethdelliott     FD_ZERO(&test->write_set);
10366ce7ad4Ssethdelliott     FD_SET(test->listener, &test->read_set);
10466ce7ad4Ssethdelliott     test->max_fd = (test->listener > test->max_fd) ? test->listener : test->max_fd;
105982c704aSsethdelliott 
106982c704aSsethdelliott     return 0;
107982c704aSsethdelliott }
108982c704aSsethdelliott 
109982c704aSsethdelliott int
110982c704aSsethdelliott iperf_accept(struct iperf_test *test)
111982c704aSsethdelliott {
112982c704aSsethdelliott     int s;
113*4e2ef507SJef Poskanzer     signed char rbuf = ACCESS_DENIED;
114af70b448Ssethdelliott     char cookie[COOKIE_SIZE];
115982c704aSsethdelliott     socklen_t len;
11612d474e2SJef Poskanzer     struct sockaddr_storage addr;
117982c704aSsethdelliott 
118b68ac00eSsethdelliott     len = sizeof(addr);
11966ce7ad4Ssethdelliott     if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
120b60a49ddSsethdelliott         i_errno = IEACCEPT;
121ec2d0670SJef Poskanzer         return -1;
122982c704aSsethdelliott     }
123af70b448Ssethdelliott 
124af70b448Ssethdelliott     if (test->ctrl_sck == -1) {
125af70b448Ssethdelliott         /* Server free, accept new client */
126112a907cSsethdelliott         if (Nread(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
127b60a49ddSsethdelliott             i_errno = IERECVCOOKIE;
128ec2d0670SJef Poskanzer             return -1;
129af70b448Ssethdelliott         }
130af70b448Ssethdelliott 
131465b565cSsethdelliott         FD_SET(s, &test->read_set);
132465b565cSsethdelliott         FD_SET(s, &test->write_set);
133465b565cSsethdelliott         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
134465b565cSsethdelliott         test->ctrl_sck = s;
135982c704aSsethdelliott 
136c9693599SJef Poskanzer 	if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0)
137ec2d0670SJef Poskanzer             return -1;
1388bdc8fffSJef Poskanzer         if (iperf_exchange_parameters(test) < 0)
139ec2d0670SJef Poskanzer             return -1;
1408a7e01ebSJef Poskanzer 	if (test->server_affinity != -1)
1418a7e01ebSJef Poskanzer 	    if (iperf_setaffinity(test->server_affinity) != 0)
1428a7e01ebSJef Poskanzer 		return -1;
1438bdc8fffSJef Poskanzer         if (test->on_connect)
1444df383f6Ssethdelliott             test->on_connect(test);
145982c704aSsethdelliott     } else {
146111645edSJef Poskanzer         /* XXX: Do we even need to receive cookie if we're just going to deny anyways? */
147af70b448Ssethdelliott         if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
148b60a49ddSsethdelliott             i_errno = IERECVCOOKIE;
149ec2d0670SJef Poskanzer             return -1;
150465b565cSsethdelliott         }
151*4e2ef507SJef Poskanzer         if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
152b60a49ddSsethdelliott             i_errno = IESENDMESSAGE;
153ec2d0670SJef Poskanzer             return -1;
154465b565cSsethdelliott         }
155465b565cSsethdelliott         close(s);
156982c704aSsethdelliott     }
157982c704aSsethdelliott 
158ec2d0670SJef Poskanzer     return 0;
159af70b448Ssethdelliott }
160af70b448Ssethdelliott 
161b68ac00eSsethdelliott 
162a951c980SBrian Tierney /**************************************************************************/
163982c704aSsethdelliott int
164465b565cSsethdelliott iperf_handle_message_server(struct iperf_test *test)
165982c704aSsethdelliott {
166b68ac00eSsethdelliott     int rval;
167efdc02f7Ssethdelliott     struct iperf_stream *sp;
168efdc02f7Ssethdelliott 
169b60a49ddSsethdelliott     // XXX: Need to rethink how this behaves to fit API
17001943402SJef Poskanzer     if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp)) <= 0) {
171b68ac00eSsethdelliott         if (rval == 0) {
172b5e0751fSJef Poskanzer 	    iperf_err(test, "the client has unexpectedly closed the connection");
173b60a49ddSsethdelliott             i_errno = IECTRLCLOSE;
174b68ac00eSsethdelliott             test->state = IPERF_DONE;
175ec2d0670SJef Poskanzer             return 0;
176b68ac00eSsethdelliott         } else {
177b60a49ddSsethdelliott             i_errno = IERECVMESSAGE;
178ec2d0670SJef Poskanzer             return -1;
179982c704aSsethdelliott         }
180b68ac00eSsethdelliott     }
181982c704aSsethdelliott 
182982c704aSsethdelliott     switch(test->state) {
183ba2672a2Ssethdelliott         case TEST_START:
184ba2672a2Ssethdelliott             break;
185465b565cSsethdelliott         case TEST_END:
1863331e801Ssethdelliott             cpu_util(&test->cpu_util);
187f1b3bd81Ssethdelliott             test->stats_callback(test);
188dd4bc008Ssethdelliott             SLIST_FOREACH(sp, &test->streams, streams) {
189efdc02f7Ssethdelliott                 FD_CLR(sp->socket, &test->read_set);
190efdc02f7Ssethdelliott                 FD_CLR(sp->socket, &test->write_set);
191efdc02f7Ssethdelliott                 close(sp->socket);
192efdc02f7Ssethdelliott             }
193c9693599SJef Poskanzer 	    if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0)
194ec2d0670SJef Poskanzer                 return -1;
195b60a49ddSsethdelliott             if (iperf_exchange_results(test) < 0)
196ec2d0670SJef Poskanzer                 return -1;
197c9693599SJef Poskanzer 	    if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0)
198ec2d0670SJef Poskanzer                 return -1;
1994df383f6Ssethdelliott             if (test->on_test_finish)
2004df383f6Ssethdelliott                 test->on_test_finish(test);
201181d61afSsethdelliott             test->reporter_callback(test);
202465b565cSsethdelliott             break;
203873952e3Ssethdelliott         case IPERF_DONE:
204873952e3Ssethdelliott             break;
205465b565cSsethdelliott         case CLIENT_TERMINATE:
206ffdcc7d4Ssethdelliott             i_errno = IECLIENTTERM;
207ffdcc7d4Ssethdelliott 
208ffdcc7d4Ssethdelliott             // XXX: Remove this line below!
209b5e0751fSJef Poskanzer 	    iperf_err(test, "the client has terminated");
210dd4bc008Ssethdelliott             SLIST_FOREACH(sp, &test->streams, streams) {
2111ac522ecSsethdelliott                 FD_CLR(sp->socket, &test->read_set);
2121ac522ecSsethdelliott                 FD_CLR(sp->socket, &test->write_set);
2131ac522ecSsethdelliott                 close(sp->socket);
2141ac522ecSsethdelliott             }
2151ac522ecSsethdelliott             test->state = IPERF_DONE;
2161ac522ecSsethdelliott             break;
217ba2672a2Ssethdelliott         default:
218b60a49ddSsethdelliott             i_errno = IEMESSAGE;
219ec2d0670SJef Poskanzer             return -1;
220982c704aSsethdelliott     }
221982c704aSsethdelliott 
222ec2d0670SJef Poskanzer     return 0;
223982c704aSsethdelliott }
224982c704aSsethdelliott 
2250bd8d9daSsethdelliott /* XXX: This function is not used anymore */
226efdc02f7Ssethdelliott void
227efdc02f7Ssethdelliott iperf_test_reset(struct iperf_test *test)
228efdc02f7Ssethdelliott {
2290bd8d9daSsethdelliott     struct iperf_stream *sp;
230efdc02f7Ssethdelliott 
231efdc02f7Ssethdelliott     close(test->ctrl_sck);
232efdc02f7Ssethdelliott 
233efdc02f7Ssethdelliott     /* Free streams */
234dd4bc008Ssethdelliott     while (!SLIST_EMPTY(&test->streams)) {
235dd4bc008Ssethdelliott         sp = SLIST_FIRST(&test->streams);
236dd4bc008Ssethdelliott         SLIST_REMOVE_HEAD(&test->streams, streams);
237dd4bc008Ssethdelliott         iperf_free_stream(sp);
238dd4bc008Ssethdelliott     }
239ec2d0670SJef Poskanzer     if (test->timer != NULL) {
240ec2d0670SJef Poskanzer 	tmr_cancel(test->timer);
241f1b3bd81Ssethdelliott 	test->timer = NULL;
242ec2d0670SJef Poskanzer     }
243ec2d0670SJef Poskanzer     if (test->stats_timer != NULL) {
244ec2d0670SJef Poskanzer 	tmr_cancel(test->stats_timer);
245f1b3bd81Ssethdelliott 	test->stats_timer = NULL;
246ec2d0670SJef Poskanzer     }
247ec2d0670SJef Poskanzer     if (test->reporter_timer != NULL) {
248ec2d0670SJef Poskanzer 	tmr_cancel(test->reporter_timer);
249f1b3bd81Ssethdelliott 	test->reporter_timer = NULL;
250ec2d0670SJef Poskanzer     }
251efdc02f7Ssethdelliott 
252dd4bc008Ssethdelliott     SLIST_INIT(&test->streams);
25332885561Ssethdelliott 
254efdc02f7Ssethdelliott     test->role = 's';
25566ce7ad4Ssethdelliott     set_protocol(test, Ptcp);
25657892604SJef Poskanzer     test->omit = OMIT;
25732885561Ssethdelliott     test->duration = DURATION;
258e32a7bcdSJef Poskanzer     test->diskfile_name = (char*) 0;
2598a7e01ebSJef Poskanzer     test->affinity = -1;
2608a7e01ebSJef Poskanzer     test->server_affinity = -1;
26132885561Ssethdelliott     test->state = 0;
26232885561Ssethdelliott     test->server_hostname = NULL;
26332885561Ssethdelliott 
26432885561Ssethdelliott     test->ctrl_sck = -1;
26566ce7ad4Ssethdelliott     test->prot_listener = -1;
26632885561Ssethdelliott 
267f1b3bd81Ssethdelliott     test->bytes_sent = 0;
268f1b3bd81Ssethdelliott 
26932885561Ssethdelliott     test->reverse = 0;
2702c042fd4SJef Poskanzer     test->sender = 0;
27169bdbfd3SJef Poskanzer     test->sender_has_retransmits = 0;
272b68ac00eSsethdelliott     test->no_delay = 0;
27332885561Ssethdelliott 
274efdc02f7Ssethdelliott     FD_ZERO(&test->read_set);
275efdc02f7Ssethdelliott     FD_ZERO(&test->write_set);
27666ce7ad4Ssethdelliott     FD_SET(test->listener, &test->read_set);
27766ce7ad4Ssethdelliott     test->max_fd = test->listener;
27832885561Ssethdelliott 
27932885561Ssethdelliott     test->num_streams = 1;
280112a907cSsethdelliott     test->settings->socket_bufsize = 0;
281112a907cSsethdelliott     test->settings->blksize = DEFAULT_TCP_BLKSIZE;
282d611f13eSJef Poskanzer     test->settings->rate = 0;
283112a907cSsethdelliott     test->settings->mss = 0;
284112a907cSsethdelliott     memset(test->cookie, 0, COOKIE_SIZE);
285efdc02f7Ssethdelliott }
286efdc02f7Ssethdelliott 
287c9693599SJef Poskanzer static void
28838917b1fSJef Poskanzer server_stats_timer_proc(TimerClientData client_data, struct timeval *nowP)
28938917b1fSJef Poskanzer {
29038917b1fSJef Poskanzer     struct iperf_test *test = client_data.p;
29138917b1fSJef Poskanzer 
29238917b1fSJef Poskanzer     if (test->done)
29338917b1fSJef Poskanzer         return;
29438917b1fSJef Poskanzer     if (test->stats_callback)
29538917b1fSJef Poskanzer 	test->stats_callback(test);
29638917b1fSJef Poskanzer }
29738917b1fSJef Poskanzer 
29838917b1fSJef Poskanzer static void
29938917b1fSJef Poskanzer server_reporter_timer_proc(TimerClientData client_data, struct timeval *nowP)
30038917b1fSJef Poskanzer {
30138917b1fSJef Poskanzer     struct iperf_test *test = client_data.p;
30238917b1fSJef Poskanzer 
30338917b1fSJef Poskanzer     if (test->done)
30438917b1fSJef Poskanzer         return;
30538917b1fSJef Poskanzer     if (test->reporter_callback)
30638917b1fSJef Poskanzer 	test->reporter_callback(test);
30738917b1fSJef Poskanzer }
30838917b1fSJef Poskanzer 
30938917b1fSJef Poskanzer static int
31038917b1fSJef Poskanzer create_server_timers(struct iperf_test * test)
31138917b1fSJef Poskanzer {
31238917b1fSJef Poskanzer     struct timeval now;
31338917b1fSJef Poskanzer     TimerClientData cd;
31438917b1fSJef Poskanzer 
31538917b1fSJef Poskanzer     if (gettimeofday(&now, NULL) < 0) {
31638917b1fSJef Poskanzer 	i_errno = IEINITTEST;
31738917b1fSJef Poskanzer 	return -1;
31838917b1fSJef Poskanzer     }
31938917b1fSJef Poskanzer     cd.p = test;
32038917b1fSJef Poskanzer     test->stats_timer = test->reporter_timer = NULL;
32138917b1fSJef Poskanzer     if (test->stats_interval != 0) {
32238917b1fSJef Poskanzer         test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
32338917b1fSJef Poskanzer         if (test->stats_timer == NULL) {
32438917b1fSJef Poskanzer             i_errno = IEINITTEST;
32538917b1fSJef Poskanzer             return -1;
32638917b1fSJef Poskanzer 	}
32738917b1fSJef Poskanzer     }
32838917b1fSJef Poskanzer     if (test->reporter_interval != 0) {
32938917b1fSJef Poskanzer         test->reporter_timer = tmr_create(&now, server_reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1);
33038917b1fSJef Poskanzer         if (test->reporter_timer == NULL) {
33138917b1fSJef Poskanzer             i_errno = IEINITTEST;
33238917b1fSJef Poskanzer             return -1;
33338917b1fSJef Poskanzer 	}
33438917b1fSJef Poskanzer     }
33538917b1fSJef Poskanzer     return 0;
33638917b1fSJef Poskanzer }
33738917b1fSJef Poskanzer 
33838917b1fSJef Poskanzer static void
33957892604SJef Poskanzer server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP)
340c9693599SJef Poskanzer {
341c9693599SJef Poskanzer     struct iperf_test *test = client_data.p;
342c9693599SJef Poskanzer 
34357892604SJef Poskanzer     test->omit_timer = NULL;
34457892604SJef Poskanzer     test->omitting = 0;
345c9693599SJef Poskanzer     iperf_reset_stats(test);
346a953f5aaSJef Poskanzer     if (test->verbose && !test->json_output && test->reporter_interval == 0)
34757892604SJef Poskanzer 	printf("Finished omit period, starting real test\n");
34838917b1fSJef Poskanzer 
34938917b1fSJef Poskanzer     /* Reset the timers. */
35038917b1fSJef Poskanzer     if (test->stats_timer != NULL)
35138917b1fSJef Poskanzer 	tmr_reset(nowP, test->stats_timer);
35238917b1fSJef Poskanzer     if (test->reporter_timer != NULL)
35338917b1fSJef Poskanzer 	tmr_reset(nowP, test->reporter_timer);
354c9693599SJef Poskanzer }
355c9693599SJef Poskanzer 
356c9693599SJef Poskanzer static int
35757892604SJef Poskanzer create_server_omit_timer(struct iperf_test * test)
358c9693599SJef Poskanzer {
359c9693599SJef Poskanzer     struct timeval now;
360c9693599SJef Poskanzer     TimerClientData cd;
361c9693599SJef Poskanzer 
362a953f5aaSJef Poskanzer     if (test->omit == 0) {
363a953f5aaSJef Poskanzer 	test->omit_timer = NULL;
364a953f5aaSJef Poskanzer 	test->omitting = 0;
365a953f5aaSJef Poskanzer     } else {
366c9693599SJef Poskanzer 	if (gettimeofday(&now, NULL) < 0) {
367c9693599SJef Poskanzer 	    i_errno = IEINITTEST;
368c9693599SJef Poskanzer 	    return -1;
369c9693599SJef Poskanzer 	}
37057892604SJef Poskanzer 	test->omitting = 1;
371c9693599SJef Poskanzer 	cd.p = test;
37257892604SJef Poskanzer 	test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
37357892604SJef Poskanzer 	if (test->omit_timer == NULL) {
374c9693599SJef Poskanzer 	    i_errno = IEINITTEST;
375c9693599SJef Poskanzer 	    return -1;
376c9693599SJef Poskanzer 	}
377a953f5aaSJef Poskanzer     }
378a953f5aaSJef Poskanzer 
379c9693599SJef Poskanzer     return 0;
380c9693599SJef Poskanzer }
381c9693599SJef Poskanzer 
382c9693599SJef Poskanzer static void
383c9693599SJef Poskanzer cleanup_server(struct iperf_test *test)
384c9693599SJef Poskanzer {
385c9693599SJef Poskanzer     /* Close open test sockets */
386c9693599SJef Poskanzer     close(test->ctrl_sck);
387c9693599SJef Poskanzer     close(test->listener);
38838917b1fSJef Poskanzer 
38938917b1fSJef Poskanzer     /* Cancel any remaining timers. */
39038917b1fSJef Poskanzer     if (test->stats_timer != NULL) {
39138917b1fSJef Poskanzer 	tmr_cancel(test->stats_timer);
39238917b1fSJef Poskanzer 	test->stats_timer = NULL;
39338917b1fSJef Poskanzer     }
39438917b1fSJef Poskanzer     if (test->reporter_timer != NULL) {
39538917b1fSJef Poskanzer 	tmr_cancel(test->reporter_timer);
39638917b1fSJef Poskanzer 	test->reporter_timer = NULL;
39738917b1fSJef Poskanzer     }
39838917b1fSJef Poskanzer     if (test->omit_timer != NULL) {
39938917b1fSJef Poskanzer 	tmr_cancel(test->omit_timer);
40038917b1fSJef Poskanzer 	test->omit_timer = NULL;
40138917b1fSJef Poskanzer     }
402c9693599SJef Poskanzer }
403c9693599SJef Poskanzer 
404afe6222aSJef Poskanzer 
405afe6222aSJef Poskanzer static jmp_buf sigend_jmp_buf;
406afe6222aSJef Poskanzer 
407afe6222aSJef Poskanzer static void
408afe6222aSJef Poskanzer sigend_handler(int sig)
409afe6222aSJef Poskanzer {
410afe6222aSJef Poskanzer     longjmp(sigend_jmp_buf, 1);
411afe6222aSJef Poskanzer }
412afe6222aSJef Poskanzer 
413afe6222aSJef Poskanzer 
4147fa9f68fSsethdelliott int
415a951c980SBrian Tierney iperf_run_server(struct iperf_test *test)
416a951c980SBrian Tierney {
417112a907cSsethdelliott     int result, s, streams_accepted;
4186177a7f1SJef Poskanzer     fd_set read_set, write_set;
4198a0b5a5dSsethdelliott     struct iperf_stream *sp;
420ec2d0670SJef Poskanzer     struct timeval now;
421a951c980SBrian Tierney 
422afe6222aSJef Poskanzer     /* Termination signals. */
423afe6222aSJef Poskanzer     iperf_catch_sigend(sigend_handler);
424afe6222aSJef Poskanzer     if (setjmp(sigend_jmp_buf))
425afe6222aSJef Poskanzer 	iperf_got_sigend(test);
426afe6222aSJef Poskanzer 
4278a7e01ebSJef Poskanzer     if (test->affinity != -1)
4288a7e01ebSJef Poskanzer 	if (iperf_setaffinity(test->affinity) != 0)
4298a7e01ebSJef Poskanzer 	    return -1;
4308a7e01ebSJef Poskanzer 
431e96ab740SJef Poskanzer     if (test->json_output)
432e96ab740SJef Poskanzer 	if (iperf_json_start(test) < 0)
433e96ab740SJef Poskanzer 	    return -1;
434e96ab740SJef Poskanzer 
435e96ab740SJef Poskanzer     if (test->json_output) {
436e96ab740SJef Poskanzer 	cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
437e96ab740SJef Poskanzer 	cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
438e96ab740SJef Poskanzer     } else if (test->verbose) {
439e96ab740SJef Poskanzer 	printf("%s\n", version);
440e96ab740SJef Poskanzer 	system("uname -a");
441e96ab740SJef Poskanzer     }
442e96ab740SJef Poskanzer 
443982c704aSsethdelliott     // Open socket and listen
444982c704aSsethdelliott     if (iperf_server_listen(test) < 0) {
445ec2d0670SJef Poskanzer         return -1;
446e99faeaeSBrian Tierney     }
447a951c980SBrian Tierney 
4483331e801Ssethdelliott     // Begin calculating CPU utilization
4493331e801Ssethdelliott     cpu_util(NULL);
4503331e801Ssethdelliott 
451efdc02f7Ssethdelliott     test->state = IPERF_START;
452112a907cSsethdelliott     streams_accepted = 0;
453a951c980SBrian Tierney 
454ec2d0670SJef Poskanzer     (void) gettimeofday(&now, NULL);
455873952e3Ssethdelliott     while (test->state != IPERF_DONE) {
456982c704aSsethdelliott 
4576177a7f1SJef Poskanzer         memcpy(&read_set, &test->read_set, sizeof(fd_set));
4586177a7f1SJef Poskanzer         memcpy(&write_set, &test->write_set, sizeof(fd_set));
459982c704aSsethdelliott 
4606177a7f1SJef Poskanzer         result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now));
461982c704aSsethdelliott         if (result < 0 && errno != EINTR) {
462c9693599SJef Poskanzer 	    cleanup_server(test);
463b60a49ddSsethdelliott             i_errno = IESELECT;
464ec2d0670SJef Poskanzer             return -1;
465ec2d0670SJef Poskanzer         }
466ec2d0670SJef Poskanzer 	if (result > 0) {
4676177a7f1SJef Poskanzer             if (FD_ISSET(test->listener, &read_set)) {
468b68ac00eSsethdelliott                 if (test->state != CREATE_STREAMS) {
469465b565cSsethdelliott                     if (iperf_accept(test) < 0) {
470c9693599SJef Poskanzer 			cleanup_server(test);
471ec2d0670SJef Poskanzer                         return -1;
472982c704aSsethdelliott                     }
4736177a7f1SJef Poskanzer                     FD_CLR(test->listener, &read_set);
474982c704aSsethdelliott                 }
475b68ac00eSsethdelliott             }
4766177a7f1SJef Poskanzer             if (FD_ISSET(test->ctrl_sck, &read_set)) {
477c9693599SJef Poskanzer                 if (iperf_handle_message_server(test) < 0) {
478c9693599SJef Poskanzer 		    cleanup_server(test);
479ec2d0670SJef Poskanzer                     return -1;
480c9693599SJef Poskanzer 		}
4816177a7f1SJef Poskanzer                 FD_CLR(test->ctrl_sck, &read_set);
482982c704aSsethdelliott             }
483465b565cSsethdelliott 
484465b565cSsethdelliott             if (test->state == CREATE_STREAMS) {
4856177a7f1SJef Poskanzer                 if (FD_ISSET(test->prot_listener, &read_set)) {
4868a0b5a5dSsethdelliott 
487c9693599SJef Poskanzer                     if ((s = test->protocol->accept(test)) < 0) {
488c9693599SJef Poskanzer 			cleanup_server(test);
489ec2d0670SJef Poskanzer                         return -1;
490c9693599SJef Poskanzer 		    }
4918a0b5a5dSsethdelliott 
4928a0b5a5dSsethdelliott                     if (!is_closed(s)) {
49366ce7ad4Ssethdelliott                         sp = iperf_new_stream(test, s);
494c9693599SJef Poskanzer                         if (!sp) {
495c9693599SJef Poskanzer 			    cleanup_server(test);
496ec2d0670SJef Poskanzer                             return -1;
497c9693599SJef Poskanzer 			}
49866ce7ad4Ssethdelliott 
4998a0b5a5dSsethdelliott                         FD_SET(s, &test->read_set);
5008a0b5a5dSsethdelliott                         FD_SET(s, &test->write_set);
5018a0b5a5dSsethdelliott                         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
50266ce7ad4Ssethdelliott 
503112a907cSsethdelliott                         streams_accepted++;
5044df383f6Ssethdelliott                         if (test->on_new_stream)
5054df383f6Ssethdelliott                             test->on_new_stream(sp);
506b68ac00eSsethdelliott                     }
5076177a7f1SJef Poskanzer                     FD_CLR(test->prot_listener, &read_set);
508b68ac00eSsethdelliott                 }
5098a0b5a5dSsethdelliott 
510112a907cSsethdelliott                 if (streams_accepted == test->num_streams) {
51166ce7ad4Ssethdelliott                     if (test->protocol->id != Ptcp) {
5128a0b5a5dSsethdelliott                         FD_CLR(test->prot_listener, &test->read_set);
5138a0b5a5dSsethdelliott                         close(test->prot_listener);
51466ce7ad4Ssethdelliott                     } else {
5150bd8d9daSsethdelliott                         if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
51666ce7ad4Ssethdelliott                             FD_CLR(test->listener, &test->read_set);
51766ce7ad4Ssethdelliott                             close(test->listener);
518f99bd3b2Ssethdelliott                             if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
519c9693599SJef Poskanzer 				cleanup_server(test);
520b60a49ddSsethdelliott                                 i_errno = IELISTEN;
521ec2d0670SJef Poskanzer                                 return -1;
522c81883bfSsethdelliott                             }
52366ce7ad4Ssethdelliott                             test->listener = s;
524c81883bfSsethdelliott                             test->max_fd = (s > test->max_fd ? s : test->max_fd);
52566ce7ad4Ssethdelliott                             FD_SET(test->listener, &test->read_set);
526c81883bfSsethdelliott                         }
5278556db5dSsethdelliott                     }
5288a0b5a5dSsethdelliott                     test->prot_listener = -1;
529c9693599SJef Poskanzer 		    if (iperf_set_send_state(test, TEST_START) != 0) {
530c9693599SJef Poskanzer 			cleanup_server(test);
531ec2d0670SJef Poskanzer                         return -1;
532982c704aSsethdelliott 		    }
533c9693599SJef Poskanzer                     if (iperf_init_test(test) < 0) {
534c9693599SJef Poskanzer 			cleanup_server(test);
535ec2d0670SJef Poskanzer                         return -1;
536c9693599SJef Poskanzer 		    }
53738917b1fSJef Poskanzer 		    if (create_server_timers(test) < 0) {
53838917b1fSJef Poskanzer 			cleanup_server(test);
53938917b1fSJef Poskanzer                         return -1;
54038917b1fSJef Poskanzer 		    }
54157892604SJef Poskanzer 		    if (create_server_omit_timer(test) < 0) {
542c9693599SJef Poskanzer 			cleanup_server(test);
543c9693599SJef Poskanzer                         return -1;
544c9693599SJef Poskanzer 		    }
5458bdc8fffSJef Poskanzer 		    if (test->reverse)
5468bdc8fffSJef Poskanzer 			if (iperf_create_send_timers(test) < 0) {
5478bdc8fffSJef Poskanzer 			    cleanup_server(test);
5488bdc8fffSJef Poskanzer 			    return -1;
5498bdc8fffSJef Poskanzer 			}
550c9693599SJef Poskanzer 		    if (iperf_set_send_state(test, TEST_RUNNING) != 0) {
551c9693599SJef Poskanzer 			cleanup_server(test);
552ec2d0670SJef Poskanzer                         return -1;
553f1b3bd81Ssethdelliott 		    }
554982c704aSsethdelliott                 }
555982c704aSsethdelliott             }
556982c704aSsethdelliott 
557f1b3bd81Ssethdelliott             if (test->state == TEST_RUNNING) {
558465b565cSsethdelliott                 if (test->reverse) {
559465b565cSsethdelliott                     // Reverse mode. Server sends.
560c9693599SJef Poskanzer                     if (iperf_send(test, &write_set) < 0) {
561c9693599SJef Poskanzer 			cleanup_server(test);
562ec2d0670SJef Poskanzer                         return -1;
563c9693599SJef Poskanzer 		    }
564982c704aSsethdelliott                 } else {
565465b565cSsethdelliott                     // Regular mode. Server receives.
566c9693599SJef Poskanzer                     if (iperf_recv(test, &read_set) < 0) {
567c9693599SJef Poskanzer 			cleanup_server(test);
568ec2d0670SJef Poskanzer                         return -1;
569e99faeaeSBrian Tierney 		    }
570c9693599SJef Poskanzer                 }
571f1b3bd81Ssethdelliott 
572ec2d0670SJef Poskanzer 		/* Run the timers. */
573ec2d0670SJef Poskanzer 		(void) gettimeofday(&now, NULL);
574ec2d0670SJef Poskanzer 		tmr_run(&now);
575f1b3bd81Ssethdelliott             }
576a951c980SBrian Tierney         }
577982c704aSsethdelliott     }
578e99faeaeSBrian Tierney 
579c9693599SJef Poskanzer     cleanup_server(test);
580efdc02f7Ssethdelliott 
581e96ab740SJef Poskanzer     if (test->json_output) {
582e96ab740SJef Poskanzer 	if (iperf_json_finish(test) < 0)
583e96ab740SJef Poskanzer 	    return -1;
584e96ab740SJef Poskanzer     }
585e96ab740SJef Poskanzer 
5868a7e01ebSJef Poskanzer     if (test->server_affinity != -1)
5878a7e01ebSJef Poskanzer 	if (iperf_clearaffinity() != 0)
5888a7e01ebSJef Poskanzer 	    return -1;
5898a7e01ebSJef Poskanzer 
590ec2d0670SJef Poskanzer     return 0;
591a3281a3dSBrian Tierney }
592