1a951c980SBrian Tierney /*
2ce010040SBruce A. Mah * iperf, Copyright (c) 2014-2022 The Regents of the University of
3da9f046fSBruce A. Mah * California, through Lawrence Berkeley National Laboratory (subject
4da9f046fSBruce A. Mah * to receipt of any required approvals from the U.S. Dept. of
5da9f046fSBruce A. Mah * Energy). All rights reserved.
67d375156SJon Dugan *
7da9f046fSBruce A. Mah * If you have questions about your rights to use or distribute this
8da9f046fSBruce A. Mah * software, please contact Berkeley Lab's Technology Transfer
9da9f046fSBruce A. Mah * Department at [email protected].
10da9f046fSBruce A. Mah *
11da9f046fSBruce A. Mah * NOTICE. This software is owned by the U.S. Department of Energy.
12da9f046fSBruce A. Mah * As such, the U.S. Government has been granted for itself and others
13da9f046fSBruce A. Mah * acting on its behalf a paid-up, nonexclusive, irrevocable,
14da9f046fSBruce A. Mah * worldwide license in the Software to reproduce, prepare derivative
15da9f046fSBruce A. Mah * works, and perform publicly and display publicly. Beginning five
16da9f046fSBruce A. Mah * (5) years after the date permission to assert copyright is obtained
17da9f046fSBruce A. Mah * from the U.S. Department of Energy, and subject to any subsequent
18da9f046fSBruce A. Mah * five (5) year renewals, the U.S. Government is granted for itself
19da9f046fSBruce A. Mah * and others acting on its behalf a paid-up, nonexclusive,
20da9f046fSBruce A. Mah * irrevocable, worldwide license in the Software to reproduce,
21da9f046fSBruce A. Mah * prepare derivative works, distribute copies to the public, perform
22da9f046fSBruce A. Mah * publicly and display publicly, and to permit others to do so.
23da9f046fSBruce A. Mah *
24da9f046fSBruce A. Mah * This code is distributed under a BSD style license, see the LICENSE
25da9f046fSBruce A. Mah * file for complete information.
26a951c980SBrian Tierney */
27a951c980SBrian Tierney /* iperf_server_api.c: Functions to be used by an iperf server
28a951c980SBrian Tierney */
29a951c980SBrian Tierney
30a951c980SBrian Tierney #include <stdio.h>
31a951c980SBrian Tierney #include <stdlib.h>
32a951c980SBrian Tierney #include <string.h>
33a951c980SBrian Tierney #include <getopt.h>
34a951c980SBrian Tierney #include <errno.h>
35a951c980SBrian Tierney #include <unistd.h>
36a951c980SBrian Tierney #include <assert.h>
37a951c980SBrian Tierney #include <fcntl.h>
38a951c980SBrian Tierney #include <sys/socket.h>
39a951c980SBrian Tierney #include <sys/types.h>
40a951c980SBrian Tierney #include <netinet/in.h>
41a951c980SBrian Tierney #include <arpa/inet.h>
42a951c980SBrian Tierney #include <netdb.h>
43426221a3SBruce A. Mah #ifdef HAVE_STDINT_H
44a951c980SBrian Tierney #include <stdint.h>
45426221a3SBruce A. Mah #endif
46a951c980SBrian Tierney #include <sys/time.h>
47a951c980SBrian Tierney #include <sys/resource.h>
48a951c980SBrian Tierney #include <sched.h>
49a951c980SBrian Tierney #include <setjmp.h>
50a951c980SBrian Tierney
51a951c980SBrian Tierney #include "iperf.h"
52a951c980SBrian Tierney #include "iperf_api.h"
53a951c980SBrian Tierney #include "iperf_udp.h"
54a951c980SBrian Tierney #include "iperf_tcp.h"
558a0b5a5dSsethdelliott #include "iperf_util.h"
56a951c980SBrian Tierney #include "timer.h"
57cde81d76SBen Fox-Moore #include "iperf_time.h"
58a951c980SBrian Tierney #include "net.h"
59a951c980SBrian Tierney #include "units.h"
60b0b16b86SJon Dugan #include "iperf_util.h"
61a1861d5fSBruce A. Mah #include "iperf_locale.h"
62a951c980SBrian Tierney
637eeaa1cbSBruce A. Mah #if defined(HAVE_TCP_CONGESTION)
647eeaa1cbSBruce A. Mah #if !defined(TCP_CA_NAME_MAX)
657eeaa1cbSBruce A. Mah #define TCP_CA_NAME_MAX 16
667eeaa1cbSBruce A. Mah #endif /* TCP_CA_NAME_MAX */
677eeaa1cbSBruce A. Mah #endif /* HAVE_TCP_CONGESTION */
68a3281a3dSBrian Tierney
69982c704aSsethdelliott int
iperf_server_listen(struct iperf_test * test)70982c704aSsethdelliott iperf_server_listen(struct iperf_test *test)
71982c704aSsethdelliott {
725c01581bSJef Poskanzer retry:
7321581a72SBruce A. Mah if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) {
745c01581bSJef Poskanzer if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) {
755c01581bSJef Poskanzer /* If we get "Address family not supported by protocol", that
765c01581bSJef Poskanzer ** probably means we were compiled with IPv6 but the running
775c01581bSJef Poskanzer ** kernel does not actually do IPv6. This is not too unusual,
785c01581bSJef Poskanzer ** v6 support is and perhaps always will be spotty.
795c01581bSJef Poskanzer */
805c01581bSJef Poskanzer warning("this system does not seem to support IPv6 - trying IPv4");
815c01581bSJef Poskanzer test->settings->domain = AF_INET;
825c01581bSJef Poskanzer goto retry;
835c01581bSJef Poskanzer } else {
84b60a49ddSsethdelliott i_errno = IELISTEN;
85ec2d0670SJef Poskanzer return -1;
86982c704aSsethdelliott }
875c01581bSJef Poskanzer }
88982c704aSsethdelliott
899bfb54c0SJef Poskanzer if (!test->json_output) {
90be66b575SDavid Bar-On if (test->server_last_run_rc != 2)
91be66b575SDavid Bar-On test->server_test_number +=1;
92be66b575SDavid Bar-On if (test->debug || test->server_last_run_rc != 2) {
93ad2a706fSNevo Hed iperf_printf(test, "-----------------------------------------------------------\n");
94be66b575SDavid Bar-On iperf_printf(test, "Server listening on %d (test #%d)\n", test->server_port, test->server_test_number);
95ad2a706fSNevo Hed iperf_printf(test, "-----------------------------------------------------------\n");
96af34c411SBruce A. Mah if (test->forceflush)
97af34c411SBruce A. Mah iflush(test);
98af34c411SBruce A. Mah }
99be66b575SDavid Bar-On }
100982c704aSsethdelliott
101982c704aSsethdelliott FD_ZERO(&test->read_set);
102efdc02f7Ssethdelliott FD_ZERO(&test->write_set);
10366ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set);
104082cbb0eSJef Poskanzer if (test->listener > test->max_fd) test->max_fd = test->listener;
105982c704aSsethdelliott
106982c704aSsethdelliott return 0;
107982c704aSsethdelliott }
108982c704aSsethdelliott
109982c704aSsethdelliott int
iperf_accept(struct iperf_test * test)110982c704aSsethdelliott iperf_accept(struct iperf_test *test)
111982c704aSsethdelliott {
112982c704aSsethdelliott int s;
1134e2ef507SJef Poskanzer signed char rbuf = ACCESS_DENIED;
114982c704aSsethdelliott socklen_t len;
11512d474e2SJef Poskanzer struct sockaddr_storage addr;
116982c704aSsethdelliott
117b68ac00eSsethdelliott len = sizeof(addr);
11866ce7ad4Ssethdelliott if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
119b60a49ddSsethdelliott i_errno = IEACCEPT;
120ec2d0670SJef Poskanzer return -1;
121982c704aSsethdelliott }
122af70b448Ssethdelliott
123af70b448Ssethdelliott if (test->ctrl_sck == -1) {
124af70b448Ssethdelliott /* Server free, accept new client */
125082cbb0eSJef Poskanzer test->ctrl_sck = s;
12697a1d11aSBruce A. Mah // set TCP_NODELAY for lower latency on control messages
12797a1d11aSBruce A. Mah int flag = 1;
12897a1d11aSBruce A. Mah if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int))) {
12997a1d11aSBruce A. Mah i_errno = IESETNODELAY;
13097a1d11aSBruce A. Mah return -1;
13197a1d11aSBruce A. Mah }
13297a1d11aSBruce A. Mah
133*7bdd5b0eSDavid Bar-On #if defined(HAVE_TCP_USER_TIMEOUT)
134*7bdd5b0eSDavid Bar-On int opt;
135*7bdd5b0eSDavid Bar-On if ((opt = test->settings->snd_timeout)) {
136*7bdd5b0eSDavid Bar-On if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
137*7bdd5b0eSDavid Bar-On i_errno = IESETUSERTIMEOUT;
138*7bdd5b0eSDavid Bar-On return -1;
139*7bdd5b0eSDavid Bar-On }
140*7bdd5b0eSDavid Bar-On }
141*7bdd5b0eSDavid Bar-On #endif /* HAVE_TCP_USER_TIMEOUT */
142*7bdd5b0eSDavid Bar-On
143082cbb0eSJef Poskanzer if (Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
144b60a49ddSsethdelliott i_errno = IERECVCOOKIE;
145ec2d0670SJef Poskanzer return -1;
146af70b448Ssethdelliott }
147082cbb0eSJef Poskanzer FD_SET(test->ctrl_sck, &test->read_set);
148082cbb0eSJef Poskanzer if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;
149982c704aSsethdelliott
150c9693599SJef Poskanzer if (iperf_set_send_state(test, PARAM_EXCHANGE) != 0)
151ec2d0670SJef Poskanzer return -1;
1528bdc8fffSJef Poskanzer if (iperf_exchange_parameters(test) < 0)
153ec2d0670SJef Poskanzer return -1;
1548a7e01ebSJef Poskanzer if (test->server_affinity != -1)
155deefb95fSBruce A. Mah if (iperf_setaffinity(test, test->server_affinity) != 0)
1568a7e01ebSJef Poskanzer return -1;
1578bdc8fffSJef Poskanzer if (test->on_connect)
1584df383f6Ssethdelliott test->on_connect(test);
159982c704aSsethdelliott } else {
16040d45dcfSBruce A. Mah /*
16140d45dcfSBruce A. Mah * Don't try to read from the socket. It could block an ongoing test.
16240d45dcfSBruce A. Mah * Just send ACCESS_DENIED.
16327695dc4SDavid Bar-On * Also, if sending failed, don't return an error, as the request is not related
16427695dc4SDavid Bar-On * to the ongoing test, and returning an error will terminate the test.
16540d45dcfSBruce A. Mah */
1664e2ef507SJef Poskanzer if (Nwrite(s, (char*) &rbuf, sizeof(rbuf), Ptcp) < 0) {
16727695dc4SDavid Bar-On if (test->debug)
16850638f60SBruce A. Mah printf("failed to send ACCESS_DENIED to an unsolicited connection request during active test\n");
16927695dc4SDavid Bar-On } else {
17027695dc4SDavid Bar-On if (test->debug)
17150638f60SBruce A. Mah printf("successfully sent ACCESS_DENIED to an unsolicited connection request during active test\n");
172465b565cSsethdelliott }
173465b565cSsethdelliott close(s);
174982c704aSsethdelliott }
175982c704aSsethdelliott
176ec2d0670SJef Poskanzer return 0;
177af70b448Ssethdelliott }
178af70b448Ssethdelliott
179b68ac00eSsethdelliott
180a951c980SBrian Tierney /**************************************************************************/
181982c704aSsethdelliott int
iperf_handle_message_server(struct iperf_test * test)182465b565cSsethdelliott iperf_handle_message_server(struct iperf_test *test)
183982c704aSsethdelliott {
184b68ac00eSsethdelliott int rval;
185efdc02f7Ssethdelliott struct iperf_stream *sp;
186efdc02f7Ssethdelliott
187b60a49ddSsethdelliott // XXX: Need to rethink how this behaves to fit API
18801943402SJef Poskanzer if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp)) <= 0) {
189b68ac00eSsethdelliott if (rval == 0) {
190b5e0751fSJef Poskanzer iperf_err(test, "the client has unexpectedly closed the connection");
191b60a49ddSsethdelliott i_errno = IECTRLCLOSE;
192b68ac00eSsethdelliott test->state = IPERF_DONE;
193ec2d0670SJef Poskanzer return 0;
194b68ac00eSsethdelliott } else {
195b60a49ddSsethdelliott i_errno = IERECVMESSAGE;
196ec2d0670SJef Poskanzer return -1;
197982c704aSsethdelliott }
198b68ac00eSsethdelliott }
199982c704aSsethdelliott
200982c704aSsethdelliott switch(test->state) {
201ba2672a2Ssethdelliott case TEST_START:
202ba2672a2Ssethdelliott break;
203465b565cSsethdelliott case TEST_END:
204a4c1383aSJef Poskanzer test->done = 1;
205056361fcSJef Poskanzer cpu_util(test->cpu_util);
206f1b3bd81Ssethdelliott test->stats_callback(test);
207dd4bc008Ssethdelliott SLIST_FOREACH(sp, &test->streams, streams) {
208efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->read_set);
209efdc02f7Ssethdelliott FD_CLR(sp->socket, &test->write_set);
210efdc02f7Ssethdelliott close(sp->socket);
211efdc02f7Ssethdelliott }
21258243811SBruce A. Mah test->reporter_callback(test);
213c9693599SJef Poskanzer if (iperf_set_send_state(test, EXCHANGE_RESULTS) != 0)
214ec2d0670SJef Poskanzer return -1;
215b60a49ddSsethdelliott if (iperf_exchange_results(test) < 0)
216ec2d0670SJef Poskanzer return -1;
217c9693599SJef Poskanzer if (iperf_set_send_state(test, DISPLAY_RESULTS) != 0)
218ec2d0670SJef Poskanzer return -1;
2194df383f6Ssethdelliott if (test->on_test_finish)
2204df383f6Ssethdelliott test->on_test_finish(test);
221465b565cSsethdelliott break;
222873952e3Ssethdelliott case IPERF_DONE:
223873952e3Ssethdelliott break;
224465b565cSsethdelliott case CLIENT_TERMINATE:
225ffdcc7d4Ssethdelliott i_errno = IECLIENTTERM;
226ffdcc7d4Ssethdelliott
227c04bdcb9SBruce A. Mah // Temporarily be in DISPLAY_RESULTS phase so we can get
228c04bdcb9SBruce A. Mah // ending summary statistics.
229c04bdcb9SBruce A. Mah signed char oldstate = test->state;
230c04bdcb9SBruce A. Mah cpu_util(test->cpu_util);
231c04bdcb9SBruce A. Mah test->state = DISPLAY_RESULTS;
232c04bdcb9SBruce A. Mah test->reporter_callback(test);
233c04bdcb9SBruce A. Mah test->state = oldstate;
234c04bdcb9SBruce A. Mah
235ffdcc7d4Ssethdelliott // XXX: Remove this line below!
236b5e0751fSJef Poskanzer iperf_err(test, "the client has terminated");
237dd4bc008Ssethdelliott SLIST_FOREACH(sp, &test->streams, streams) {
2381ac522ecSsethdelliott FD_CLR(sp->socket, &test->read_set);
2391ac522ecSsethdelliott FD_CLR(sp->socket, &test->write_set);
2401ac522ecSsethdelliott close(sp->socket);
2411ac522ecSsethdelliott }
2421ac522ecSsethdelliott test->state = IPERF_DONE;
2431ac522ecSsethdelliott break;
244ba2672a2Ssethdelliott default:
245b60a49ddSsethdelliott i_errno = IEMESSAGE;
246ec2d0670SJef Poskanzer return -1;
247982c704aSsethdelliott }
248982c704aSsethdelliott
249ec2d0670SJef Poskanzer return 0;
250982c704aSsethdelliott }
251982c704aSsethdelliott
252c9693599SJef Poskanzer static void
server_timer_proc(TimerClientData client_data,struct iperf_time * nowP)253cde81d76SBen Fox-Moore server_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
254f7fd67d4Sdmdailey {
255f7fd67d4Sdmdailey struct iperf_test *test = client_data.p;
256f7fd67d4Sdmdailey struct iperf_stream *sp;
257f7fd67d4Sdmdailey
258f7fd67d4Sdmdailey test->timer = NULL;
259f7fd67d4Sdmdailey if (test->done)
260f7fd67d4Sdmdailey return;
261f7fd67d4Sdmdailey test->done = 1;
262f7fd67d4Sdmdailey /* Free streams */
263f7fd67d4Sdmdailey while (!SLIST_EMPTY(&test->streams)) {
264f7fd67d4Sdmdailey sp = SLIST_FIRST(&test->streams);
265f7fd67d4Sdmdailey SLIST_REMOVE_HEAD(&test->streams, streams);
266f7fd67d4Sdmdailey close(sp->socket);
267f7fd67d4Sdmdailey iperf_free_stream(sp);
268f7fd67d4Sdmdailey }
269f7fd67d4Sdmdailey close(test->ctrl_sck);
270f7fd67d4Sdmdailey }
271f7fd67d4Sdmdailey
272f7fd67d4Sdmdailey static void
server_stats_timer_proc(TimerClientData client_data,struct iperf_time * nowP)273cde81d76SBen Fox-Moore server_stats_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
27438917b1fSJef Poskanzer {
27538917b1fSJef Poskanzer struct iperf_test *test = client_data.p;
27638917b1fSJef Poskanzer
27738917b1fSJef Poskanzer if (test->done)
27838917b1fSJef Poskanzer return;
27938917b1fSJef Poskanzer if (test->stats_callback)
28038917b1fSJef Poskanzer test->stats_callback(test);
28138917b1fSJef Poskanzer }
28238917b1fSJef Poskanzer
28338917b1fSJef Poskanzer static void
server_reporter_timer_proc(TimerClientData client_data,struct iperf_time * nowP)284cde81d76SBen Fox-Moore server_reporter_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
28538917b1fSJef Poskanzer {
28638917b1fSJef Poskanzer struct iperf_test *test = client_data.p;
28738917b1fSJef Poskanzer
28838917b1fSJef Poskanzer if (test->done)
28938917b1fSJef Poskanzer return;
29038917b1fSJef Poskanzer if (test->reporter_callback)
29138917b1fSJef Poskanzer test->reporter_callback(test);
29238917b1fSJef Poskanzer }
29338917b1fSJef Poskanzer
29438917b1fSJef Poskanzer static int
create_server_timers(struct iperf_test * test)29538917b1fSJef Poskanzer create_server_timers(struct iperf_test * test)
29638917b1fSJef Poskanzer {
297cde81d76SBen Fox-Moore struct iperf_time now;
29838917b1fSJef Poskanzer TimerClientData cd;
299098dd3ccSAndrew Cooks int max_rtt = 4; /* seconds */
300098dd3ccSAndrew Cooks int state_transitions = 10; /* number of state transitions in iperf3 */
301098dd3ccSAndrew Cooks int grace_period = max_rtt * state_transitions;
30238917b1fSJef Poskanzer
303cde81d76SBen Fox-Moore if (iperf_time_now(&now) < 0) {
30438917b1fSJef Poskanzer i_errno = IEINITTEST;
30538917b1fSJef Poskanzer return -1;
30638917b1fSJef Poskanzer }
30738917b1fSJef Poskanzer cd.p = test;
308f7fd67d4Sdmdailey test->timer = test->stats_timer = test->reporter_timer = NULL;
309f7fd67d4Sdmdailey if (test->duration != 0 ) {
310f7fd67d4Sdmdailey test->done = 0;
311098dd3ccSAndrew Cooks test->timer = tmr_create(&now, server_timer_proc, cd, (test->duration + test->omit + grace_period) * SEC_TO_US, 0);
312f7fd67d4Sdmdailey if (test->timer == NULL) {
313f7fd67d4Sdmdailey i_errno = IEINITTEST;
314f7fd67d4Sdmdailey return -1;
315f7fd67d4Sdmdailey }
316f7fd67d4Sdmdailey }
317f7fd67d4Sdmdailey
31838917b1fSJef Poskanzer test->stats_timer = test->reporter_timer = NULL;
31938917b1fSJef Poskanzer if (test->stats_interval != 0) {
32038917b1fSJef Poskanzer test->stats_timer = tmr_create(&now, server_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
32138917b1fSJef Poskanzer if (test->stats_timer == NULL) {
32238917b1fSJef Poskanzer i_errno = IEINITTEST;
32338917b1fSJef Poskanzer return -1;
32438917b1fSJef Poskanzer }
32538917b1fSJef Poskanzer }
32638917b1fSJef Poskanzer if (test->reporter_interval != 0) {
32738917b1fSJef Poskanzer test->reporter_timer = tmr_create(&now, server_reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1);
32838917b1fSJef Poskanzer if (test->reporter_timer == NULL) {
32938917b1fSJef Poskanzer i_errno = IEINITTEST;
33038917b1fSJef Poskanzer return -1;
33138917b1fSJef Poskanzer }
33238917b1fSJef Poskanzer }
33338917b1fSJef Poskanzer return 0;
33438917b1fSJef Poskanzer }
33538917b1fSJef Poskanzer
33638917b1fSJef Poskanzer static void
server_omit_timer_proc(TimerClientData client_data,struct iperf_time * nowP)337cde81d76SBen Fox-Moore server_omit_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
338c9693599SJef Poskanzer {
339c9693599SJef Poskanzer struct iperf_test *test = client_data.p;
340c9693599SJef Poskanzer
34157892604SJef Poskanzer test->omit_timer = NULL;
34257892604SJef Poskanzer test->omitting = 0;
343c9693599SJef Poskanzer iperf_reset_stats(test);
344a953f5aaSJef Poskanzer if (test->verbose && !test->json_output && test->reporter_interval == 0)
345ad2a706fSNevo Hed iperf_printf(test, "%s", report_omit_done);
34638917b1fSJef Poskanzer
34738917b1fSJef Poskanzer /* Reset the timers. */
34838917b1fSJef Poskanzer if (test->stats_timer != NULL)
34938917b1fSJef Poskanzer tmr_reset(nowP, test->stats_timer);
35038917b1fSJef Poskanzer if (test->reporter_timer != NULL)
35138917b1fSJef Poskanzer tmr_reset(nowP, test->reporter_timer);
352c9693599SJef Poskanzer }
353c9693599SJef Poskanzer
354c9693599SJef Poskanzer static int
create_server_omit_timer(struct iperf_test * test)35557892604SJef Poskanzer create_server_omit_timer(struct iperf_test * test)
356c9693599SJef Poskanzer {
357cde81d76SBen Fox-Moore struct iperf_time now;
358c9693599SJef Poskanzer TimerClientData cd;
359c9693599SJef Poskanzer
360a953f5aaSJef Poskanzer if (test->omit == 0) {
361a953f5aaSJef Poskanzer test->omit_timer = NULL;
362a953f5aaSJef Poskanzer test->omitting = 0;
363a953f5aaSJef Poskanzer } else {
364cde81d76SBen Fox-Moore if (iperf_time_now(&now) < 0) {
365c9693599SJef Poskanzer i_errno = IEINITTEST;
366c9693599SJef Poskanzer return -1;
367c9693599SJef Poskanzer }
36857892604SJef Poskanzer test->omitting = 1;
369c9693599SJef Poskanzer cd.p = test;
37057892604SJef Poskanzer test->omit_timer = tmr_create(&now, server_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
37157892604SJef Poskanzer if (test->omit_timer == NULL) {
372c9693599SJef Poskanzer i_errno = IEINITTEST;
373c9693599SJef Poskanzer return -1;
374c9693599SJef Poskanzer }
375a953f5aaSJef Poskanzer }
376a953f5aaSJef Poskanzer
377c9693599SJef Poskanzer return 0;
378c9693599SJef Poskanzer }
379c9693599SJef Poskanzer
380c9693599SJef Poskanzer static void
cleanup_server(struct iperf_test * test)381c9693599SJef Poskanzer cleanup_server(struct iperf_test *test)
382c9693599SJef Poskanzer {
383a0c6f0ecSDavid Bar-On struct iperf_stream *sp;
384a0c6f0ecSDavid Bar-On
385a0c6f0ecSDavid Bar-On /* Close open streams */
386a0c6f0ecSDavid Bar-On SLIST_FOREACH(sp, &test->streams, streams) {
387a0c6f0ecSDavid Bar-On FD_CLR(sp->socket, &test->read_set);
388a0c6f0ecSDavid Bar-On FD_CLR(sp->socket, &test->write_set);
389a0c6f0ecSDavid Bar-On close(sp->socket);
390a0c6f0ecSDavid Bar-On }
391a0c6f0ecSDavid Bar-On
392c9693599SJef Poskanzer /* Close open test sockets */
39303340fe5SBruce A. Mah if (test->ctrl_sck) {
394c9693599SJef Poskanzer close(test->ctrl_sck);
39503340fe5SBruce A. Mah }
39603340fe5SBruce A. Mah if (test->listener) {
397c9693599SJef Poskanzer close(test->listener);
39803340fe5SBruce A. Mah }
39950315e7aSDavid Bar-On if (test->prot_listener > -1) { // May remain open if create socket failed
40050315e7aSDavid Bar-On close(test->prot_listener);
40150315e7aSDavid Bar-On }
40238917b1fSJef Poskanzer
40338917b1fSJef Poskanzer /* Cancel any remaining timers. */
40438917b1fSJef Poskanzer if (test->stats_timer != NULL) {
40538917b1fSJef Poskanzer tmr_cancel(test->stats_timer);
40638917b1fSJef Poskanzer test->stats_timer = NULL;
40738917b1fSJef Poskanzer }
40838917b1fSJef Poskanzer if (test->reporter_timer != NULL) {
40938917b1fSJef Poskanzer tmr_cancel(test->reporter_timer);
41038917b1fSJef Poskanzer test->reporter_timer = NULL;
41138917b1fSJef Poskanzer }
41238917b1fSJef Poskanzer if (test->omit_timer != NULL) {
41338917b1fSJef Poskanzer tmr_cancel(test->omit_timer);
41438917b1fSJef Poskanzer test->omit_timer = NULL;
41538917b1fSJef Poskanzer }
4165ab2132cSGabriel Ganne if (test->congestion_used != NULL) {
4175ab2132cSGabriel Ganne free(test->congestion_used);
418103d4318SBruce A. Mah test->congestion_used = NULL;
4195ab2132cSGabriel Ganne }
420f7fd67d4Sdmdailey if (test->timer != NULL) {
421f7fd67d4Sdmdailey tmr_cancel(test->timer);
422f7fd67d4Sdmdailey test->timer = NULL;
423f7fd67d4Sdmdailey }
424c9693599SJef Poskanzer }
425c9693599SJef Poskanzer
426afe6222aSJef Poskanzer
4277fa9f68fSsethdelliott int
iperf_run_server(struct iperf_test * test)428a951c980SBrian Tierney iperf_run_server(struct iperf_test *test)
429a951c980SBrian Tierney {
4300778f04cSBoris Okunev int result, s;
4310778f04cSBoris Okunev int send_streams_accepted, rec_streams_accepted;
4320778f04cSBoris Okunev int streams_to_send = 0, streams_to_rec = 0;
43319329249SBruce A. Mah #if defined(HAVE_TCP_CONGESTION)
43419329249SBruce A. Mah int saved_errno;
43519329249SBruce A. Mah #endif /* HAVE_TCP_CONGESTION */
4366177a7f1SJef Poskanzer fd_set read_set, write_set;
4378a0b5a5dSsethdelliott struct iperf_stream *sp;
438cde81d76SBen Fox-Moore struct iperf_time now;
439be66b575SDavid Bar-On struct iperf_time last_receive_time;
440be66b575SDavid Bar-On struct iperf_time diff_time;
4417bcbb1f6SJef Poskanzer struct timeval* timeout;
4428ffe72e2SDavid Bar-On struct timeval used_timeout;
4430778f04cSBoris Okunev int flag;
444be66b575SDavid Bar-On int64_t t_usecs;
4458ffe72e2SDavid Bar-On int64_t timeout_us;
4468ffe72e2SDavid Bar-On int64_t rcv_timeout_us;
447a951c980SBrian Tierney
448255a9c71Ssrgnk if (test->logfile)
449255a9c71Ssrgnk if (iperf_open_logfile(test) < 0)
450255a9c71Ssrgnk return -2;
451255a9c71Ssrgnk
4528a7e01ebSJef Poskanzer if (test->affinity != -1)
453deefb95fSBruce A. Mah if (iperf_setaffinity(test, test->affinity) != 0)
454b7ab2b4bSBruce A. Mah return -2;
4558a7e01ebSJef Poskanzer
456e96ab740SJef Poskanzer if (test->json_output)
457e96ab740SJef Poskanzer if (iperf_json_start(test) < 0)
458b7ab2b4bSBruce A. Mah return -2;
459e96ab740SJef Poskanzer
460e96ab740SJef Poskanzer if (test->json_output) {
461e96ab740SJef Poskanzer cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
462e96ab740SJef Poskanzer cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
463e96ab740SJef Poskanzer } else if (test->verbose) {
464ad2a706fSNevo Hed iperf_printf(test, "%s\n", version);
465ad2a706fSNevo Hed iperf_printf(test, "%s", "");
466ad2a706fSNevo Hed iperf_printf(test, "%s\n", get_system_info());
4673fa8072eSBruce A. Mah iflush(test);
468e96ab740SJef Poskanzer }
469e96ab740SJef Poskanzer
470982c704aSsethdelliott // Open socket and listen
471982c704aSsethdelliott if (iperf_server_listen(test) < 0) {
472b7ab2b4bSBruce A. Mah return -2;
473e99faeaeSBrian Tierney }
474a951c980SBrian Tierney
475be66b575SDavid Bar-On iperf_time_now(&last_receive_time); // Initialize last time something was received
476be66b575SDavid Bar-On
477efdc02f7Ssethdelliott test->state = IPERF_START;
4780778f04cSBoris Okunev send_streams_accepted = 0;
4790778f04cSBoris Okunev rec_streams_accepted = 0;
4808ffe72e2SDavid Bar-On rcv_timeout_us = (test->settings->rcv_timeout.secs * SEC_TO_US) + test->settings->rcv_timeout.usecs;
481a951c980SBrian Tierney
482873952e3Ssethdelliott while (test->state != IPERF_DONE) {
483982c704aSsethdelliott
484a0c6f0ecSDavid Bar-On // Check if average transfer rate was exceeded (condition set in the callback routines)
485a0c6f0ecSDavid Bar-On if (test->bitrate_limit_exceeded) {
486a0c6f0ecSDavid Bar-On cleanup_server(test);
487a0c6f0ecSDavid Bar-On i_errno = IETOTALRATE;
488a0c6f0ecSDavid Bar-On return -1;
489a0c6f0ecSDavid Bar-On }
490a0c6f0ecSDavid Bar-On
4916177a7f1SJef Poskanzer memcpy(&read_set, &test->read_set, sizeof(fd_set));
4926177a7f1SJef Poskanzer memcpy(&write_set, &test->write_set, sizeof(fd_set));
493982c704aSsethdelliott
494cde81d76SBen Fox-Moore iperf_time_now(&now);
4957bcbb1f6SJef Poskanzer timeout = tmr_timeout(&now);
496a0c6f0ecSDavid Bar-On
497be66b575SDavid Bar-On // Ensure select() will timeout to allow handling error cases that require server restart
4988ffe72e2SDavid Bar-On if (test->state == IPERF_START) { // In idle mode server may need to restart
4998ffe72e2SDavid Bar-On if (timeout == NULL && test->settings->idle_timeout > 0) {
5008ffe72e2SDavid Bar-On used_timeout.tv_sec = test->settings->idle_timeout;
5018ffe72e2SDavid Bar-On used_timeout.tv_usec = 0;
5028ffe72e2SDavid Bar-On timeout = &used_timeout;
503be66b575SDavid Bar-On }
5048ffe72e2SDavid Bar-On } else if (test->mode != SENDER) { // In non-reverse active mode server ensures data is received
5058ffe72e2SDavid Bar-On timeout_us = -1;
5068ffe72e2SDavid Bar-On if (timeout != NULL) {
5078ffe72e2SDavid Bar-On used_timeout.tv_sec = timeout->tv_sec;
5088ffe72e2SDavid Bar-On used_timeout.tv_usec = timeout->tv_usec;
5098ffe72e2SDavid Bar-On timeout_us = (timeout->tv_sec * SEC_TO_US) + timeout->tv_usec;
510be66b575SDavid Bar-On }
5118ffe72e2SDavid Bar-On if (timeout_us < 0 || timeout_us > rcv_timeout_us) {
5128ffe72e2SDavid Bar-On used_timeout.tv_sec = test->settings->rcv_timeout.secs;
5138ffe72e2SDavid Bar-On used_timeout.tv_usec = test->settings->rcv_timeout.usecs;
5148ffe72e2SDavid Bar-On }
5158ffe72e2SDavid Bar-On timeout = &used_timeout;
516be66b575SDavid Bar-On }
517be66b575SDavid Bar-On
518be66b575SDavid Bar-On result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
519982c704aSsethdelliott if (result < 0 && errno != EINTR) {
520c9693599SJef Poskanzer cleanup_server(test);
521b60a49ddSsethdelliott i_errno = IESELECT;
522ec2d0670SJef Poskanzer return -1;
523be66b575SDavid Bar-On } else if (result == 0) {
5248ffe72e2SDavid Bar-On // If nothing was received during the specified time (per state)
525be66b575SDavid Bar-On // then probably something got stack either at the client, server or network,
5268ffe72e2SDavid Bar-On // and Test should be forced to end.
527be66b575SDavid Bar-On iperf_time_now(&now);
528be66b575SDavid Bar-On t_usecs = 0;
529be66b575SDavid Bar-On if (iperf_time_diff(&now, &last_receive_time, &diff_time) == 0) {
530be66b575SDavid Bar-On t_usecs = iperf_time_in_usecs(&diff_time);
531be66b575SDavid Bar-On if (test->state == IPERF_START) {
532be66b575SDavid Bar-On if (test->settings->idle_timeout > 0 && t_usecs >= test->settings->idle_timeout * SEC_TO_US) {
533be66b575SDavid Bar-On test->server_forced_idle_restarts_count += 1;
534be66b575SDavid Bar-On if (test->debug)
535be66b575SDavid Bar-On printf("Server restart (#%d) in idle state as no connection request was received for %d sec\n",
536be66b575SDavid Bar-On test->server_forced_idle_restarts_count, test->settings->idle_timeout);
537be66b575SDavid Bar-On cleanup_server(test);
538775341deSMark Feit if ( iperf_get_test_one_off(test) ) {
539775341deSMark Feit if (test->debug)
540775341deSMark Feit printf("No connection request was received for %d sec in one-off mode; exiting.\n",
541775341deSMark Feit test->settings->idle_timeout);
542775341deSMark Feit exit(0);
543775341deSMark Feit }
544775341deSMark Feit
545be66b575SDavid Bar-On return 2;
546ec2d0670SJef Poskanzer }
547be66b575SDavid Bar-On }
5488ffe72e2SDavid Bar-On else if (test->mode != SENDER && t_usecs > rcv_timeout_us) {
549be66b575SDavid Bar-On test->server_forced_no_msg_restarts_count += 1;
550be66b575SDavid Bar-On i_errno = IENOMSG;
55125f50c23SBruce A. Mah if (iperf_get_verbose(test))
552de006004SBruce A. Mah iperf_err(test, "Server restart (#%d) during active test due to idle data for receiving data",
5538ffe72e2SDavid Bar-On test->server_forced_no_msg_restarts_count);
554be66b575SDavid Bar-On cleanup_server(test);
555be66b575SDavid Bar-On return -1;
556be66b575SDavid Bar-On }
557be66b575SDavid Bar-On
558be66b575SDavid Bar-On }
559be66b575SDavid Bar-On }
560be66b575SDavid Bar-On
561ec2d0670SJef Poskanzer if (result > 0) {
562be66b575SDavid Bar-On iperf_time_now(&last_receive_time);
5636177a7f1SJef Poskanzer if (FD_ISSET(test->listener, &read_set)) {
564b68ac00eSsethdelliott if (test->state != CREATE_STREAMS) {
565465b565cSsethdelliott if (iperf_accept(test) < 0) {
566c9693599SJef Poskanzer cleanup_server(test);
567ec2d0670SJef Poskanzer return -1;
568982c704aSsethdelliott }
5696177a7f1SJef Poskanzer FD_CLR(test->listener, &read_set);
5700778f04cSBoris Okunev
5710778f04cSBoris Okunev // Set streams number
5720778f04cSBoris Okunev if (test->mode == BIDIRECTIONAL) {
5730778f04cSBoris Okunev streams_to_send = test->num_streams;
5740778f04cSBoris Okunev streams_to_rec = test->num_streams;
5750778f04cSBoris Okunev } else if (test->mode == RECEIVER) {
5760778f04cSBoris Okunev streams_to_rec = test->num_streams;
5770778f04cSBoris Okunev streams_to_send = 0;
5780778f04cSBoris Okunev } else {
5790778f04cSBoris Okunev streams_to_send = test->num_streams;
5800778f04cSBoris Okunev streams_to_rec = 0;
5810778f04cSBoris Okunev }
582982c704aSsethdelliott }
583b68ac00eSsethdelliott }
5846177a7f1SJef Poskanzer if (FD_ISSET(test->ctrl_sck, &read_set)) {
585c9693599SJef Poskanzer if (iperf_handle_message_server(test) < 0) {
586c9693599SJef Poskanzer cleanup_server(test);
587ec2d0670SJef Poskanzer return -1;
588c9693599SJef Poskanzer }
5896177a7f1SJef Poskanzer FD_CLR(test->ctrl_sck, &read_set);
590982c704aSsethdelliott }
591465b565cSsethdelliott
592465b565cSsethdelliott if (test->state == CREATE_STREAMS) {
5936177a7f1SJef Poskanzer if (FD_ISSET(test->prot_listener, &read_set)) {
5948a0b5a5dSsethdelliott
595c9693599SJef Poskanzer if ((s = test->protocol->accept(test)) < 0) {
596c9693599SJef Poskanzer cleanup_server(test);
597ec2d0670SJef Poskanzer return -1;
598c9693599SJef Poskanzer }
5998a0b5a5dSsethdelliott
6001e33e721SBruce A. Mah if (!is_closed(s)) {
6011e33e721SBruce A. Mah
602*7bdd5b0eSDavid Bar-On #if defined(HAVE_TCP_USER_TIMEOUT)
603*7bdd5b0eSDavid Bar-On if (test->protocol->id == Ptcp) {
604*7bdd5b0eSDavid Bar-On int opt;
605*7bdd5b0eSDavid Bar-On if ((opt = test->settings->snd_timeout)) {
606*7bdd5b0eSDavid Bar-On if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
607*7bdd5b0eSDavid Bar-On saved_errno = errno;
608*7bdd5b0eSDavid Bar-On close(s);
609*7bdd5b0eSDavid Bar-On cleanup_server(test);
610*7bdd5b0eSDavid Bar-On errno = saved_errno;
611*7bdd5b0eSDavid Bar-On i_errno = IESETUSERTIMEOUT;
612*7bdd5b0eSDavid Bar-On return -1;
613*7bdd5b0eSDavid Bar-On }
614*7bdd5b0eSDavid Bar-On }
615*7bdd5b0eSDavid Bar-On }
616*7bdd5b0eSDavid Bar-On #endif /* HAVE_TCP_USER_TIMEOUT */
617*7bdd5b0eSDavid Bar-On
6187eeaa1cbSBruce A. Mah #if defined(HAVE_TCP_CONGESTION)
6197eeaa1cbSBruce A. Mah if (test->protocol->id == Ptcp) {
6207eeaa1cbSBruce A. Mah if (test->congestion) {
6217eeaa1cbSBruce A. Mah if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
62208758a16SBruce A. Mah /*
62308758a16SBruce A. Mah * ENOENT means we tried to set the
62408758a16SBruce A. Mah * congestion algorithm but the algorithm
62508758a16SBruce A. Mah * specified doesn't exist. This can happen
62608758a16SBruce A. Mah * if the client and server have different
62708758a16SBruce A. Mah * congestion algorithms available. In this
62808758a16SBruce A. Mah * case, print a warning, but otherwise
62908758a16SBruce A. Mah * continue.
63008758a16SBruce A. Mah */
63108758a16SBruce A. Mah if (errno == ENOENT) {
63208758a16SBruce A. Mah warning("TCP congestion control algorithm not supported");
63308758a16SBruce A. Mah }
63408758a16SBruce A. Mah else {
635b6072241STodd C. Miller saved_errno = errno;
6367eeaa1cbSBruce A. Mah close(s);
6377eeaa1cbSBruce A. Mah cleanup_server(test);
638b6072241STodd C. Miller errno = saved_errno;
6397eeaa1cbSBruce A. Mah i_errno = IESETCONGESTION;
6407eeaa1cbSBruce A. Mah return -1;
6417eeaa1cbSBruce A. Mah }
6427eeaa1cbSBruce A. Mah }
64308758a16SBruce A. Mah }
6447eeaa1cbSBruce A. Mah {
645a8ee9c65Sf1rebird socklen_t len = TCP_CA_NAME_MAX;
6467eeaa1cbSBruce A. Mah char ca[TCP_CA_NAME_MAX + 1];
64753a68308SDavid Bar-On int rc;
64853a68308SDavid Bar-On rc = getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len);
64953a68308SDavid Bar-On if (rc < 0 && test->congestion) {
650b6072241STodd C. Miller saved_errno = errno;
6517eeaa1cbSBruce A. Mah close(s);
6527eeaa1cbSBruce A. Mah cleanup_server(test);
653b6072241STodd C. Miller errno = saved_errno;
6547eeaa1cbSBruce A. Mah i_errno = IESETCONGESTION;
6557eeaa1cbSBruce A. Mah return -1;
6567eeaa1cbSBruce A. Mah }
657ce010040SBruce A. Mah /*
658ce010040SBruce A. Mah * If not the first connection, discard prior
659ce010040SBruce A. Mah * congestion algorithm name so we don't leak
660ce010040SBruce A. Mah * duplicated strings. We probably don't need
661ce010040SBruce A. Mah * the old string anyway.
662ce010040SBruce A. Mah */
663ce010040SBruce A. Mah if (test->congestion_used != NULL) {
664ce010040SBruce A. Mah free(test->congestion_used);
665ce010040SBruce A. Mah }
66653a68308SDavid Bar-On // Set actual used congestion alg, or set to unknown if could not get it
66753a68308SDavid Bar-On if (rc < 0)
66853a68308SDavid Bar-On test->congestion_used = strdup("unknown");
66953a68308SDavid Bar-On else
6707eeaa1cbSBruce A. Mah test->congestion_used = strdup(ca);
6717eeaa1cbSBruce A. Mah if (test->debug) {
6727eeaa1cbSBruce A. Mah printf("Congestion algorithm is %s\n", test->congestion_used);
6737eeaa1cbSBruce A. Mah }
6747eeaa1cbSBruce A. Mah }
6757eeaa1cbSBruce A. Mah }
6767eeaa1cbSBruce A. Mah #endif /* HAVE_TCP_CONGESTION */
6777eeaa1cbSBruce A. Mah
6780778f04cSBoris Okunev if (rec_streams_accepted != streams_to_rec) {
6790778f04cSBoris Okunev flag = 0;
6800778f04cSBoris Okunev ++rec_streams_accepted;
6810778f04cSBoris Okunev } else if (send_streams_accepted != streams_to_send) {
6820778f04cSBoris Okunev flag = 1;
6830778f04cSBoris Okunev ++send_streams_accepted;
6840778f04cSBoris Okunev }
6850778f04cSBoris Okunev
6860778f04cSBoris Okunev if (flag != -1) {
6870778f04cSBoris Okunev sp = iperf_new_stream(test, s, flag);
688c9693599SJef Poskanzer if (!sp) {
689c9693599SJef Poskanzer cleanup_server(test);
690ec2d0670SJef Poskanzer return -1;
691c9693599SJef Poskanzer }
69266ce7ad4Ssethdelliott
6930778f04cSBoris Okunev if (sp->sender)
6948a0b5a5dSsethdelliott FD_SET(s, &test->write_set);
69596feeac5SJef Poskanzer else
69696feeac5SJef Poskanzer FD_SET(s, &test->read_set);
6970778f04cSBoris Okunev
698082cbb0eSJef Poskanzer if (s > test->max_fd) test->max_fd = s;
69966ce7ad4Ssethdelliott
7008694d1dbSBruce A. Mah /*
7018694d1dbSBruce A. Mah * If the protocol isn't UDP, or even if it is but
7028694d1dbSBruce A. Mah * we're the receiver, set nonblocking sockets.
7038694d1dbSBruce A. Mah * We need this to allow a server receiver to
7048694d1dbSBruce A. Mah * maintain interactivity with the control channel.
7058694d1dbSBruce A. Mah */
7068694d1dbSBruce A. Mah if (test->protocol->id != Pudp ||
7070778f04cSBoris Okunev !sp->sender) {
708081ba8e4SBruce A. Mah setnonblocking(s, 1);
709cbacc1d6SBruce A. Mah }
710081ba8e4SBruce A. Mah
7114df383f6Ssethdelliott if (test->on_new_stream)
7124df383f6Ssethdelliott test->on_new_stream(sp);
7130778f04cSBoris Okunev
7140778f04cSBoris Okunev flag = -1;
7150778f04cSBoris Okunev }
716b68ac00eSsethdelliott }
7176177a7f1SJef Poskanzer FD_CLR(test->prot_listener, &read_set);
718b68ac00eSsethdelliott }
7198a0b5a5dSsethdelliott
7200778f04cSBoris Okunev
7210778f04cSBoris Okunev if (rec_streams_accepted == streams_to_rec && send_streams_accepted == streams_to_send) {
72266ce7ad4Ssethdelliott if (test->protocol->id != Ptcp) {
7238a0b5a5dSsethdelliott FD_CLR(test->prot_listener, &test->read_set);
7248a0b5a5dSsethdelliott close(test->prot_listener);
72566ce7ad4Ssethdelliott } else {
7260bd8d9daSsethdelliott if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
72766ce7ad4Ssethdelliott FD_CLR(test->listener, &test->read_set);
72866ce7ad4Ssethdelliott close(test->listener);
72903340fe5SBruce A. Mah test->listener = 0;
73021581a72SBruce A. Mah if ((s = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) {
731c9693599SJef Poskanzer cleanup_server(test);
732b60a49ddSsethdelliott i_errno = IELISTEN;
733ec2d0670SJef Poskanzer return -1;
734c81883bfSsethdelliott }
73566ce7ad4Ssethdelliott test->listener = s;
73666ce7ad4Ssethdelliott FD_SET(test->listener, &test->read_set);
737082cbb0eSJef Poskanzer if (test->listener > test->max_fd) test->max_fd = test->listener;
738c81883bfSsethdelliott }
7398556db5dSsethdelliott }
7408a0b5a5dSsethdelliott test->prot_listener = -1;
741a0c6f0ecSDavid Bar-On
742a0c6f0ecSDavid Bar-On /* Ensure that total requested data rate is not above limit */
743a0c6f0ecSDavid Bar-On iperf_size_t total_requested_rate = test->num_streams * test->settings->rate * (test->mode == BIDIRECTIONAL? 2 : 1);
744a0c6f0ecSDavid Bar-On if (test->settings->bitrate_limit > 0 && total_requested_rate > test->settings->bitrate_limit) {
74525f50c23SBruce A. Mah if (iperf_get_verbose(test))
746223da980SBruce A. Mah iperf_err(test, "Client total requested throughput rate of %" PRIu64 " bps exceeded %" PRIu64 " bps limit",
747a0c6f0ecSDavid Bar-On total_requested_rate, test->settings->bitrate_limit);
748a0c6f0ecSDavid Bar-On cleanup_server(test);
749a0c6f0ecSDavid Bar-On i_errno = IETOTALRATE;
750a0c6f0ecSDavid Bar-On return -1;
751a0c6f0ecSDavid Bar-On }
752a0c6f0ecSDavid Bar-On
753aeb0b3dbSjtluka // Begin calculating CPU utilization
754aeb0b3dbSjtluka cpu_util(NULL);
755aeb0b3dbSjtluka
756c9693599SJef Poskanzer if (iperf_set_send_state(test, TEST_START) != 0) {
757c9693599SJef Poskanzer cleanup_server(test);
758ec2d0670SJef Poskanzer return -1;
759982c704aSsethdelliott }
760c9693599SJef Poskanzer if (iperf_init_test(test) < 0) {
761c9693599SJef Poskanzer cleanup_server(test);
762ec2d0670SJef Poskanzer return -1;
763c9693599SJef Poskanzer }
76438917b1fSJef Poskanzer if (create_server_timers(test) < 0) {
76538917b1fSJef Poskanzer cleanup_server(test);
76638917b1fSJef Poskanzer return -1;
76738917b1fSJef Poskanzer }
76857892604SJef Poskanzer if (create_server_omit_timer(test) < 0) {
769c9693599SJef Poskanzer cleanup_server(test);
770c9693599SJef Poskanzer return -1;
771c9693599SJef Poskanzer }
7720778f04cSBoris Okunev if (test->mode != RECEIVER)
7738bdc8fffSJef Poskanzer if (iperf_create_send_timers(test) < 0) {
7748bdc8fffSJef Poskanzer cleanup_server(test);
7758bdc8fffSJef Poskanzer return -1;
7768bdc8fffSJef Poskanzer }
777c9693599SJef Poskanzer if (iperf_set_send_state(test, TEST_RUNNING) != 0) {
778c9693599SJef Poskanzer cleanup_server(test);
779ec2d0670SJef Poskanzer return -1;
780f1b3bd81Ssethdelliott }
781982c704aSsethdelliott }
782982c704aSsethdelliott }
783982c704aSsethdelliott
784f1b3bd81Ssethdelliott if (test->state == TEST_RUNNING) {
7850778f04cSBoris Okunev if (test->mode == BIDIRECTIONAL) {
7860778f04cSBoris Okunev if (iperf_recv(test, &read_set) < 0) {
7870778f04cSBoris Okunev cleanup_server(test);
7880778f04cSBoris Okunev return -1;
7890778f04cSBoris Okunev }
7900778f04cSBoris Okunev if (iperf_send(test, &write_set) < 0) {
7910778f04cSBoris Okunev cleanup_server(test);
7920778f04cSBoris Okunev return -1;
7930778f04cSBoris Okunev }
7940778f04cSBoris Okunev } else if (test->mode == SENDER) {
795465b565cSsethdelliott // Reverse mode. Server sends.
796c9693599SJef Poskanzer if (iperf_send(test, &write_set) < 0) {
797c9693599SJef Poskanzer cleanup_server(test);
798ec2d0670SJef Poskanzer return -1;
799c9693599SJef Poskanzer }
800982c704aSsethdelliott } else {
801465b565cSsethdelliott // Regular mode. Server receives.
802c9693599SJef Poskanzer if (iperf_recv(test, &read_set) < 0) {
803c9693599SJef Poskanzer cleanup_server(test);
804ec2d0670SJef Poskanzer return -1;
805e99faeaeSBrian Tierney }
806c9693599SJef Poskanzer }
807ace30a64SJef Poskanzer }
808ace30a64SJef Poskanzer }
809f1b3bd81Ssethdelliott
8107bcbb1f6SJef Poskanzer if (result == 0 ||
8117bcbb1f6SJef Poskanzer (timeout != NULL && timeout->tv_sec == 0 && timeout->tv_usec == 0)) {
812ec2d0670SJef Poskanzer /* Run the timers. */
813cde81d76SBen Fox-Moore iperf_time_now(&now);
814ec2d0670SJef Poskanzer tmr_run(&now);
815f1b3bd81Ssethdelliott }
816a951c980SBrian Tierney }
817e99faeaeSBrian Tierney
818c9693599SJef Poskanzer cleanup_server(test);
819efdc02f7Ssethdelliott
820e96ab740SJef Poskanzer if (test->json_output) {
821e96ab740SJef Poskanzer if (iperf_json_finish(test) < 0)
822e96ab740SJef Poskanzer return -1;
823e96ab740SJef Poskanzer }
824e96ab740SJef Poskanzer
825aeb6938dSBruce A. Mah iflush(test);
826aeb6938dSBruce A. Mah
8278a7e01ebSJef Poskanzer if (test->server_affinity != -1)
828deefb95fSBruce A. Mah if (iperf_clearaffinity(test) != 0)
8298a7e01ebSJef Poskanzer return -1;
8308a7e01ebSJef Poskanzer
831ec2d0670SJef Poskanzer return 0;
832a3281a3dSBrian Tierney }
833