xref: /iperf/src/iperf_server_api.c (revision f8bd11af)
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');
90*f8bd11afSJef Poskanzer 	    if (!test->json_output)
91982c704aSsethdelliott 		printf("TCP window size: %s\n", ubuf);
92982c704aSsethdelliott         } else {
93*f8bd11afSJef 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;
113465b565cSsethdelliott     int 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;
1408bdc8fffSJef Poskanzer         if (test->on_connect)
1414df383f6Ssethdelliott             test->on_connect(test);
142982c704aSsethdelliott     } else {
143111645edSJef Poskanzer         /* XXX: Do we even need to receive cookie if we're just going to deny anyways? */
144af70b448Ssethdelliott         if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
145b60a49ddSsethdelliott             i_errno = IERECVCOOKIE;
146ec2d0670SJef Poskanzer             return -1;
147465b565cSsethdelliott         }
148987b4323SJef Poskanzer         if (Nwrite(s, (char*) &rbuf, sizeof(int), Ptcp) < 0) {
149b60a49ddSsethdelliott             i_errno = IESENDMESSAGE;
150ec2d0670SJef Poskanzer             return -1;
151465b565cSsethdelliott         }
152465b565cSsethdelliott         close(s);
153982c704aSsethdelliott     }
154982c704aSsethdelliott 
155ec2d0670SJef Poskanzer     return 0;
156af70b448Ssethdelliott }
157af70b448Ssethdelliott 
158b68ac00eSsethdelliott 
159a951c980SBrian Tierney /**************************************************************************/
160982c704aSsethdelliott int
161465b565cSsethdelliott iperf_handle_message_server(struct iperf_test *test)
162982c704aSsethdelliott {
163b68ac00eSsethdelliott     int rval;
164efdc02f7Ssethdelliott     struct iperf_stream *sp;
165efdc02f7Ssethdelliott 
166b60a49ddSsethdelliott     // XXX: Need to rethink how this behaves to fit API
16701943402SJef Poskanzer     if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp)) <= 0) {
168b68ac00eSsethdelliott         if (rval == 0) {
169b5e0751fSJef Poskanzer 	    iperf_err(test, "the client has unexpectedly closed the connection");
170b60a49ddSsethdelliott             i_errno = IECTRLCLOSE;
171b68ac00eSsethdelliott             test->state = IPERF_DONE;
172ec2d0670SJef Poskanzer             return 0;
173b68ac00eSsethdelliott         } else {
174b60a49ddSsethdelliott             i_errno = IERECVMESSAGE;
175ec2d0670SJef Poskanzer             return -1;
176982c704aSsethdelliott         }
177b68ac00eSsethdelliott     }
178982c704aSsethdelliott 
179982c704aSsethdelliott     switch(test->state) {
180ba2672a2Ssethdelliott         case TEST_START:
181ba2672a2Ssethdelliott             break;
182465b565cSsethdelliott         case TEST_END:
1833331e801Ssethdelliott             cpu_util(&test->cpu_util);
184f1b3bd81Ssethdelliott             test->stats_callback(test);
185dd4bc008Ssethdelliott             SLIST_FOREACH(sp, &test->streams, streams) {
186efdc02f7Ssethdelliott                 FD_CLR(sp->socket, &test->read_set);
187efdc02f7Ssethdelliott                 FD_CLR(sp->socket, &test->write_set);
188efdc02f7Ssethdelliott                 close(sp->socket);
189efdc02f7Ssethdelliott             }
190c9693599SJef Poskanzer 	    if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0)
191ec2d0670SJef Poskanzer                 return -1;
19269bdbfd3SJef Poskanzer             if (iperf_sum_results(test) < 0)
19369bdbfd3SJef Poskanzer                 return -1;
194b60a49ddSsethdelliott             if (iperf_exchange_results(test) < 0)
195ec2d0670SJef Poskanzer                 return -1;
196c9693599SJef Poskanzer 	    if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0)
197ec2d0670SJef Poskanzer                 return -1;
1984df383f6Ssethdelliott             if (test->on_test_finish)
1994df383f6Ssethdelliott                 test->on_test_finish(test);
200181d61afSsethdelliott             test->reporter_callback(test);
201465b565cSsethdelliott             break;
202873952e3Ssethdelliott         case IPERF_DONE:
203873952e3Ssethdelliott             break;
204465b565cSsethdelliott         case CLIENT_TERMINATE:
205ffdcc7d4Ssethdelliott             i_errno = IECLIENTTERM;
206ffdcc7d4Ssethdelliott 
207ffdcc7d4Ssethdelliott             // XXX: Remove this line below!
208b5e0751fSJef Poskanzer 	    iperf_err(test, "the client has terminated");
209dd4bc008Ssethdelliott             SLIST_FOREACH(sp, &test->streams, streams) {
2101ac522ecSsethdelliott                 FD_CLR(sp->socket, &test->read_set);
2111ac522ecSsethdelliott                 FD_CLR(sp->socket, &test->write_set);
2121ac522ecSsethdelliott                 close(sp->socket);
2131ac522ecSsethdelliott             }
2141ac522ecSsethdelliott             test->state = IPERF_DONE;
2151ac522ecSsethdelliott             break;
216ba2672a2Ssethdelliott         default:
217b60a49ddSsethdelliott             i_errno = IEMESSAGE;
218ec2d0670SJef Poskanzer             return -1;
219982c704aSsethdelliott     }
220982c704aSsethdelliott 
221ec2d0670SJef Poskanzer     return 0;
222982c704aSsethdelliott }
223982c704aSsethdelliott 
2240bd8d9daSsethdelliott /* XXX: This function is not used anymore */
225efdc02f7Ssethdelliott void
226efdc02f7Ssethdelliott iperf_test_reset(struct iperf_test *test)
227efdc02f7Ssethdelliott {
2280bd8d9daSsethdelliott     struct iperf_stream *sp;
229efdc02f7Ssethdelliott 
230efdc02f7Ssethdelliott     close(test->ctrl_sck);
231efdc02f7Ssethdelliott 
232efdc02f7Ssethdelliott     /* Free streams */
233dd4bc008Ssethdelliott     while (!SLIST_EMPTY(&test->streams)) {
234dd4bc008Ssethdelliott         sp = SLIST_FIRST(&test->streams);
235dd4bc008Ssethdelliott         SLIST_REMOVE_HEAD(&test->streams, streams);
236dd4bc008Ssethdelliott         iperf_free_stream(sp);
237dd4bc008Ssethdelliott     }
238ec2d0670SJef Poskanzer     if (test->timer != NULL) {
239ec2d0670SJef Poskanzer 	tmr_cancel(test->timer);
240f1b3bd81Ssethdelliott 	test->timer = NULL;
241ec2d0670SJef Poskanzer     }
242ec2d0670SJef Poskanzer     if (test->stats_timer != NULL) {
243ec2d0670SJef Poskanzer 	tmr_cancel(test->stats_timer);
244f1b3bd81Ssethdelliott 	test->stats_timer = NULL;
245ec2d0670SJef Poskanzer     }
246ec2d0670SJef Poskanzer     if (test->reporter_timer != NULL) {
247ec2d0670SJef Poskanzer 	tmr_cancel(test->reporter_timer);
248f1b3bd81Ssethdelliott 	test->reporter_timer = NULL;
249ec2d0670SJef Poskanzer     }
250efdc02f7Ssethdelliott 
251dd4bc008Ssethdelliott     SLIST_INIT(&test->streams);
25232885561Ssethdelliott 
253efdc02f7Ssethdelliott     test->role = 's';
25466ce7ad4Ssethdelliott     set_protocol(test, Ptcp);
25557892604SJef Poskanzer     test->omit = OMIT;
25632885561Ssethdelliott     test->duration = DURATION;
25732885561Ssethdelliott     test->state = 0;
25832885561Ssethdelliott     test->server_hostname = NULL;
25932885561Ssethdelliott 
26032885561Ssethdelliott     test->ctrl_sck = -1;
26166ce7ad4Ssethdelliott     test->prot_listener = -1;
26232885561Ssethdelliott 
263f1b3bd81Ssethdelliott     test->bytes_sent = 0;
264f1b3bd81Ssethdelliott 
26532885561Ssethdelliott     test->reverse = 0;
2662c042fd4SJef Poskanzer     test->sender = 0;
26769bdbfd3SJef Poskanzer     test->sender_has_retransmits = 0;
268b68ac00eSsethdelliott     test->no_delay = 0;
26932885561Ssethdelliott 
270efdc02f7Ssethdelliott     FD_ZERO(&test->read_set);
271efdc02f7Ssethdelliott     FD_ZERO(&test->write_set);
27266ce7ad4Ssethdelliott     FD_SET(test->listener, &test->read_set);
27366ce7ad4Ssethdelliott     test->max_fd = test->listener;
27432885561Ssethdelliott 
27532885561Ssethdelliott     test->num_streams = 1;
276112a907cSsethdelliott     test->settings->socket_bufsize = 0;
277112a907cSsethdelliott     test->settings->blksize = DEFAULT_TCP_BLKSIZE;
278d611f13eSJef Poskanzer     test->settings->rate = 0;
279112a907cSsethdelliott     test->settings->mss = 0;
280112a907cSsethdelliott     memset(test->cookie, 0, COOKIE_SIZE);
281efdc02f7Ssethdelliott }
282efdc02f7Ssethdelliott 
283c9693599SJef Poskanzer static void
28457892604SJef Poskanzer server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP)
285c9693599SJef Poskanzer {
286c9693599SJef Poskanzer     struct iperf_test *test = client_data.p;
287c9693599SJef Poskanzer 
28857892604SJef Poskanzer     test->omit_timer = NULL;
28957892604SJef Poskanzer     test->omitting = 0;
290c9693599SJef Poskanzer     iperf_reset_stats(test);
291c9693599SJef Poskanzer     if (test->verbose && !test->json_output)
29257892604SJef Poskanzer 	printf("Finished omit period, starting real test\n");
293c9693599SJef Poskanzer }
294c9693599SJef Poskanzer 
295c9693599SJef Poskanzer static int
29657892604SJef Poskanzer create_server_omit_timer(struct iperf_test * test)
297c9693599SJef Poskanzer {
298c9693599SJef Poskanzer     struct timeval now;
299c9693599SJef Poskanzer     TimerClientData cd;
300c9693599SJef Poskanzer 
301c9693599SJef Poskanzer     if (gettimeofday(&now, NULL) < 0) {
302c9693599SJef Poskanzer 	i_errno = IEINITTEST;
303c9693599SJef Poskanzer 	return -1;
304c9693599SJef Poskanzer     }
30557892604SJef Poskanzer     test->omitting = 1;
306c9693599SJef Poskanzer     cd.p = test;
30757892604SJef Poskanzer     test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
30857892604SJef Poskanzer     if (test->omit_timer == NULL) {
309c9693599SJef Poskanzer 	i_errno = IEINITTEST;
310c9693599SJef Poskanzer 	return -1;
311c9693599SJef Poskanzer     }
312c9693599SJef Poskanzer     return 0;
313c9693599SJef Poskanzer }
314c9693599SJef Poskanzer 
315c9693599SJef Poskanzer static void
316c9693599SJef Poskanzer cleanup_server(struct iperf_test *test)
317c9693599SJef Poskanzer {
318c9693599SJef Poskanzer     /* Close open test sockets */
319c9693599SJef Poskanzer     close(test->ctrl_sck);
320c9693599SJef Poskanzer     close(test->listener);
321c9693599SJef Poskanzer }
322c9693599SJef Poskanzer 
3237fa9f68fSsethdelliott int
324a951c980SBrian Tierney iperf_run_server(struct iperf_test *test)
325a951c980SBrian Tierney {
326112a907cSsethdelliott     int result, s, streams_accepted;
3276177a7f1SJef Poskanzer     fd_set read_set, write_set;
3288a0b5a5dSsethdelliott     struct iperf_stream *sp;
329ec2d0670SJef Poskanzer     struct timeval now;
330a951c980SBrian Tierney 
331e96ab740SJef Poskanzer     if (test->json_output)
332e96ab740SJef Poskanzer 	if (iperf_json_start(test) < 0)
333e96ab740SJef Poskanzer 	    return -1;
334e96ab740SJef Poskanzer 
335e96ab740SJef Poskanzer     if (test->json_output) {
336e96ab740SJef Poskanzer 	cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
337e96ab740SJef Poskanzer 	cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
338e96ab740SJef Poskanzer     } else if (test->verbose) {
339e96ab740SJef Poskanzer 	printf("%s\n", version);
340e96ab740SJef Poskanzer 	system("uname -a");
341e96ab740SJef Poskanzer     }
342e96ab740SJef Poskanzer 
343982c704aSsethdelliott     // Open socket and listen
344982c704aSsethdelliott     if (iperf_server_listen(test) < 0) {
345ec2d0670SJef Poskanzer         return -1;
346e99faeaeSBrian Tierney     }
347a951c980SBrian Tierney 
3483331e801Ssethdelliott     // Begin calculating CPU utilization
3493331e801Ssethdelliott     cpu_util(NULL);
3503331e801Ssethdelliott 
351efdc02f7Ssethdelliott     test->state = IPERF_START;
352112a907cSsethdelliott     streams_accepted = 0;
353a951c980SBrian Tierney 
354ec2d0670SJef Poskanzer     (void) gettimeofday(&now, NULL);
355873952e3Ssethdelliott     while (test->state != IPERF_DONE) {
356982c704aSsethdelliott 
3576177a7f1SJef Poskanzer         memcpy(&read_set, &test->read_set, sizeof(fd_set));
3586177a7f1SJef Poskanzer         memcpy(&write_set, &test->write_set, sizeof(fd_set));
359982c704aSsethdelliott 
3606177a7f1SJef Poskanzer         result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now));
361982c704aSsethdelliott         if (result < 0 && errno != EINTR) {
362c9693599SJef Poskanzer 	    cleanup_server(test);
363b60a49ddSsethdelliott             i_errno = IESELECT;
364ec2d0670SJef Poskanzer             return -1;
365ec2d0670SJef Poskanzer         }
366ec2d0670SJef Poskanzer 	if (result > 0) {
3676177a7f1SJef Poskanzer             if (FD_ISSET(test->listener, &read_set)) {
368b68ac00eSsethdelliott                 if (test->state != CREATE_STREAMS) {
369465b565cSsethdelliott                     if (iperf_accept(test) < 0) {
370c9693599SJef Poskanzer 			cleanup_server(test);
371ec2d0670SJef Poskanzer                         return -1;
372982c704aSsethdelliott                     }
3736177a7f1SJef Poskanzer                     FD_CLR(test->listener, &read_set);
374982c704aSsethdelliott                 }
375b68ac00eSsethdelliott             }
3766177a7f1SJef Poskanzer             if (FD_ISSET(test->ctrl_sck, &read_set)) {
377c9693599SJef Poskanzer                 if (iperf_handle_message_server(test) < 0) {
378c9693599SJef Poskanzer 		    cleanup_server(test);
379ec2d0670SJef Poskanzer                     return -1;
380c9693599SJef Poskanzer 		}
3816177a7f1SJef Poskanzer                 FD_CLR(test->ctrl_sck, &read_set);
382982c704aSsethdelliott             }
383465b565cSsethdelliott 
384465b565cSsethdelliott             if (test->state == CREATE_STREAMS) {
3856177a7f1SJef Poskanzer                 if (FD_ISSET(test->prot_listener, &read_set)) {
3868a0b5a5dSsethdelliott 
387c9693599SJef Poskanzer                     if ((s = test->protocol->accept(test)) < 0) {
388c9693599SJef Poskanzer 			cleanup_server(test);
389ec2d0670SJef Poskanzer                         return -1;
390c9693599SJef Poskanzer 		    }
3918a0b5a5dSsethdelliott 
3928a0b5a5dSsethdelliott                     if (!is_closed(s)) {
39366ce7ad4Ssethdelliott                         sp = iperf_new_stream(test, s);
394c9693599SJef Poskanzer                         if (!sp) {
395c9693599SJef Poskanzer 			    cleanup_server(test);
396ec2d0670SJef Poskanzer                             return -1;
397c9693599SJef Poskanzer 			}
39866ce7ad4Ssethdelliott 
3998a0b5a5dSsethdelliott                         FD_SET(s, &test->read_set);
4008a0b5a5dSsethdelliott                         FD_SET(s, &test->write_set);
4018a0b5a5dSsethdelliott                         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
40266ce7ad4Ssethdelliott 
403112a907cSsethdelliott                         streams_accepted++;
4044df383f6Ssethdelliott                         if (test->on_new_stream)
4054df383f6Ssethdelliott                             test->on_new_stream(sp);
406b68ac00eSsethdelliott                     }
4076177a7f1SJef Poskanzer                     FD_CLR(test->prot_listener, &read_set);
408b68ac00eSsethdelliott                 }
4098a0b5a5dSsethdelliott 
410112a907cSsethdelliott                 if (streams_accepted == test->num_streams) {
41166ce7ad4Ssethdelliott                     if (test->protocol->id != Ptcp) {
4128a0b5a5dSsethdelliott                         FD_CLR(test->prot_listener, &test->read_set);
4138a0b5a5dSsethdelliott                         close(test->prot_listener);
41466ce7ad4Ssethdelliott                     } else {
4150bd8d9daSsethdelliott                         if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
41666ce7ad4Ssethdelliott                             FD_CLR(test->listener, &test->read_set);
41766ce7ad4Ssethdelliott                             close(test->listener);
418f99bd3b2Ssethdelliott                             if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
419c9693599SJef Poskanzer 				cleanup_server(test);
420b60a49ddSsethdelliott                                 i_errno = IELISTEN;
421ec2d0670SJef Poskanzer                                 return -1;
422c81883bfSsethdelliott                             }
42366ce7ad4Ssethdelliott                             test->listener = s;
424c81883bfSsethdelliott                             test->max_fd = (s > test->max_fd ? s : test->max_fd);
42566ce7ad4Ssethdelliott                             FD_SET(test->listener, &test->read_set);
426c81883bfSsethdelliott                         }
4278556db5dSsethdelliott                     }
4288a0b5a5dSsethdelliott                     test->prot_listener = -1;
429c9693599SJef Poskanzer 		    if (iperf_set_send_state(test, TEST_START) != 0) {
430c9693599SJef Poskanzer 			cleanup_server(test);
431ec2d0670SJef Poskanzer                         return -1;
432982c704aSsethdelliott 		    }
433c9693599SJef Poskanzer                     if (iperf_init_test(test) < 0) {
434c9693599SJef Poskanzer 			cleanup_server(test);
435ec2d0670SJef Poskanzer                         return -1;
436c9693599SJef Poskanzer 		    }
43757892604SJef Poskanzer 		    if (create_server_omit_timer(test) < 0) {
438c9693599SJef Poskanzer 			cleanup_server(test);
439c9693599SJef Poskanzer                         return -1;
440c9693599SJef Poskanzer 		    }
4418bdc8fffSJef Poskanzer 		    if (test->reverse)
4428bdc8fffSJef Poskanzer 			if (iperf_create_send_timers(test) < 0) {
4438bdc8fffSJef Poskanzer 			    cleanup_server(test);
4448bdc8fffSJef Poskanzer 			    return -1;
4458bdc8fffSJef Poskanzer 			}
446c9693599SJef Poskanzer 		    if (iperf_set_send_state(test, TEST_RUNNING) != 0) {
447c9693599SJef Poskanzer 			cleanup_server(test);
448ec2d0670SJef Poskanzer                         return -1;
449f1b3bd81Ssethdelliott 		    }
450982c704aSsethdelliott                 }
451982c704aSsethdelliott             }
452982c704aSsethdelliott 
453f1b3bd81Ssethdelliott             if (test->state == TEST_RUNNING) {
454465b565cSsethdelliott                 if (test->reverse) {
455465b565cSsethdelliott                     // Reverse mode. Server sends.
456c9693599SJef Poskanzer                     if (iperf_send(test, &write_set) < 0) {
457c9693599SJef Poskanzer 			cleanup_server(test);
458ec2d0670SJef Poskanzer                         return -1;
459c9693599SJef Poskanzer 		    }
460982c704aSsethdelliott                 } else {
461465b565cSsethdelliott                     // Regular mode. Server receives.
462c9693599SJef Poskanzer                     if (iperf_recv(test, &read_set) < 0) {
463c9693599SJef Poskanzer 			cleanup_server(test);
464ec2d0670SJef Poskanzer                         return -1;
465e99faeaeSBrian Tierney 		    }
466c9693599SJef Poskanzer                 }
467f1b3bd81Ssethdelliott 
468ec2d0670SJef Poskanzer 		/* Run the timers. */
469ec2d0670SJef Poskanzer 		(void) gettimeofday(&now, NULL);
470ec2d0670SJef Poskanzer 		tmr_run(&now);
471f1b3bd81Ssethdelliott             }
472a951c980SBrian Tierney         }
473982c704aSsethdelliott     }
474e99faeaeSBrian Tierney 
475c9693599SJef Poskanzer     cleanup_server(test);
476efdc02f7Ssethdelliott 
477e96ab740SJef Poskanzer     if (test->json_output) {
478e96ab740SJef Poskanzer 	if (iperf_json_finish(test) < 0)
479e96ab740SJef Poskanzer 	    return -1;
480e96ab740SJef Poskanzer     }
481e96ab740SJef Poskanzer 
482ec2d0670SJef Poskanzer     return 0;
483a3281a3dSBrian Tierney }
484