xref: /iperf/src/iperf_server_api.c (revision e32a7bcd)
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;
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;
257*e32a7bcdSJef Poskanzer     test->diskfile_name = (char*) 0;
25832885561Ssethdelliott     test->state = 0;
25932885561Ssethdelliott     test->server_hostname = NULL;
26032885561Ssethdelliott 
26132885561Ssethdelliott     test->ctrl_sck = -1;
26266ce7ad4Ssethdelliott     test->prot_listener = -1;
26332885561Ssethdelliott 
264f1b3bd81Ssethdelliott     test->bytes_sent = 0;
265f1b3bd81Ssethdelliott 
26632885561Ssethdelliott     test->reverse = 0;
2672c042fd4SJef Poskanzer     test->sender = 0;
26869bdbfd3SJef Poskanzer     test->sender_has_retransmits = 0;
269b68ac00eSsethdelliott     test->no_delay = 0;
27032885561Ssethdelliott 
271efdc02f7Ssethdelliott     FD_ZERO(&test->read_set);
272efdc02f7Ssethdelliott     FD_ZERO(&test->write_set);
27366ce7ad4Ssethdelliott     FD_SET(test->listener, &test->read_set);
27466ce7ad4Ssethdelliott     test->max_fd = test->listener;
27532885561Ssethdelliott 
27632885561Ssethdelliott     test->num_streams = 1;
277112a907cSsethdelliott     test->settings->socket_bufsize = 0;
278112a907cSsethdelliott     test->settings->blksize = DEFAULT_TCP_BLKSIZE;
279d611f13eSJef Poskanzer     test->settings->rate = 0;
280112a907cSsethdelliott     test->settings->mss = 0;
281112a907cSsethdelliott     memset(test->cookie, 0, COOKIE_SIZE);
282efdc02f7Ssethdelliott }
283efdc02f7Ssethdelliott 
284c9693599SJef Poskanzer static void
28557892604SJef Poskanzer server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP)
286c9693599SJef Poskanzer {
287c9693599SJef Poskanzer     struct iperf_test *test = client_data.p;
288c9693599SJef Poskanzer 
28957892604SJef Poskanzer     test->omit_timer = NULL;
29057892604SJef Poskanzer     test->omitting = 0;
291c9693599SJef Poskanzer     iperf_reset_stats(test);
292c9693599SJef Poskanzer     if (test->verbose && !test->json_output)
29357892604SJef Poskanzer 	printf("Finished omit period, starting real test\n");
294c9693599SJef Poskanzer }
295c9693599SJef Poskanzer 
296c9693599SJef Poskanzer static int
29757892604SJef Poskanzer create_server_omit_timer(struct iperf_test * test)
298c9693599SJef Poskanzer {
299c9693599SJef Poskanzer     struct timeval now;
300c9693599SJef Poskanzer     TimerClientData cd;
301c9693599SJef Poskanzer 
302c9693599SJef Poskanzer     if (gettimeofday(&now, NULL) < 0) {
303c9693599SJef Poskanzer 	i_errno = IEINITTEST;
304c9693599SJef Poskanzer 	return -1;
305c9693599SJef Poskanzer     }
30657892604SJef Poskanzer     test->omitting = 1;
307c9693599SJef Poskanzer     cd.p = test;
30857892604SJef Poskanzer     test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
30957892604SJef Poskanzer     if (test->omit_timer == NULL) {
310c9693599SJef Poskanzer 	i_errno = IEINITTEST;
311c9693599SJef Poskanzer 	return -1;
312c9693599SJef Poskanzer     }
313c9693599SJef Poskanzer     return 0;
314c9693599SJef Poskanzer }
315c9693599SJef Poskanzer 
316c9693599SJef Poskanzer static void
317c9693599SJef Poskanzer cleanup_server(struct iperf_test *test)
318c9693599SJef Poskanzer {
319c9693599SJef Poskanzer     /* Close open test sockets */
320c9693599SJef Poskanzer     close(test->ctrl_sck);
321c9693599SJef Poskanzer     close(test->listener);
322c9693599SJef Poskanzer }
323c9693599SJef Poskanzer 
3247fa9f68fSsethdelliott int
325a951c980SBrian Tierney iperf_run_server(struct iperf_test *test)
326a951c980SBrian Tierney {
327112a907cSsethdelliott     int result, s, streams_accepted;
3286177a7f1SJef Poskanzer     fd_set read_set, write_set;
3298a0b5a5dSsethdelliott     struct iperf_stream *sp;
330ec2d0670SJef Poskanzer     struct timeval now;
331a951c980SBrian Tierney 
332e96ab740SJef Poskanzer     if (test->json_output)
333e96ab740SJef Poskanzer 	if (iperf_json_start(test) < 0)
334e96ab740SJef Poskanzer 	    return -1;
335e96ab740SJef Poskanzer 
336e96ab740SJef Poskanzer     if (test->json_output) {
337e96ab740SJef Poskanzer 	cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
338e96ab740SJef Poskanzer 	cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
339e96ab740SJef Poskanzer     } else if (test->verbose) {
340e96ab740SJef Poskanzer 	printf("%s\n", version);
341e96ab740SJef Poskanzer 	system("uname -a");
342e96ab740SJef Poskanzer     }
343e96ab740SJef Poskanzer 
344982c704aSsethdelliott     // Open socket and listen
345982c704aSsethdelliott     if (iperf_server_listen(test) < 0) {
346ec2d0670SJef Poskanzer         return -1;
347e99faeaeSBrian Tierney     }
348a951c980SBrian Tierney 
3493331e801Ssethdelliott     // Begin calculating CPU utilization
3503331e801Ssethdelliott     cpu_util(NULL);
3513331e801Ssethdelliott 
352efdc02f7Ssethdelliott     test->state = IPERF_START;
353112a907cSsethdelliott     streams_accepted = 0;
354a951c980SBrian Tierney 
355ec2d0670SJef Poskanzer     (void) gettimeofday(&now, NULL);
356873952e3Ssethdelliott     while (test->state != IPERF_DONE) {
357982c704aSsethdelliott 
3586177a7f1SJef Poskanzer         memcpy(&read_set, &test->read_set, sizeof(fd_set));
3596177a7f1SJef Poskanzer         memcpy(&write_set, &test->write_set, sizeof(fd_set));
360982c704aSsethdelliott 
3616177a7f1SJef Poskanzer         result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now));
362982c704aSsethdelliott         if (result < 0 && errno != EINTR) {
363c9693599SJef Poskanzer 	    cleanup_server(test);
364b60a49ddSsethdelliott             i_errno = IESELECT;
365ec2d0670SJef Poskanzer             return -1;
366ec2d0670SJef Poskanzer         }
367ec2d0670SJef Poskanzer 	if (result > 0) {
3686177a7f1SJef Poskanzer             if (FD_ISSET(test->listener, &read_set)) {
369b68ac00eSsethdelliott                 if (test->state != CREATE_STREAMS) {
370465b565cSsethdelliott                     if (iperf_accept(test) < 0) {
371c9693599SJef Poskanzer 			cleanup_server(test);
372ec2d0670SJef Poskanzer                         return -1;
373982c704aSsethdelliott                     }
3746177a7f1SJef Poskanzer                     FD_CLR(test->listener, &read_set);
375982c704aSsethdelliott                 }
376b68ac00eSsethdelliott             }
3776177a7f1SJef Poskanzer             if (FD_ISSET(test->ctrl_sck, &read_set)) {
378c9693599SJef Poskanzer                 if (iperf_handle_message_server(test) < 0) {
379c9693599SJef Poskanzer 		    cleanup_server(test);
380ec2d0670SJef Poskanzer                     return -1;
381c9693599SJef Poskanzer 		}
3826177a7f1SJef Poskanzer                 FD_CLR(test->ctrl_sck, &read_set);
383982c704aSsethdelliott             }
384465b565cSsethdelliott 
385465b565cSsethdelliott             if (test->state == CREATE_STREAMS) {
3866177a7f1SJef Poskanzer                 if (FD_ISSET(test->prot_listener, &read_set)) {
3878a0b5a5dSsethdelliott 
388c9693599SJef Poskanzer                     if ((s = test->protocol->accept(test)) < 0) {
389c9693599SJef Poskanzer 			cleanup_server(test);
390ec2d0670SJef Poskanzer                         return -1;
391c9693599SJef Poskanzer 		    }
3928a0b5a5dSsethdelliott 
3938a0b5a5dSsethdelliott                     if (!is_closed(s)) {
39466ce7ad4Ssethdelliott                         sp = iperf_new_stream(test, s);
395c9693599SJef Poskanzer                         if (!sp) {
396c9693599SJef Poskanzer 			    cleanup_server(test);
397ec2d0670SJef Poskanzer                             return -1;
398c9693599SJef Poskanzer 			}
39966ce7ad4Ssethdelliott 
4008a0b5a5dSsethdelliott                         FD_SET(s, &test->read_set);
4018a0b5a5dSsethdelliott                         FD_SET(s, &test->write_set);
4028a0b5a5dSsethdelliott                         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
40366ce7ad4Ssethdelliott 
404112a907cSsethdelliott                         streams_accepted++;
4054df383f6Ssethdelliott                         if (test->on_new_stream)
4064df383f6Ssethdelliott                             test->on_new_stream(sp);
407b68ac00eSsethdelliott                     }
4086177a7f1SJef Poskanzer                     FD_CLR(test->prot_listener, &read_set);
409b68ac00eSsethdelliott                 }
4108a0b5a5dSsethdelliott 
411112a907cSsethdelliott                 if (streams_accepted == test->num_streams) {
41266ce7ad4Ssethdelliott                     if (test->protocol->id != Ptcp) {
4138a0b5a5dSsethdelliott                         FD_CLR(test->prot_listener, &test->read_set);
4148a0b5a5dSsethdelliott                         close(test->prot_listener);
41566ce7ad4Ssethdelliott                     } else {
4160bd8d9daSsethdelliott                         if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
41766ce7ad4Ssethdelliott                             FD_CLR(test->listener, &test->read_set);
41866ce7ad4Ssethdelliott                             close(test->listener);
419f99bd3b2Ssethdelliott                             if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
420c9693599SJef Poskanzer 				cleanup_server(test);
421b60a49ddSsethdelliott                                 i_errno = IELISTEN;
422ec2d0670SJef Poskanzer                                 return -1;
423c81883bfSsethdelliott                             }
42466ce7ad4Ssethdelliott                             test->listener = s;
425c81883bfSsethdelliott                             test->max_fd = (s > test->max_fd ? s : test->max_fd);
42666ce7ad4Ssethdelliott                             FD_SET(test->listener, &test->read_set);
427c81883bfSsethdelliott                         }
4288556db5dSsethdelliott                     }
4298a0b5a5dSsethdelliott                     test->prot_listener = -1;
430c9693599SJef Poskanzer 		    if (iperf_set_send_state(test, TEST_START) != 0) {
431c9693599SJef Poskanzer 			cleanup_server(test);
432ec2d0670SJef Poskanzer                         return -1;
433982c704aSsethdelliott 		    }
434c9693599SJef Poskanzer                     if (iperf_init_test(test) < 0) {
435c9693599SJef Poskanzer 			cleanup_server(test);
436ec2d0670SJef Poskanzer                         return -1;
437c9693599SJef Poskanzer 		    }
43857892604SJef Poskanzer 		    if (create_server_omit_timer(test) < 0) {
439c9693599SJef Poskanzer 			cleanup_server(test);
440c9693599SJef Poskanzer                         return -1;
441c9693599SJef Poskanzer 		    }
4428bdc8fffSJef Poskanzer 		    if (test->reverse)
4438bdc8fffSJef Poskanzer 			if (iperf_create_send_timers(test) < 0) {
4448bdc8fffSJef Poskanzer 			    cleanup_server(test);
4458bdc8fffSJef Poskanzer 			    return -1;
4468bdc8fffSJef Poskanzer 			}
447c9693599SJef Poskanzer 		    if (iperf_set_send_state(test, TEST_RUNNING) != 0) {
448c9693599SJef Poskanzer 			cleanup_server(test);
449ec2d0670SJef Poskanzer                         return -1;
450f1b3bd81Ssethdelliott 		    }
451982c704aSsethdelliott                 }
452982c704aSsethdelliott             }
453982c704aSsethdelliott 
454f1b3bd81Ssethdelliott             if (test->state == TEST_RUNNING) {
455465b565cSsethdelliott                 if (test->reverse) {
456465b565cSsethdelliott                     // Reverse mode. Server sends.
457c9693599SJef Poskanzer                     if (iperf_send(test, &write_set) < 0) {
458c9693599SJef Poskanzer 			cleanup_server(test);
459ec2d0670SJef Poskanzer                         return -1;
460c9693599SJef Poskanzer 		    }
461982c704aSsethdelliott                 } else {
462465b565cSsethdelliott                     // Regular mode. Server receives.
463c9693599SJef Poskanzer                     if (iperf_recv(test, &read_set) < 0) {
464c9693599SJef Poskanzer 			cleanup_server(test);
465ec2d0670SJef Poskanzer                         return -1;
466e99faeaeSBrian Tierney 		    }
467c9693599SJef Poskanzer                 }
468f1b3bd81Ssethdelliott 
469ec2d0670SJef Poskanzer 		/* Run the timers. */
470ec2d0670SJef Poskanzer 		(void) gettimeofday(&now, NULL);
471ec2d0670SJef Poskanzer 		tmr_run(&now);
472f1b3bd81Ssethdelliott             }
473a951c980SBrian Tierney         }
474982c704aSsethdelliott     }
475e99faeaeSBrian Tierney 
476c9693599SJef Poskanzer     cleanup_server(test);
477efdc02f7Ssethdelliott 
478e96ab740SJef Poskanzer     if (test->json_output) {
479e96ab740SJef Poskanzer 	if (iperf_json_finish(test) < 0)
480e96ab740SJef Poskanzer 	    return -1;
481e96ab740SJef Poskanzer     }
482e96ab740SJef Poskanzer 
483ec2d0670SJef Poskanzer     return 0;
484a3281a3dSBrian Tierney }
485