xref: /iperf/src/iperf_client_api.c (revision 7bdd5b0e)
17d375156SJon Dugan /*
21e33e721SBruce 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.
267d375156SJon Dugan  */
2718631aacSsethdelliott #include <errno.h>
2818631aacSsethdelliott #include <setjmp.h>
29e96ab740SJef Poskanzer #include <stdio.h>
3018631aacSsethdelliott #include <stdlib.h>
3118631aacSsethdelliott #include <string.h>
3218631aacSsethdelliott #include <unistd.h>
33a27f6534SJef Poskanzer #include <signal.h>
3418631aacSsethdelliott #include <sys/types.h>
357d413a50SBruce A. Mah #include <netinet/in.h>
3618631aacSsethdelliott #include <sys/select.h>
3718631aacSsethdelliott #include <sys/uio.h>
3898ce496bSjef #include <arpa/inet.h>
3918631aacSsethdelliott 
4018631aacSsethdelliott #include "iperf.h"
4118631aacSsethdelliott #include "iperf_api.h"
4218631aacSsethdelliott #include "iperf_util.h"
43a1861d5fSBruce A. Mah #include "iperf_locale.h"
44cde81d76SBen Fox-Moore #include "iperf_time.h"
4518631aacSsethdelliott #include "net.h"
4618631aacSsethdelliott #include "timer.h"
4718631aacSsethdelliott 
487eeaa1cbSBruce A. Mah #if defined(HAVE_TCP_CONGESTION)
497eeaa1cbSBruce A. Mah #if !defined(TCP_CA_NAME_MAX)
507eeaa1cbSBruce A. Mah #define TCP_CA_NAME_MAX 16
517eeaa1cbSBruce A. Mah #endif /* TCP_CA_NAME_MAX */
527eeaa1cbSBruce A. Mah #endif /* HAVE_TCP_CONGESTION */
5318631aacSsethdelliott 
5418631aacSsethdelliott int
iperf_create_streams(struct iperf_test * test,int sender)550778f04cSBoris Okunev iperf_create_streams(struct iperf_test *test, int sender)
5618631aacSsethdelliott {
5724753fd7Sswlars     if (NULL == test)
5824753fd7Sswlars     {
5924753fd7Sswlars         iperf_err(NULL, "No test\n");
6024753fd7Sswlars         return -1;
6124753fd7Sswlars     }
6219329249SBruce A. Mah     int i, s;
6319329249SBruce A. Mah #if defined(HAVE_TCP_CONGESTION)
6419329249SBruce A. Mah     int saved_errno;
6519329249SBruce A. Mah #endif /* HAVE_TCP_CONGESTION */
6618631aacSsethdelliott     struct iperf_stream *sp;
6718631aacSsethdelliott 
6851732113SKevin Constantine     int orig_bind_port = test->bind_port;
6918631aacSsethdelliott     for (i = 0; i < test->num_streams; ++i) {
7018631aacSsethdelliott 
716bd4e258SBruce A. Mah         test->bind_port = orig_bind_port;
726bd4e258SBruce A. Mah 	if (orig_bind_port) {
736bd4e258SBruce A. Mah 	    test->bind_port += i;
7418631aacSsethdelliott             // If Bidir make sure send and receive ports are different
75ec2d0670SJef Poskanzer             if (!sender && test->mode == BIDIRECTIONAL)
7618631aacSsethdelliott                 test->bind_port += test->num_streams;
777eeaa1cbSBruce A. Mah         }
787eeaa1cbSBruce A. Mah         s = test->protocol->connect(test);
797eeaa1cbSBruce A. Mah         test->bind_port = orig_bind_port;
807eeaa1cbSBruce A. Mah         if (s < 0)
81b6072241STodd C. Miller             return -1;
827eeaa1cbSBruce A. Mah 
83b6072241STodd C. Miller #if defined(HAVE_TCP_CONGESTION)
847eeaa1cbSBruce A. Mah 	if (test->protocol->id == Ptcp) {
857eeaa1cbSBruce A. Mah 	    if (test->congestion) {
867eeaa1cbSBruce A. Mah 		if (setsockopt(s, IPPROTO_TCP, TCP_CONGESTION, test->congestion, strlen(test->congestion)) < 0) {
877eeaa1cbSBruce A. Mah 		    saved_errno = errno;
887eeaa1cbSBruce A. Mah 		    close(s);
890fd60a36SBruce A. Mah 		    errno = saved_errno;
907eeaa1cbSBruce A. Mah 		    i_errno = IESETCONGESTION;
9153a68308SDavid Bar-On 		    return -1;
9253a68308SDavid Bar-On 		}
9353a68308SDavid Bar-On 	    }
94b6072241STodd C. Miller 	    {
957eeaa1cbSBruce A. Mah 		socklen_t len = TCP_CA_NAME_MAX;
96b6072241STodd C. Miller 		char ca[TCP_CA_NAME_MAX + 1];
977eeaa1cbSBruce A. Mah                 int rc;
987eeaa1cbSBruce A. Mah 		rc = getsockopt(s, IPPROTO_TCP, TCP_CONGESTION, ca, &len);
997eeaa1cbSBruce A. Mah                 if (rc < 0 && test->congestion) {
10053a68308SDavid Bar-On 		    saved_errno = errno;
10153a68308SDavid Bar-On 		    close(s);
10253a68308SDavid Bar-On 		    errno = saved_errno;
10353a68308SDavid Bar-On 		    i_errno = IESETCONGESTION;
1047eeaa1cbSBruce A. Mah 		    return -1;
1057eeaa1cbSBruce A. Mah 		}
1067eeaa1cbSBruce A. Mah                 // Set actual used congestion alg, or set to unknown if could not get it
1077eeaa1cbSBruce A. Mah                 if (rc < 0)
1087eeaa1cbSBruce A. Mah                     test->congestion_used = strdup("unknown");
1097eeaa1cbSBruce A. Mah                 else
1107eeaa1cbSBruce A. Mah                     test->congestion_used = strdup(ca);
1117eeaa1cbSBruce A. Mah 		if (test->debug) {
1120778f04cSBoris Okunev 		    printf("Congestion algorithm is %s\n", test->congestion_used);
11318631aacSsethdelliott 		}
11496feeac5SJef Poskanzer 	    }
11596feeac5SJef Poskanzer 	}
116082cbb0eSJef Poskanzer #endif /* HAVE_TCP_CONGESTION */
11718631aacSsethdelliott 
1180778f04cSBoris Okunev 	if (sender)
11918631aacSsethdelliott 	    FD_SET(s, &test->write_set);
120ec2d0670SJef Poskanzer 	else
12118631aacSsethdelliott 	    FD_SET(s, &test->read_set);
12218631aacSsethdelliott 	if (s > test->max_fd) test->max_fd = s;
12318631aacSsethdelliott 
12418631aacSsethdelliott         sp = iperf_new_stream(test, s, sender);
12518631aacSsethdelliott         if (!sp)
12618631aacSsethdelliott             return -1;
127ec2d0670SJef Poskanzer 
12818631aacSsethdelliott         /* Perform the new stream callback */
12918631aacSsethdelliott         if (test->on_new_stream)
130c9693599SJef Poskanzer             test->on_new_stream(sp);
131cde81d76SBen Fox-Moore     }
132c9693599SJef Poskanzer 
133c9693599SJef Poskanzer     return 0;
134c9693599SJef Poskanzer }
135c9693599SJef Poskanzer 
136c9693599SJef Poskanzer static void
test_timer_proc(TimerClientData client_data,struct iperf_time * nowP)137c9693599SJef Poskanzer test_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
138c9693599SJef Poskanzer {
139c9693599SJef Poskanzer     struct iperf_test *test = client_data.p;
140cde81d76SBen Fox-Moore 
141c9693599SJef Poskanzer     test->timer = NULL;
142c9693599SJef Poskanzer     test->done = 1;
143c9693599SJef Poskanzer }
144c9693599SJef Poskanzer 
145c9693599SJef Poskanzer static void
client_stats_timer_proc(TimerClientData client_data,struct iperf_time * nowP)14638917b1fSJef Poskanzer client_stats_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
147c9693599SJef Poskanzer {
148c9693599SJef Poskanzer     struct iperf_test *test = client_data.p;
149c9693599SJef Poskanzer 
150c9693599SJef Poskanzer     if (test->done)
151cde81d76SBen Fox-Moore         return;
152c9693599SJef Poskanzer     if (test->stats_callback)
153c9693599SJef Poskanzer 	test->stats_callback(test);
154c9693599SJef Poskanzer }
155c9693599SJef Poskanzer 
156c9693599SJef Poskanzer static void
client_reporter_timer_proc(TimerClientData client_data,struct iperf_time * nowP)15738917b1fSJef Poskanzer client_reporter_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
158c9693599SJef Poskanzer {
159c9693599SJef Poskanzer     struct iperf_test *test = client_data.p;
160c9693599SJef Poskanzer 
161a953f5aaSJef Poskanzer     if (test->done)
162a953f5aaSJef Poskanzer         return;
163a953f5aaSJef Poskanzer     if (test->reporter_callback)
164cde81d76SBen Fox-Moore 	test->reporter_callback(test);
165a953f5aaSJef Poskanzer }
16624753fd7Sswlars 
16724753fd7Sswlars static int
create_client_timers(struct iperf_test * test)16824753fd7Sswlars create_client_timers(struct iperf_test * test)
16924753fd7Sswlars {
17024753fd7Sswlars     struct iperf_time now;
17124753fd7Sswlars     TimerClientData cd;
172a953f5aaSJef Poskanzer     if (NULL == test)
173cde81d76SBen Fox-Moore     {
174a953f5aaSJef Poskanzer         iperf_err(NULL, "No test\n");
175a953f5aaSJef Poskanzer         i_errno = IEINITTEST;
176a953f5aaSJef Poskanzer         return -1;
177a953f5aaSJef Poskanzer     }
178a953f5aaSJef Poskanzer 
179f11d3fa3SJef Poskanzer     if (iperf_time_now(&now) < 0) {
180a953f5aaSJef Poskanzer 	i_errno = IEINITTEST;
181a953f5aaSJef Poskanzer 	return -1;
182a953f5aaSJef Poskanzer     }
183a953f5aaSJef Poskanzer     cd.p = test;
184a953f5aaSJef Poskanzer     test->timer = test->stats_timer = test->reporter_timer = NULL;
185a953f5aaSJef Poskanzer     if (test->duration != 0) {
186a953f5aaSJef Poskanzer 	test->done = 0;
187a953f5aaSJef Poskanzer         test->timer = tmr_create(&now, test_timer_proc, cd, ( test->duration + test->omit ) * SEC_TO_US, 0);
18838917b1fSJef Poskanzer         if (test->timer == NULL) {
189a953f5aaSJef Poskanzer             i_errno = IEINITTEST;
190a953f5aaSJef Poskanzer             return -1;
191a953f5aaSJef Poskanzer 	}
192a953f5aaSJef Poskanzer     }
193a953f5aaSJef Poskanzer     if (test->stats_interval != 0) {
194a953f5aaSJef Poskanzer         test->stats_timer = tmr_create(&now, client_stats_timer_proc, cd, test->stats_interval * SEC_TO_US, 1);
19538917b1fSJef Poskanzer         if (test->stats_timer == NULL) {
196a953f5aaSJef Poskanzer             i_errno = IEINITTEST;
197a953f5aaSJef Poskanzer             return -1;
198a953f5aaSJef Poskanzer 	}
199a953f5aaSJef Poskanzer     }
200a953f5aaSJef Poskanzer     if (test->reporter_interval != 0) {
201a953f5aaSJef Poskanzer         test->reporter_timer = tmr_create(&now, client_reporter_timer_proc, cd, test->reporter_interval * SEC_TO_US, 1);
202a953f5aaSJef Poskanzer         if (test->reporter_timer == NULL) {
203a953f5aaSJef Poskanzer             i_errno = IEINITTEST;
204c9693599SJef Poskanzer             return -1;
205cde81d76SBen Fox-Moore 	}
206c9693599SJef Poskanzer     }
207c9693599SJef Poskanzer     return 0;
208c9693599SJef Poskanzer }
20957892604SJef Poskanzer 
21057892604SJef Poskanzer static void
client_omit_timer_proc(TimerClientData client_data,struct iperf_time * nowP)211c9693599SJef Poskanzer client_omit_timer_proc(TimerClientData client_data, struct iperf_time *nowP)
212a953f5aaSJef Poskanzer {
213ad2a706fSNevo Hed     struct iperf_test *test = client_data.p;
214c9693599SJef Poskanzer 
215a953f5aaSJef Poskanzer     test->omit_timer = NULL;
216a953f5aaSJef Poskanzer     test->omitting = 0;
217a953f5aaSJef Poskanzer     iperf_reset_stats(test);
218a953f5aaSJef Poskanzer     if (test->verbose && !test->json_output && test->reporter_interval == 0)
219a953f5aaSJef Poskanzer         iperf_printf(test, "%s", report_omit_done);
220c9693599SJef Poskanzer 
221c9693599SJef Poskanzer     /* Reset the timers. */
222c9693599SJef Poskanzer     if (test->stats_timer != NULL)
22357892604SJef Poskanzer         tmr_reset(nowP, test->stats_timer);
224c9693599SJef Poskanzer     if (test->reporter_timer != NULL)
225cde81d76SBen Fox-Moore         tmr_reset(nowP, test->reporter_timer);
226c9693599SJef Poskanzer }
22724753fd7Sswlars 
22824753fd7Sswlars static int
create_client_omit_timer(struct iperf_test * test)22924753fd7Sswlars create_client_omit_timer(struct iperf_test * test)
23024753fd7Sswlars {
23124753fd7Sswlars     struct iperf_time now;
232c9693599SJef Poskanzer     TimerClientData cd;
233a953f5aaSJef Poskanzer     if (NULL == test)
234a953f5aaSJef Poskanzer     {
235a953f5aaSJef Poskanzer         iperf_err(NULL, "No test\n");
236a953f5aaSJef Poskanzer         return -1;
237cde81d76SBen Fox-Moore     }
238c9693599SJef Poskanzer 
239c9693599SJef Poskanzer     if (test->omit == 0) {
240c9693599SJef Poskanzer 	test->omit_timer = NULL;
24157892604SJef Poskanzer         test->omitting = 0;
242c9693599SJef Poskanzer     } else {
24357892604SJef Poskanzer 	if (iperf_time_now(&now) < 0) {
24457892604SJef Poskanzer 	    i_errno = IEINITTEST;
245c9693599SJef Poskanzer 	    return -1;
246c9693599SJef Poskanzer 	}
247c9693599SJef Poskanzer 	test->omitting = 1;
248a953f5aaSJef Poskanzer 	cd.p = test;
249c9693599SJef Poskanzer 	test->omit_timer = tmr_create(&now, client_omit_timer_proc, cd, test->omit * SEC_TO_US, 0);
250c9693599SJef Poskanzer 	if (test->omit_timer == NULL) {
251c9693599SJef Poskanzer 	    i_errno = IEINITTEST;
25218631aacSsethdelliott 	    return -1;
25318631aacSsethdelliott 	}
25418631aacSsethdelliott     }
255d2b9eb1aSJef Poskanzer     return 0;
256d2b9eb1aSJef Poskanzer }
25718631aacSsethdelliott 
25824753fd7Sswlars int
iperf_handle_message_client(struct iperf_test * test)25924753fd7Sswlars iperf_handle_message_client(struct iperf_test *test)
26024753fd7Sswlars {
26124753fd7Sswlars     int rval;
26224753fd7Sswlars     int32_t err;
26324753fd7Sswlars 
264e35f2035SJef Poskanzer     if (NULL == test)
26501943402SJef Poskanzer     {
26618631aacSsethdelliott         iperf_err(NULL, "No test\n");
26718631aacSsethdelliott 	i_errno = IEINITTEST;
268ec2d0670SJef Poskanzer         return -1;
26918631aacSsethdelliott     }
27018631aacSsethdelliott     /*!!! Why is this read() and not Nread()? */
271ec2d0670SJef Poskanzer     if ((rval = read(test->ctrl_sck, (char*) &test->state, sizeof(signed char))) <= 0) {
27218631aacSsethdelliott         if (rval == 0) {
27318631aacSsethdelliott             i_errno = IECTRLCLOSE;
27418631aacSsethdelliott             return -1;
27518631aacSsethdelliott         } else {
27618631aacSsethdelliott             i_errno = IERECVMESSAGE;
277111645edSJef Poskanzer             return -1;
278ec2d0670SJef Poskanzer         }
27918631aacSsethdelliott     }
28018631aacSsethdelliott 
28118631aacSsethdelliott     switch (test->state) {
28218631aacSsethdelliott         case PARAM_EXCHANGE:
2830778f04cSBoris Okunev             if (iperf_exchange_parameters(test) < 0)
2840778f04cSBoris Okunev                 return -1;
2850778f04cSBoris Okunev             if (test->on_connect)
2860778f04cSBoris Okunev                 test->on_connect(test);
2870778f04cSBoris Okunev             break;
2880778f04cSBoris Okunev         case CREATE_STREAMS:
2890778f04cSBoris Okunev             if (test->mode == BIDIRECTIONAL)
2900778f04cSBoris Okunev             {
291ec2d0670SJef Poskanzer                 if (iperf_create_streams(test, 1) < 0)
29218631aacSsethdelliott                     return -1;
29318631aacSsethdelliott                 if (iperf_create_streams(test, 0) < 0)
294111645edSJef Poskanzer                     return -1;
295ec2d0670SJef Poskanzer             }
296a953f5aaSJef Poskanzer             else if (iperf_create_streams(test, test->mode) < 0)
297a953f5aaSJef Poskanzer                 return -1;
29857892604SJef Poskanzer             break;
299c9693599SJef Poskanzer         case TEST_START:
3000778f04cSBoris Okunev             if (iperf_init_test(test) < 0)
3018bdc8fffSJef Poskanzer                 return -1;
302c9693599SJef Poskanzer             if (create_client_timers(test) < 0)
30318631aacSsethdelliott                 return -1;
30418631aacSsethdelliott             if (create_client_omit_timer(test) < 0)
30518631aacSsethdelliott                 return -1;
30618631aacSsethdelliott 	    if (test->mode)
307111645edSJef Poskanzer 		if (iperf_create_send_timers(test) < 0)
308ec2d0670SJef Poskanzer 		    return -1;
30918631aacSsethdelliott             break;
31018631aacSsethdelliott         case TEST_RUNNING:
31118631aacSsethdelliott             break;
31218631aacSsethdelliott         case EXCHANGE_RESULTS:
31318631aacSsethdelliott             if (iperf_exchange_results(test) < 0)
31418631aacSsethdelliott                 return -1;
31518631aacSsethdelliott             break;
31618631aacSsethdelliott         case DISPLAY_RESULTS:
31718631aacSsethdelliott             if (test->on_test_finish)
31818631aacSsethdelliott                 test->on_test_finish(test);
319c04bdcb9SBruce A. Mah             iperf_client_end(test);
320c04bdcb9SBruce A. Mah             break;
321c04bdcb9SBruce A. Mah         case IPERF_DONE:
322c04bdcb9SBruce A. Mah             break;
323c04bdcb9SBruce A. Mah         case SERVER_TERMINATE:
324c04bdcb9SBruce A. Mah             i_errno = IESERVERTERM;
325c04bdcb9SBruce A. Mah 
326c04bdcb9SBruce A. Mah 	    /*
327c04bdcb9SBruce A. Mah 	     * Temporarily be in DISPLAY_RESULTS phase so we can get
328c04bdcb9SBruce A. Mah 	     * ending summary statistics.
329ec2d0670SJef Poskanzer 	     */
33018631aacSsethdelliott 	    signed char oldstate = test->state;
33118631aacSsethdelliott 	    cpu_util(test->cpu_util);
332ec2d0670SJef Poskanzer 	    test->state = DISPLAY_RESULTS;
3332c206d54Ssethdelliott 	    test->reporter_callback(test);
334d2b9eb1aSJef Poskanzer 	    test->state = oldstate;
3352c206d54Ssethdelliott             return -1;
336ec2d0670SJef Poskanzer         case ACCESS_DENIED:
3372c206d54Ssethdelliott             i_errno = IEACCESSDENIED;
338d2b9eb1aSJef Poskanzer             return -1;
339d2b9eb1aSJef Poskanzer         case SERVER_ERROR:
3402c206d54Ssethdelliott             if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
341ec2d0670SJef Poskanzer                 i_errno = IECTRLREAD;
3422c206d54Ssethdelliott                 return -1;
343d2b9eb1aSJef Poskanzer             }
344ec2d0670SJef Poskanzer 	    i_errno = ntohl(err);
34518631aacSsethdelliott             if (Nread(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
34618631aacSsethdelliott                 i_errno = IECTRLREAD;
347ec2d0670SJef Poskanzer                 return -1;
34818631aacSsethdelliott             }
34918631aacSsethdelliott             errno = ntohl(err);
350ec2d0670SJef Poskanzer             return -1;
35118631aacSsethdelliott         default:
35218631aacSsethdelliott             i_errno = IEMESSAGE;
35318631aacSsethdelliott             return -1;
35418631aacSsethdelliott     }
35518631aacSsethdelliott 
35618631aacSsethdelliott     return 0;
35718631aacSsethdelliott }
35818631aacSsethdelliott 
359*7bdd5b0eSDavid Bar-On 
360*7bdd5b0eSDavid Bar-On 
361*7bdd5b0eSDavid Bar-On /* iperf_connect -- client to server connection function */
36224753fd7Sswlars int
iperf_connect(struct iperf_test * test)36324753fd7Sswlars iperf_connect(struct iperf_test *test)
36424753fd7Sswlars {
36524753fd7Sswlars     int opt;
36624753fd7Sswlars     socklen_t len;
36718631aacSsethdelliott 
36818631aacSsethdelliott     if (NULL == test)
36918631aacSsethdelliott     {
3702ab386bfSjef         iperf_err(NULL, "No test\n");
37118631aacSsethdelliott         return -1;
37218631aacSsethdelliott     }
373d7613a8eSJef Poskanzer     FD_ZERO(&test->read_set);
374023fb45eSKevin Constantine     FD_ZERO(&test->write_set);
37521581a72SBruce A. Mah 
37618631aacSsethdelliott     make_cookie(test->cookie);
37718631aacSsethdelliott 
378ec2d0670SJef Poskanzer     /* Create and connect the control channel */
37918631aacSsethdelliott     if (test->ctrl_sck < 0)
38018631aacSsethdelliott 	// Create the control channel using an ephemeral port
38197a1d11aSBruce A. Mah 	test->ctrl_sck = netdial(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, 0, test->server_hostname, test->server_port, test->settings->connect_timeout);
38297a1d11aSBruce A. Mah     if (test->ctrl_sck < 0) {
38397a1d11aSBruce A. Mah         i_errno = IECONNECT;
38497a1d11aSBruce A. Mah         return -1;
38597a1d11aSBruce A. Mah     }
38697a1d11aSBruce A. Mah 
38797a1d11aSBruce A. Mah     // set TCP_NODELAY for lower latency on control messages
388*7bdd5b0eSDavid Bar-On     int flag = 1;
389*7bdd5b0eSDavid Bar-On     if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int))) {
390*7bdd5b0eSDavid Bar-On         i_errno = IESETNODELAY;
391*7bdd5b0eSDavid Bar-On         return -1;
392*7bdd5b0eSDavid Bar-On     }
393*7bdd5b0eSDavid Bar-On 
394*7bdd5b0eSDavid Bar-On #if defined(HAVE_TCP_USER_TIMEOUT)
395*7bdd5b0eSDavid Bar-On     if ((opt = test->settings->snd_timeout)) {
396*7bdd5b0eSDavid Bar-On         if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
39718631aacSsethdelliott         i_errno = IESETUSERTIMEOUT;
39818631aacSsethdelliott         return -1;
399ec2d0670SJef Poskanzer         }
40018631aacSsethdelliott     }
40118631aacSsethdelliott #endif /* HAVE_TCP_USER_TIMEOUT */
40218631aacSsethdelliott 
403082cbb0eSJef Poskanzer     if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
40418631aacSsethdelliott         i_errno = IESENDCOOKIE;
4050fd60a36SBruce A. Mah         return -1;
4060fd60a36SBruce A. Mah     }
4070fd60a36SBruce A. Mah 
4080fd60a36SBruce A. Mah     FD_SET(test->ctrl_sck, &test->read_set);
4090fd60a36SBruce A. Mah     if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;
410d60f6234SBoris Okunev 
4110fd60a36SBruce A. Mah     len = sizeof(opt);
4120fd60a36SBruce A. Mah     if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) {
413d60f6234SBoris Okunev         test->ctrl_sck_mss = 0;
414805a4ce1SBruce A. Mah     }
415d60f6234SBoris Okunev     else {
416d60f6234SBoris Okunev         if (opt > 0 && opt <= MAX_UDP_BLOCKSIZE) {
417d60f6234SBoris Okunev             test->ctrl_sck_mss = opt;
418d60f6234SBoris Okunev         }
419d60f6234SBoris Okunev         else {
420d60f6234SBoris Okunev             char str[WARN_STR_LEN];
421d60f6234SBoris Okunev             snprintf(str, sizeof(str),
4220fd60a36SBruce A. Mah                      "Ignoring nonsense TCP MSS %d", opt);
4230fd60a36SBruce A. Mah             warning(str);
4240fd60a36SBruce A. Mah 
4250fd60a36SBruce A. Mah             test->ctrl_sck_mss = 0;
4260fd60a36SBruce A. Mah         }
4270fd60a36SBruce A. Mah     }
4280fd60a36SBruce A. Mah 
4290fd60a36SBruce A. Mah     if (test->verbose) {
4300fd60a36SBruce A. Mah 	printf("Control connection MSS %d\n", test->ctrl_sck_mss);
4310fd60a36SBruce A. Mah     }
4320fd60a36SBruce A. Mah 
4330fd60a36SBruce A. Mah     /*
4340fd60a36SBruce A. Mah      * If we're doing a UDP test and the block size wasn't explicitly
4350fd60a36SBruce A. Mah      * set, then use the known MSS of the control connection to pick
4360fd60a36SBruce A. Mah      * an appropriate default.  If we weren't able to get the
4370fd60a36SBruce A. Mah      * MSS for some reason, then default to something that should
4380fd60a36SBruce A. Mah      * work on non-jumbo-frame Ethernet networks.  The goal is to
4390fd60a36SBruce A. Mah      * pick a reasonable default that is large but should get from
4400fd60a36SBruce A. Mah      * sender to receiver without any IP fragmentation.
4410fd60a36SBruce A. Mah      *
4420fd60a36SBruce A. Mah      * We assume that the control connection is routed the same as the
4430fd60a36SBruce A. Mah      * data packets (thus has the same PMTU).  Also in the case of
4440fd60a36SBruce A. Mah      * --reverse tests, we assume that the MTU is the same in both
4450fd60a36SBruce A. Mah      * directions.  Note that even if the algorithm guesses wrong,
4460fd60a36SBruce A. Mah      * the user always has the option to override.
4470fd60a36SBruce A. Mah      */
4480fd60a36SBruce A. Mah     if (test->protocol->id == Pudp) {
4490fd60a36SBruce A. Mah 	if (test->settings->blksize == 0) {
450f46e2e3eSBruce A. Mah 	    if (test->ctrl_sck_mss) {
4510fd60a36SBruce A. Mah 		test->settings->blksize = test->ctrl_sck_mss;
4520fd60a36SBruce A. Mah 	    }
453f46e2e3eSBruce A. Mah 	    else {
4540fd60a36SBruce A. Mah 		test->settings->blksize = DEFAULT_UDP_BLKSIZE;
4550fd60a36SBruce A. Mah 	    }
4560fd60a36SBruce A. Mah 	    if (test->verbose) {
4570fd60a36SBruce A. Mah 		printf("Setting UDP block size to %d\n", test->settings->blksize);
4580fd60a36SBruce A. Mah 	    }
459ca954c76SBruce A. Mah 	}
460ca954c76SBruce A. Mah 
461805a4ce1SBruce A. Mah 	/*
462f46e2e3eSBruce A. Mah 	 * Regardless of whether explicitly or implicitly set, if the
463d6a67517SBruce A. Mah 	 * block size is larger than the MSS, print a warning.
464f46e2e3eSBruce A. Mah 	 */
4650fd60a36SBruce A. Mah 	if (test->ctrl_sck_mss > 0 &&
4660fd60a36SBruce A. Mah 	    test->settings->blksize > test->ctrl_sck_mss) {
4670fd60a36SBruce A. Mah 	    char str[WARN_STR_LEN];
468ec2d0670SJef Poskanzer 	    snprintf(str, sizeof(str),
46918631aacSsethdelliott 		     "UDP block size %d exceeds TCP MSS %d, may result in fragmentation / drops", test->settings->blksize, test->ctrl_sck_mss);
47018631aacSsethdelliott 	    warning(str);
47118631aacSsethdelliott 	}
47218631aacSsethdelliott     }
47318631aacSsethdelliott 
47418631aacSsethdelliott     return 0;
47524753fd7Sswlars }
47624753fd7Sswlars 
47724753fd7Sswlars 
47824753fd7Sswlars int
iperf_client_end(struct iperf_test * test)47924753fd7Sswlars iperf_client_end(struct iperf_test *test)
4800bd8d9daSsethdelliott {
4810bd8d9daSsethdelliott     if (NULL == test)
4820bd8d9daSsethdelliott     {
4830bd8d9daSsethdelliott         iperf_err(NULL, "No test\n");
4840bd8d9daSsethdelliott         return -1;
4850bd8d9daSsethdelliott     }
48618631aacSsethdelliott     struct iperf_stream *sp;
48718631aacSsethdelliott 
48818631aacSsethdelliott     /* Close all stream sockets */
48918631aacSsethdelliott     SLIST_FOREACH(sp, &test->streams, streams) {
4901e33e721SBruce A. Mah         close(sp->socket);
4911e33e721SBruce A. Mah     }
49246cb4b4bSBruce A. Mah 
49346cb4b4bSBruce A. Mah     /* show final summary */
4941e33e721SBruce A. Mah     test->reporter_callback(test);
49546cb4b4bSBruce A. Mah 
496946a5a0fSp0intR     /* Send response only if no error in server */
4978464c3c2SBruce A. Mah     if (test->state > 0) {
498946a5a0fSp0intR         if (iperf_set_send_state(test, IPERF_DONE) != 0)
499946a5a0fSp0intR             return -1;
500ec2d0670SJef Poskanzer     }
50118631aacSsethdelliott 
50218631aacSsethdelliott     /* Close control socket */
50318631aacSsethdelliott     if (test->ctrl_sck >= 0)
50418631aacSsethdelliott         close(test->ctrl_sck);
50518631aacSsethdelliott 
50618631aacSsethdelliott     return 0;
507a27f6534SJef Poskanzer }
5087bcbb1f6SJef Poskanzer 
5096177a7f1SJef Poskanzer 
510cde81d76SBen Fox-Moore int
iperf_run_client(struct iperf_test * test)5117bcbb1f6SJef Poskanzer iperf_run_client(struct iperf_test * test)
512081ba8e4SBruce A. Mah {
5138ffe72e2SDavid Bar-On     int startup;
5148ffe72e2SDavid Bar-On     int result = 0;
5158ffe72e2SDavid Bar-On     fd_set read_set, write_set;
5168ffe72e2SDavid Bar-On     struct iperf_time now;
5178ffe72e2SDavid Bar-On     struct timeval* timeout = NULL;
5188ffe72e2SDavid Bar-On     struct iperf_stream *sp;
51918631aacSsethdelliott     struct iperf_time last_receive_time;
52024753fd7Sswlars     struct iperf_time diff_time;
52124753fd7Sswlars     struct timeval used_timeout;
52224753fd7Sswlars     int64_t t_usecs;
52324753fd7Sswlars     int64_t timeout_us;
52424753fd7Sswlars     int64_t rcv_timeout_us;
52524753fd7Sswlars 
526255a9c71Ssrgnk     if (NULL == test)
527255a9c71Ssrgnk     {
528255a9c71Ssrgnk         iperf_err(NULL, "No test\n");
529255a9c71Ssrgnk         return -1;
5308a7e01ebSJef Poskanzer     }
531deefb95fSBruce A. Mah 
5328a7e01ebSJef Poskanzer     if (test->logfile)
5338a7e01ebSJef Poskanzer         if (iperf_open_logfile(test) < 0)
534e96ab740SJef Poskanzer             return -1;
535e96ab740SJef Poskanzer 
536e96ab740SJef Poskanzer     if (test->affinity != -1)
537e96ab740SJef Poskanzer 	if (iperf_setaffinity(test, test->affinity) != 0)
538e96ab740SJef Poskanzer 	    return -1;
539e96ab740SJef Poskanzer 
540e96ab740SJef Poskanzer     if (test->json_output)
541e96ab740SJef Poskanzer 	if (iperf_json_start(test) < 0)
542ad2a706fSNevo Hed 	    return -1;
543ad2a706fSNevo Hed 
544ad2a706fSNevo Hed     if (test->json_output) {
5453fa8072eSBruce A. Mah 	cJSON_AddItemToObject(test->json_start, "version", cJSON_CreateString(version));
546e96ab740SJef Poskanzer 	cJSON_AddItemToObject(test->json_start, "system_info", cJSON_CreateString(get_system_info()));
547e96ab740SJef Poskanzer     } else if (test->verbose) {
54818631aacSsethdelliott 	iperf_printf(test, "%s\n", version);
5498a7e01ebSJef Poskanzer 	iperf_printf(test, "%s", "");
55080b7c7b2SBruce A. Mah 	iperf_printf(test, "%s\n", get_system_info());
55118631aacSsethdelliott 	iflush(test);
552a27f6534SJef Poskanzer     }
5533331e801Ssethdelliott 
5548ffe72e2SDavid Bar-On     /* Start the client and connect to the server */
5558ffe72e2SDavid Bar-On     if (iperf_connect(test) < 0)
5568ffe72e2SDavid Bar-On         goto cleanup_and_fail;
5578ffe72e2SDavid Bar-On 
5583331e801Ssethdelliott     /* Begin calculating CPU utilization */
559a27f6534SJef Poskanzer     cpu_util(NULL);
56018631aacSsethdelliott     if (test->mode != SENDER)
5616177a7f1SJef Poskanzer         rcv_timeout_us = (test->settings->rcv_timeout.secs * SEC_TO_US) + test->settings->rcv_timeout.usecs;
5626177a7f1SJef Poskanzer     else
563cde81d76SBen Fox-Moore         rcv_timeout_us = 0;
5647bcbb1f6SJef Poskanzer 
5658ffe72e2SDavid Bar-On     startup = 1;
5668ffe72e2SDavid Bar-On     while (test->state != IPERF_DONE) {
5678ffe72e2SDavid Bar-On 	memcpy(&read_set, &test->read_set, sizeof(fd_set));
5688ffe72e2SDavid Bar-On 	memcpy(&write_set, &test->write_set, sizeof(fd_set));
5698ffe72e2SDavid Bar-On 	iperf_time_now(&now);
5708ffe72e2SDavid Bar-On 	timeout = tmr_timeout(&now);
5718ffe72e2SDavid Bar-On 
5728ffe72e2SDavid Bar-On         // In reverse active mode client ensures data is received
5738ffe72e2SDavid Bar-On         if (test->state == TEST_RUNNING && rcv_timeout_us > 0) {
5748ffe72e2SDavid Bar-On             timeout_us = -1;
5758ffe72e2SDavid Bar-On             if (timeout != NULL) {
5768ffe72e2SDavid Bar-On                 used_timeout.tv_sec = timeout->tv_sec;
5778ffe72e2SDavid Bar-On                 used_timeout.tv_usec = timeout->tv_usec;
5788ffe72e2SDavid Bar-On                 timeout_us = (timeout->tv_sec * SEC_TO_US) + timeout->tv_usec;
5798ffe72e2SDavid Bar-On             }
5808ffe72e2SDavid Bar-On             if (timeout_us < 0 || timeout_us > rcv_timeout_us) {
5817bcbb1f6SJef Poskanzer                 used_timeout.tv_sec = test->settings->rcv_timeout.secs;
58218631aacSsethdelliott                 used_timeout.tv_usec = test->settings->rcv_timeout.usecs;
58318631aacSsethdelliott             }
58480b7c7b2SBruce A. Mah             timeout = &used_timeout;
5858ffe72e2SDavid Bar-On         }
5868ffe72e2SDavid Bar-On 
5878ffe72e2SDavid Bar-On 	result = select(test->max_fd + 1, &read_set, &write_set, NULL, timeout);
5888ffe72e2SDavid Bar-On 	if (result < 0 && errno != EINTR) {
5898ffe72e2SDavid Bar-On   	    i_errno = IESELECT;
5908ffe72e2SDavid Bar-On 	    goto cleanup_and_fail;
5918ffe72e2SDavid Bar-On         } else if (result == 0 && test->state == TEST_RUNNING && rcv_timeout_us > 0) {
5928ffe72e2SDavid Bar-On             // If nothing was received in non-reverse running state then probably something got stack -
5938ffe72e2SDavid Bar-On             // either client, server or network, and test should be terminated.
594ec2d0670SJef Poskanzer             iperf_time_now(&now);
5958ffe72e2SDavid Bar-On             if (iperf_time_diff(&now, &last_receive_time, &diff_time) == 0) {
5968ffe72e2SDavid Bar-On                 t_usecs = iperf_time_in_usecs(&diff_time);
5978ffe72e2SDavid Bar-On                 if (t_usecs > rcv_timeout_us) {
5988ffe72e2SDavid Bar-On                     i_errno = IENOMSG;
599ec2d0670SJef Poskanzer                     goto cleanup_and_fail;
6008ffe72e2SDavid Bar-On                 }
6018ffe72e2SDavid Bar-On 
6028ffe72e2SDavid Bar-On             }
6036177a7f1SJef Poskanzer         }
60498ce496bSjef 
60580b7c7b2SBruce A. Mah 	if (result > 0) {
60698ce496bSjef             if (rcv_timeout_us > 0) {
6076177a7f1SJef Poskanzer                 iperf_time_now(&last_receive_time);
60818631aacSsethdelliott             }
609a27f6534SJef Poskanzer 	    if (FD_ISSET(test->ctrl_sck, &read_set)) {
61018631aacSsethdelliott  	        if (iperf_handle_message_client(test) < 0) {
61118631aacSsethdelliott 		    goto cleanup_and_fail;
612a27f6534SJef Poskanzer 		}
613c9693599SJef Poskanzer 		FD_CLR(test->ctrl_sck, &read_set);
614a953f5aaSJef Poskanzer 	    }
615a27f6534SJef Poskanzer 	}
616ba123d5cSJef Poskanzer 
6176b16244bSBruce A. Mah 	if (test->state == TEST_RUNNING) {
6186b16244bSBruce A. Mah 
619081ba8e4SBruce A. Mah 	    /* Is this our first time really running? */
620081ba8e4SBruce A. Mah 	    if (startup) {
621081ba8e4SBruce A. Mah 	        startup = 0;
622a27f6534SJef Poskanzer 
623cbacc1d6SBruce A. Mah 		// Set non-blocking for non-UDP tests
624a27f6534SJef Poskanzer 		if (test->protocol->id != Pudp) {
6250778f04cSBoris Okunev 		    SLIST_FOREACH(sp, &test->streams, streams) {
6260778f04cSBoris Okunev 			setnonblocking(sp->socket, 1);
6270778f04cSBoris Okunev 		    }
6280778f04cSBoris Okunev 		}
62980b7c7b2SBruce A. Mah 	    }
6307bcbb1f6SJef Poskanzer 
63180b7c7b2SBruce A. Mah 
6320778f04cSBoris Okunev 	    if (test->mode == BIDIRECTIONAL)
63318631aacSsethdelliott 	    {
634081ba8e4SBruce A. Mah                 if (iperf_send(test, &write_set) < 0)
63580b7c7b2SBruce A. Mah                     goto cleanup_and_fail;
6360778f04cSBoris Okunev                 if (iperf_recv(test, &read_set) < 0)
6370778f04cSBoris Okunev                     goto cleanup_and_fail;
6380778f04cSBoris Okunev 	    } else if (test->mode == SENDER) {
63980b7c7b2SBruce A. Mah                 // Regular mode. Client sends.
64018631aacSsethdelliott                 if (iperf_send(test, &write_set) < 0)
64118631aacSsethdelliott                     goto cleanup_and_fail;
6420778f04cSBoris Okunev 	    } else {
643ec2d0670SJef Poskanzer                 // Reverse mode. Client receives.
644cde81d76SBen Fox-Moore                 if (iperf_recv(test, &read_set) < 0)
645ec2d0670SJef Poskanzer                     goto cleanup_and_fail;
64618631aacSsethdelliott 	    }
647b818ef51SBruce A. Mah 
648b818ef51SBruce A. Mah 
649b818ef51SBruce A. Mah             /* Run the timers. */
650b818ef51SBruce A. Mah             iperf_time_now(&now);
651b818ef51SBruce A. Mah             tmr_run(&now);
652b818ef51SBruce A. Mah 
653b818ef51SBruce A. Mah 	    /*
654b818ef51SBruce A. Mah 	     * Is the test done yet?  We have to be out of omitting
655f11d3fa3SJef Poskanzer 	     * mode, and then we have to have fulfilled one of the
65641089978SHamid Anvari 	     * ending criteria, either by times, bytes, or blocks.
657b818ef51SBruce A. Mah 	     * The bytes and blocks tests needs to handle both the
658b818ef51SBruce A. Mah 	     * cases of the client being the sender and the client
659b818ef51SBruce A. Mah 	     * being the receiver.
660b818ef51SBruce A. Mah 	     */
661081ba8e4SBruce A. Mah 	    if ((!test->omitting) &&
662f9820fd6SBruce A. Mah 	        (test->done ||
6636b16244bSBruce A. Mah 	         (test->settings->bytes != 0 && (test->bytes_sent >= test->settings->bytes ||
664081ba8e4SBruce A. Mah 						 test->bytes_received >= test->settings->bytes)) ||
665081ba8e4SBruce A. Mah 	         (test->settings->blocks != 0 && (test->blocks_sent >= test->settings->blocks ||
666081ba8e4SBruce A. Mah 						  test->blocks_received >= test->settings->blocks)))) {
667cbacc1d6SBruce A. Mah 
668081ba8e4SBruce A. Mah 		// Unset non-blocking for non-UDP tests
669fbaa2467SJef Poskanzer 		if (test->protocol->id != Pudp) {
67095360b20SJef Poskanzer 		    SLIST_FOREACH(sp, &test->streams, streams) {
671056361fcSJef Poskanzer 			setnonblocking(sp->socket, 0);
67218631aacSsethdelliott 		    }
673c9693599SJef Poskanzer 		}
67480b7c7b2SBruce A. Mah 
67518631aacSsethdelliott 		/* Yes, done!  Send TEST_END. */
67618631aacSsethdelliott 		test->done = 1;
6770fdda50cSBruce A. Mah 		cpu_util(test->cpu_util);
6780fdda50cSBruce A. Mah 		test->stats_callback(test);
6790fdda50cSBruce A. Mah 		if (iperf_set_send_state(test, TEST_END) != 0)
6800fdda50cSBruce A. Mah                     goto cleanup_and_fail;
6810fdda50cSBruce A. Mah 	    }
6820778f04cSBoris Okunev 	}
6830fdda50cSBruce A. Mah 	// If we're in reverse mode, continue draining the data
68480b7c7b2SBruce A. Mah 	// connection(s) even if test is over.  This prevents a
6850fdda50cSBruce A. Mah 	// deadlock where the server side fills up its pipe(s)
686f11d3fa3SJef Poskanzer 	// and gets blocked, so it can't receive state changes
68718631aacSsethdelliott 	// from the client side.
688e96ab740SJef Poskanzer 	else if (test->mode == RECEIVER && test->state == TEST_END) {
689e96ab740SJef Poskanzer 	    if (iperf_recv(test, &read_set) < 0)
690e96ab740SJef Poskanzer 		goto cleanup_and_fail;
691d38ab4c8SJef Poskanzer 	}
692ad2a706fSNevo Hed     }
693ad2a706fSNevo Hed 
694d38ab4c8SJef Poskanzer     if (test->json_output) {
695e96ab740SJef Poskanzer 	if (iperf_json_finish(test) < 0)
696aeb6938dSBruce A. Mah 	    return -1;
697aeb6938dSBruce A. Mah     } else {
698ec2d0670SJef Poskanzer 	iperf_printf(test, "\n");
69980b7c7b2SBruce A. Mah 	iperf_printf(test, "%s", report_done);
70080b7c7b2SBruce A. Mah     }
70180b7c7b2SBruce A. Mah 
7022ec43d12SDavid Bar-On     iflush(test);
7031ed0239dSJoakim Sørensen 
7041ed0239dSJoakim Sørensen     return 0;
7051ed0239dSJoakim Sørensen 
7060b15c449SSarah Larsen   cleanup_and_fail:
7070b15c449SSarah Larsen     iperf_client_end(test);
7081ed0239dSJoakim Sørensen     if (test->json_output) {
7092ec43d12SDavid Bar-On         cJSON_AddStringToObject(test->json_top, "error", iperf_strerror(i_errno));
71080b7c7b2SBruce A. Mah         iperf_json_finish(test);
7111ed0239dSJoakim Sørensen         iflush(test);
71218631aacSsethdelliott         // Return 0 and not -1 since all terminating function were done here.
713         // Also prevents error message logging outside the already closed JSON output.
714         return 0;
715     }
716     iflush(test);
717     return -1;
718 }
719