xref: /iperf/src/iperf_server_api.c (revision d611f13e)
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 {
50f99bd3b2Ssethdelliott     if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
51b60a49ddSsethdelliott         i_errno = IELISTEN;
52ec2d0670SJef Poskanzer         return -1;
53982c704aSsethdelliott     }
54982c704aSsethdelliott 
559bfb54c0SJef Poskanzer     if (!test->json_output) {
56982c704aSsethdelliott 	printf("-----------------------------------------------------------\n");
57982c704aSsethdelliott 	printf("Server listening on %d\n", test->server_port);
589bfb54c0SJef Poskanzer     }
59982c704aSsethdelliott 
60982c704aSsethdelliott     // This needs to be changed to reflect if client has different window size
61982c704aSsethdelliott     // make sure we got what we asked for
62ba2672a2Ssethdelliott     /* XXX: This needs to be moved to the stream listener
6366ce7ad4Ssethdelliott     if ((x = get_tcp_windowsize(test->listener, SO_RCVBUF)) < 0) {
64982c704aSsethdelliott         // Needs to set some sort of error number/message
65982c704aSsethdelliott         perror("SO_RCVBUF");
66982c704aSsethdelliott         return -1;
67982c704aSsethdelliott     }
68ba2672a2Ssethdelliott     */
69982c704aSsethdelliott 
70ba2672a2Ssethdelliott     // XXX: This code needs to be moved to after parameter exhange
71c81883bfSsethdelliott     /*
7298ce496bSjef     char ubuf[UNIT_LEN];
7398ce496bSjef     int x;
7498ce496bSjef 
7566ce7ad4Ssethdelliott     if (test->protocol->id == Ptcp) {
76112a907cSsethdelliott         if (test->settings->socket_bufsize > 0) {
77982c704aSsethdelliott             unit_snprintf(ubuf, UNIT_LEN, (double) x, 'A');
789bfb54c0SJef Poskanzer 	    if (test->json_output)
79982c704aSsethdelliott 		printf("TCP window size: %s\n", ubuf);
80982c704aSsethdelliott         } else {
819bfb54c0SJef Poskanzer 	    if (test->json_output)
82982c704aSsethdelliott 		printf("Using TCP Autotuning\n");
83982c704aSsethdelliott         }
84982c704aSsethdelliott     }
85c81883bfSsethdelliott     */
869bfb54c0SJef Poskanzer     if (!test->json_output)
87982c704aSsethdelliott 	printf("-----------------------------------------------------------\n");
88982c704aSsethdelliott 
89982c704aSsethdelliott     FD_ZERO(&test->read_set);
90efdc02f7Ssethdelliott     FD_ZERO(&test->write_set);
9166ce7ad4Ssethdelliott     FD_SET(test->listener, &test->read_set);
9266ce7ad4Ssethdelliott     test->max_fd = (test->listener > test->max_fd) ? test->listener : test->max_fd;
93982c704aSsethdelliott 
94982c704aSsethdelliott     return 0;
95982c704aSsethdelliott }
96982c704aSsethdelliott 
97982c704aSsethdelliott int
98982c704aSsethdelliott iperf_accept(struct iperf_test *test)
99982c704aSsethdelliott {
100982c704aSsethdelliott     int s;
101465b565cSsethdelliott     int rbuf = ACCESS_DENIED;
102af70b448Ssethdelliott     char cookie[COOKIE_SIZE];
103982c704aSsethdelliott     socklen_t len;
10412d474e2SJef Poskanzer     struct sockaddr_storage addr;
105982c704aSsethdelliott 
106b68ac00eSsethdelliott     len = sizeof(addr);
10766ce7ad4Ssethdelliott     if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
108b60a49ddSsethdelliott         i_errno = IEACCEPT;
109ec2d0670SJef Poskanzer         return -1;
110982c704aSsethdelliott     }
111af70b448Ssethdelliott 
112af70b448Ssethdelliott     if (test->ctrl_sck == -1) {
113af70b448Ssethdelliott         /* Server free, accept new client */
114112a907cSsethdelliott         if (Nread(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
115b60a49ddSsethdelliott             i_errno = IERECVCOOKIE;
116ec2d0670SJef Poskanzer             return -1;
117af70b448Ssethdelliott         }
118af70b448Ssethdelliott 
119465b565cSsethdelliott         FD_SET(s, &test->read_set);
120465b565cSsethdelliott         FD_SET(s, &test->write_set);
121465b565cSsethdelliott         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
122465b565cSsethdelliott         test->ctrl_sck = s;
123982c704aSsethdelliott 
124c9693599SJef Poskanzer 	if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0)
125ec2d0670SJef Poskanzer             return -1;
126b60a49ddSsethdelliott         if (iperf_exchange_parameters(test) < 0) {
127ec2d0670SJef Poskanzer             return -1;
128b60a49ddSsethdelliott         }
1294df383f6Ssethdelliott         if (test->on_connect) {
1304df383f6Ssethdelliott             test->on_connect(test);
1314df383f6Ssethdelliott         }
132982c704aSsethdelliott     } else {
133111645edSJef Poskanzer         /* XXX: Do we even need to receive cookie if we're just going to deny anyways? */
134af70b448Ssethdelliott         if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
135b60a49ddSsethdelliott             i_errno = IERECVCOOKIE;
136ec2d0670SJef Poskanzer             return -1;
137465b565cSsethdelliott         }
138987b4323SJef Poskanzer         if (Nwrite(s, (char*) &rbuf, sizeof(int), Ptcp) < 0) {
139b60a49ddSsethdelliott             i_errno = IESENDMESSAGE;
140ec2d0670SJef Poskanzer             return -1;
141465b565cSsethdelliott         }
142465b565cSsethdelliott         close(s);
143982c704aSsethdelliott     }
144982c704aSsethdelliott 
145ec2d0670SJef Poskanzer     return 0;
146af70b448Ssethdelliott }
147af70b448Ssethdelliott 
148b68ac00eSsethdelliott 
149a951c980SBrian Tierney /**************************************************************************/
150982c704aSsethdelliott int
151465b565cSsethdelliott iperf_handle_message_server(struct iperf_test *test)
152982c704aSsethdelliott {
153b68ac00eSsethdelliott     int rval;
154efdc02f7Ssethdelliott     struct iperf_stream *sp;
155efdc02f7Ssethdelliott 
156b60a49ddSsethdelliott     // XXX: Need to rethink how this behaves to fit API
157b60a49ddSsethdelliott     if ((rval = Nread(test->ctrl_sck, &test->state, sizeof(char), Ptcp)) <= 0) {
158b68ac00eSsethdelliott         if (rval == 0) {
159b5e0751fSJef Poskanzer 	    iperf_err(test, "the client has unexpectedly closed the connection");
160b60a49ddSsethdelliott             i_errno = IECTRLCLOSE;
161b68ac00eSsethdelliott             test->state = IPERF_DONE;
162ec2d0670SJef Poskanzer             return 0;
163b68ac00eSsethdelliott         } else {
164b60a49ddSsethdelliott             i_errno = IERECVMESSAGE;
165ec2d0670SJef Poskanzer             return -1;
166982c704aSsethdelliott         }
167b68ac00eSsethdelliott     }
168982c704aSsethdelliott 
169982c704aSsethdelliott     switch(test->state) {
170ba2672a2Ssethdelliott         case TEST_START:
171ba2672a2Ssethdelliott             break;
172465b565cSsethdelliott         case TEST_END:
1733331e801Ssethdelliott             cpu_util(&test->cpu_util);
174f1b3bd81Ssethdelliott             test->stats_callback(test);
175dd4bc008Ssethdelliott             SLIST_FOREACH(sp, &test->streams, streams) {
176efdc02f7Ssethdelliott                 FD_CLR(sp->socket, &test->read_set);
177efdc02f7Ssethdelliott                 FD_CLR(sp->socket, &test->write_set);
178efdc02f7Ssethdelliott                 close(sp->socket);
179efdc02f7Ssethdelliott             }
180c9693599SJef Poskanzer 	    if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0)
181ec2d0670SJef Poskanzer                 return -1;
18269bdbfd3SJef Poskanzer             if (iperf_sum_results(test) < 0)
18369bdbfd3SJef Poskanzer                 return -1;
184b60a49ddSsethdelliott             if (iperf_exchange_results(test) < 0)
185ec2d0670SJef Poskanzer                 return -1;
186c9693599SJef Poskanzer 	    if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0)
187ec2d0670SJef Poskanzer                 return -1;
1884df383f6Ssethdelliott             if (test->on_test_finish)
1894df383f6Ssethdelliott                 test->on_test_finish(test);
190181d61afSsethdelliott             test->reporter_callback(test);
191465b565cSsethdelliott             break;
192873952e3Ssethdelliott         case IPERF_DONE:
193873952e3Ssethdelliott             break;
194465b565cSsethdelliott         case CLIENT_TERMINATE:
195ffdcc7d4Ssethdelliott             i_errno = IECLIENTTERM;
196ffdcc7d4Ssethdelliott 
197ffdcc7d4Ssethdelliott             // XXX: Remove this line below!
198b5e0751fSJef Poskanzer 	    iperf_err(test, "the client has terminated");
199dd4bc008Ssethdelliott             SLIST_FOREACH(sp, &test->streams, streams) {
2001ac522ecSsethdelliott                 FD_CLR(sp->socket, &test->read_set);
2011ac522ecSsethdelliott                 FD_CLR(sp->socket, &test->write_set);
2021ac522ecSsethdelliott                 close(sp->socket);
2031ac522ecSsethdelliott             }
2041ac522ecSsethdelliott             test->state = IPERF_DONE;
2051ac522ecSsethdelliott             break;
206ba2672a2Ssethdelliott         default:
207b60a49ddSsethdelliott             i_errno = IEMESSAGE;
208ec2d0670SJef Poskanzer             return -1;
209982c704aSsethdelliott     }
210982c704aSsethdelliott 
211ec2d0670SJef Poskanzer     return 0;
212982c704aSsethdelliott }
213982c704aSsethdelliott 
2140bd8d9daSsethdelliott /* XXX: This function is not used anymore */
215efdc02f7Ssethdelliott void
216efdc02f7Ssethdelliott iperf_test_reset(struct iperf_test *test)
217efdc02f7Ssethdelliott {
2180bd8d9daSsethdelliott     struct iperf_stream *sp;
219efdc02f7Ssethdelliott 
220efdc02f7Ssethdelliott     close(test->ctrl_sck);
221efdc02f7Ssethdelliott 
222efdc02f7Ssethdelliott     /* Free streams */
223dd4bc008Ssethdelliott     while (!SLIST_EMPTY(&test->streams)) {
224dd4bc008Ssethdelliott         sp = SLIST_FIRST(&test->streams);
225dd4bc008Ssethdelliott         SLIST_REMOVE_HEAD(&test->streams, streams);
226dd4bc008Ssethdelliott         iperf_free_stream(sp);
227dd4bc008Ssethdelliott     }
228ec2d0670SJef Poskanzer     if (test->timer != NULL) {
229ec2d0670SJef Poskanzer 	tmr_cancel(test->timer);
230f1b3bd81Ssethdelliott 	test->timer = NULL;
231ec2d0670SJef Poskanzer     }
232ec2d0670SJef Poskanzer     if (test->stats_timer != NULL) {
233ec2d0670SJef Poskanzer 	tmr_cancel(test->stats_timer);
234f1b3bd81Ssethdelliott 	test->stats_timer = NULL;
235ec2d0670SJef Poskanzer     }
236ec2d0670SJef Poskanzer     if (test->reporter_timer != NULL) {
237ec2d0670SJef Poskanzer 	tmr_cancel(test->reporter_timer);
238f1b3bd81Ssethdelliott 	test->reporter_timer = NULL;
239ec2d0670SJef Poskanzer     }
240efdc02f7Ssethdelliott 
241dd4bc008Ssethdelliott     SLIST_INIT(&test->streams);
24232885561Ssethdelliott 
243efdc02f7Ssethdelliott     test->role = 's';
24466ce7ad4Ssethdelliott     set_protocol(test, Ptcp);
24557892604SJef Poskanzer     test->omit = OMIT;
24632885561Ssethdelliott     test->duration = DURATION;
24732885561Ssethdelliott     test->state = 0;
24832885561Ssethdelliott     test->server_hostname = NULL;
24932885561Ssethdelliott 
25032885561Ssethdelliott     test->ctrl_sck = -1;
25166ce7ad4Ssethdelliott     test->prot_listener = -1;
25232885561Ssethdelliott 
253f1b3bd81Ssethdelliott     test->bytes_sent = 0;
254f1b3bd81Ssethdelliott 
25532885561Ssethdelliott     test->reverse = 0;
2562c042fd4SJef Poskanzer     test->sender = 0;
25769bdbfd3SJef Poskanzer     test->sender_has_retransmits = 0;
258b68ac00eSsethdelliott     test->no_delay = 0;
25932885561Ssethdelliott 
260efdc02f7Ssethdelliott     FD_ZERO(&test->read_set);
261efdc02f7Ssethdelliott     FD_ZERO(&test->write_set);
26266ce7ad4Ssethdelliott     FD_SET(test->listener, &test->read_set);
26366ce7ad4Ssethdelliott     test->max_fd = test->listener;
26432885561Ssethdelliott 
26532885561Ssethdelliott     test->num_streams = 1;
266112a907cSsethdelliott     test->settings->socket_bufsize = 0;
267112a907cSsethdelliott     test->settings->blksize = DEFAULT_TCP_BLKSIZE;
268*d611f13eSJef Poskanzer     test->settings->rate = 0;
269112a907cSsethdelliott     test->settings->mss = 0;
270112a907cSsethdelliott     memset(test->cookie, 0, COOKIE_SIZE);
271efdc02f7Ssethdelliott }
272efdc02f7Ssethdelliott 
273c9693599SJef Poskanzer static void
27457892604SJef Poskanzer server_omit_timer_proc(TimerClientData client_data, struct timeval *nowP)
275c9693599SJef Poskanzer {
276c9693599SJef Poskanzer     struct iperf_test *test = client_data.p;
277c9693599SJef Poskanzer 
27857892604SJef Poskanzer     test->omit_timer = NULL;
27957892604SJef Poskanzer     test->omitting = 0;
280c9693599SJef Poskanzer     iperf_reset_stats(test);
281c9693599SJef Poskanzer     if (test->verbose && !test->json_output)
28257892604SJef Poskanzer 	printf("Finished omit period, starting real test\n");
283c9693599SJef Poskanzer }
284c9693599SJef Poskanzer 
285c9693599SJef Poskanzer static int
28657892604SJef Poskanzer create_server_omit_timer(struct iperf_test * test)
287c9693599SJef Poskanzer {
288c9693599SJef Poskanzer     struct timeval now;
289c9693599SJef Poskanzer     TimerClientData cd;
290c9693599SJef Poskanzer 
291c9693599SJef Poskanzer     if (gettimeofday(&now, NULL) < 0) {
292c9693599SJef Poskanzer 	i_errno = IEINITTEST;
293c9693599SJef Poskanzer 	return -1;
294c9693599SJef Poskanzer     }
29557892604SJef Poskanzer     test->omitting = 1;
296c9693599SJef Poskanzer     cd.p = test;
29757892604SJef Poskanzer     test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
29857892604SJef Poskanzer     if (test->omit_timer == NULL) {
299c9693599SJef Poskanzer 	i_errno = IEINITTEST;
300c9693599SJef Poskanzer 	return -1;
301c9693599SJef Poskanzer     }
302c9693599SJef Poskanzer     return 0;
303c9693599SJef Poskanzer }
304c9693599SJef Poskanzer 
305c9693599SJef Poskanzer static void
306c9693599SJef Poskanzer cleanup_server(struct iperf_test *test)
307c9693599SJef Poskanzer {
308c9693599SJef Poskanzer     /* Close open test sockets */
309c9693599SJef Poskanzer     close(test->ctrl_sck);
310c9693599SJef Poskanzer     close(test->listener);
311c9693599SJef Poskanzer }
312c9693599SJef Poskanzer 
3137fa9f68fSsethdelliott int
314a951c980SBrian Tierney iperf_run_server(struct iperf_test *test)
315a951c980SBrian Tierney {
316112a907cSsethdelliott     int result, s, streams_accepted;
3176177a7f1SJef Poskanzer     fd_set read_set, write_set;
3188a0b5a5dSsethdelliott     struct iperf_stream *sp;
319ec2d0670SJef Poskanzer     struct timeval now;
320a951c980SBrian Tierney 
321e96ab740SJef Poskanzer     if (test->json_output)
322e96ab740SJef Poskanzer 	if (iperf_json_start(test) < 0)
323e96ab740SJef Poskanzer 	    return -1;
324e96ab740SJef Poskanzer 
325e96ab740SJef Poskanzer     if (test->json_output) {
326e96ab740SJef Poskanzer 	cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
327e96ab740SJef Poskanzer 	cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
328e96ab740SJef Poskanzer     } else if (test->verbose) {
329e96ab740SJef Poskanzer 	printf("%s\n", version);
330e96ab740SJef Poskanzer 	system("uname -a");
331e96ab740SJef Poskanzer     }
332e96ab740SJef Poskanzer 
333982c704aSsethdelliott     // Open socket and listen
334982c704aSsethdelliott     if (iperf_server_listen(test) < 0) {
335ec2d0670SJef Poskanzer         return -1;
336e99faeaeSBrian Tierney     }
337a951c980SBrian Tierney 
3383331e801Ssethdelliott     // Begin calculating CPU utilization
3393331e801Ssethdelliott     cpu_util(NULL);
3403331e801Ssethdelliott 
341efdc02f7Ssethdelliott     test->state = IPERF_START;
342112a907cSsethdelliott     streams_accepted = 0;
343a951c980SBrian Tierney 
344ec2d0670SJef Poskanzer     (void) gettimeofday(&now, NULL);
345873952e3Ssethdelliott     while (test->state != IPERF_DONE) {
346982c704aSsethdelliott 
3476177a7f1SJef Poskanzer         memcpy(&read_set, &test->read_set, sizeof(fd_set));
3486177a7f1SJef Poskanzer         memcpy(&write_set, &test->write_set, sizeof(fd_set));
349982c704aSsethdelliott 
3506177a7f1SJef Poskanzer         result = select(test->max_fd + 1, &read_set, &write_set, NULL, tmr_timeout(&now));
351982c704aSsethdelliott         if (result < 0 && errno != EINTR) {
352c9693599SJef Poskanzer 	    cleanup_server(test);
353b60a49ddSsethdelliott             i_errno = IESELECT;
354ec2d0670SJef Poskanzer             return -1;
355ec2d0670SJef Poskanzer         }
356ec2d0670SJef Poskanzer 	if (result > 0) {
3576177a7f1SJef Poskanzer             if (FD_ISSET(test->listener, &read_set)) {
358b68ac00eSsethdelliott                 if (test->state != CREATE_STREAMS) {
359465b565cSsethdelliott                     if (iperf_accept(test) < 0) {
360c9693599SJef Poskanzer 			cleanup_server(test);
361ec2d0670SJef Poskanzer                         return -1;
362982c704aSsethdelliott                     }
3636177a7f1SJef Poskanzer                     FD_CLR(test->listener, &read_set);
364982c704aSsethdelliott                 }
365b68ac00eSsethdelliott             }
3666177a7f1SJef Poskanzer             if (FD_ISSET(test->ctrl_sck, &read_set)) {
367c9693599SJef Poskanzer                 if (iperf_handle_message_server(test) < 0) {
368c9693599SJef Poskanzer 		    cleanup_server(test);
369ec2d0670SJef Poskanzer                     return -1;
370c9693599SJef Poskanzer 		}
3716177a7f1SJef Poskanzer                 FD_CLR(test->ctrl_sck, &read_set);
372982c704aSsethdelliott             }
373465b565cSsethdelliott 
374465b565cSsethdelliott             if (test->state == CREATE_STREAMS) {
3756177a7f1SJef Poskanzer                 if (FD_ISSET(test->prot_listener, &read_set)) {
3768a0b5a5dSsethdelliott 
377c9693599SJef Poskanzer                     if ((s = test->protocol->accept(test)) < 0) {
378c9693599SJef Poskanzer 			cleanup_server(test);
379ec2d0670SJef Poskanzer                         return -1;
380c9693599SJef Poskanzer 		    }
3818a0b5a5dSsethdelliott 
3828a0b5a5dSsethdelliott                     if (!is_closed(s)) {
38366ce7ad4Ssethdelliott                         sp = iperf_new_stream(test, s);
384c9693599SJef Poskanzer                         if (!sp) {
385c9693599SJef Poskanzer 			    cleanup_server(test);
386ec2d0670SJef Poskanzer                             return -1;
387c9693599SJef Poskanzer 			}
38866ce7ad4Ssethdelliott 
3898a0b5a5dSsethdelliott                         FD_SET(s, &test->read_set);
3908a0b5a5dSsethdelliott                         FD_SET(s, &test->write_set);
3918a0b5a5dSsethdelliott                         test->max_fd = (s > test->max_fd) ? s : test->max_fd;
39266ce7ad4Ssethdelliott 
393112a907cSsethdelliott                         streams_accepted++;
3944df383f6Ssethdelliott                         if (test->on_new_stream)
3954df383f6Ssethdelliott                             test->on_new_stream(sp);
396b68ac00eSsethdelliott                     }
3976177a7f1SJef Poskanzer                     FD_CLR(test->prot_listener, &read_set);
398b68ac00eSsethdelliott                 }
3998a0b5a5dSsethdelliott 
400112a907cSsethdelliott                 if (streams_accepted == test->num_streams) {
40166ce7ad4Ssethdelliott                     if (test->protocol->id != Ptcp) {
4028a0b5a5dSsethdelliott                         FD_CLR(test->prot_listener, &test->read_set);
4038a0b5a5dSsethdelliott                         close(test->prot_listener);
40466ce7ad4Ssethdelliott                     } else {
4050bd8d9daSsethdelliott                         if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
40666ce7ad4Ssethdelliott                             FD_CLR(test->listener, &test->read_set);
40766ce7ad4Ssethdelliott                             close(test->listener);
408f99bd3b2Ssethdelliott                             if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->server_port)) < 0) {
409c9693599SJef Poskanzer 				cleanup_server(test);
410b60a49ddSsethdelliott                                 i_errno = IELISTEN;
411ec2d0670SJef Poskanzer                                 return -1;
412c81883bfSsethdelliott                             }
41366ce7ad4Ssethdelliott                             test->listener = s;
414c81883bfSsethdelliott                             test->max_fd = (s > test->max_fd ? s : test->max_fd);
41566ce7ad4Ssethdelliott                             FD_SET(test->listener, &test->read_set);
416c81883bfSsethdelliott                         }
4178556db5dSsethdelliott                     }
4188a0b5a5dSsethdelliott                     test->prot_listener = -1;
419c9693599SJef Poskanzer 		    if (iperf_set_send_state(test, TEST_START) != 0) {
420c9693599SJef Poskanzer 			cleanup_server(test);
421ec2d0670SJef Poskanzer                         return -1;
422982c704aSsethdelliott 		    }
423c9693599SJef Poskanzer                     if (iperf_init_test(test) < 0) {
424c9693599SJef Poskanzer 			cleanup_server(test);
425ec2d0670SJef Poskanzer                         return -1;
426c9693599SJef Poskanzer 		    }
42757892604SJef Poskanzer 		    if (create_server_omit_timer(test) < 0) {
428c9693599SJef Poskanzer 			cleanup_server(test);
429c9693599SJef Poskanzer                         return -1;
430c9693599SJef Poskanzer 		    }
431c9693599SJef Poskanzer 		    if (iperf_set_send_state(test, TEST_RUNNING) != 0) {
432c9693599SJef Poskanzer 			cleanup_server(test);
433ec2d0670SJef Poskanzer                         return -1;
434f1b3bd81Ssethdelliott 		    }
435982c704aSsethdelliott                 }
436982c704aSsethdelliott             }
437982c704aSsethdelliott 
438f1b3bd81Ssethdelliott             if (test->state == TEST_RUNNING) {
439465b565cSsethdelliott                 if (test->reverse) {
440465b565cSsethdelliott                     // Reverse mode. Server sends.
441c9693599SJef Poskanzer                     if (iperf_send(test, &write_set) < 0) {
442c9693599SJef Poskanzer 			cleanup_server(test);
443ec2d0670SJef Poskanzer                         return -1;
444c9693599SJef Poskanzer 		    }
445982c704aSsethdelliott                 } else {
446465b565cSsethdelliott                     // Regular mode. Server receives.
447c9693599SJef Poskanzer                     if (iperf_recv(test, &read_set) < 0) {
448c9693599SJef Poskanzer 			cleanup_server(test);
449ec2d0670SJef Poskanzer                         return -1;
450e99faeaeSBrian Tierney 		    }
451c9693599SJef Poskanzer                 }
452f1b3bd81Ssethdelliott 
453ec2d0670SJef Poskanzer 		/* Run the timers. */
454ec2d0670SJef Poskanzer 		(void) gettimeofday(&now, NULL);
455ec2d0670SJef Poskanzer 		tmr_run(&now);
456f1b3bd81Ssethdelliott             }
457a951c980SBrian Tierney         }
458982c704aSsethdelliott     }
459e99faeaeSBrian Tierney 
460c9693599SJef Poskanzer     cleanup_server(test);
461efdc02f7Ssethdelliott 
462e96ab740SJef Poskanzer     if (test->json_output) {
463e96ab740SJef Poskanzer 	if (iperf_json_finish(test) < 0)
464e96ab740SJef Poskanzer 	    return -1;
465e96ab740SJef Poskanzer     }
466e96ab740SJef Poskanzer 
467ec2d0670SJef Poskanzer     return 0;
468a3281a3dSBrian Tierney }
469