Skip to content

Commit 8fa010c

Browse files
committed
Add support for UDP control sockt for UDP tests (no use of TCP)
1 parent 6b69d06 commit 8fa010c

9 files changed

Lines changed: 168 additions & 74 deletions

File tree

src/iperf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ struct iperf_test
295295
int sender_has_retransmits;
296296
int other_side_has_retransmits; /* used if mode == BIDIRECTIONAL */
297297
struct protocol *protocol;
298+
int udp_ctrl_sck; /* --udp-cntl-sck - true if control socket is UDP */
298299
signed char state;
299300
char *server_hostname; /* -c option */
300301
char *tmp_template;

src/iperf_api.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
11581158
#if defined(HAVE_IPPROTO_MPTCP)
11591159
{"mptcp", no_argument, NULL, 'm'},
11601160
#endif
1161+
{"udp-control", no_argument, NULL, OPT_UDP_CONTROL},
11611162
{"debug", optional_argument, NULL, 'd'},
11621163
{"help", no_argument, NULL, 'h'},
11631164
{NULL, 0, NULL, 0}
@@ -1662,6 +1663,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
16621663
test->mptcp = 1;
16631664
break;
16641665
#endif
1666+
case OPT_UDP_CONTROL:
1667+
test->udp_ctrl_sck = 1;
1668+
break;
16651669
case 'h':
16661670
usage_long(stdout);
16671671
exit(0);
@@ -1784,6 +1788,11 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
17841788
}
17851789
test->settings->blksize = blksize;
17861790

1791+
if (test->role == 'c' && test->udp_ctrl_sck && test->protocol->id != Pudp) {
1792+
i_errno = IEUDPCNTLONLYUDP;
1793+
return -1;
1794+
}
1795+
17871796
if (!rate_flag)
17881797
test->settings->rate = test->protocol->id == Pudp ? UDP_RATE : 0;
17891798

@@ -3112,6 +3121,8 @@ iperf_defaults(struct iperf_test *testp)
31123121

31133122
set_protocol(testp, Ptcp);
31143123

3124+
testp->udp_ctrl_sck = 0;
3125+
31153126
#if defined(HAVE_SCTP_H)
31163127
sctp = protocol_new();
31173128
if (!sctp) {

src/iperf_api.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ typedef atomic_uint_fast64_t atomic_iperf_size_t;
101101
#define OPT_JSON_STREAM 28
102102
#define OPT_SND_TIMEOUT 29
103103
#define OPT_USE_PKCS1_PADDING 30
104+
#define OPT_UDP_CONTROL 31
104105

105106
/* states */
106107
#define TEST_START 1
@@ -421,6 +422,7 @@ enum {
421422
IESNDTIMEOUT = 33, // Illegal message send timeout
422423
IEUDPFILETRANSFER = 34, // Cannot transfer file using UDP
423424
IESERVERAUTHUSERS = 35, // Cannot access authorized users file
425+
IEUDPCNTLONLYUDP = 36, // UDP Control Socket is supported only in UDP test
424426
/* Test errors */
425427
IENEWTEST = 100, // Unable to create a new test (check perror)
426428
IEINITTEST = 101, // Test initialization failed (check perror)

src/iperf_client_api.c

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
#include "iperf.h"
4242
#include "iperf_api.h"
43+
#include "iperf_udp.h"
4344
#include "iperf_util.h"
4445
#include "iperf_locale.h"
4546
#include "iperf_time.h"
@@ -316,8 +317,7 @@ iperf_handle_message_client(struct iperf_test *test)
316317
iperf_printf(test, "Reading new State from the Server - current state is %d-%s\n", test->state, state_to_text(test->state));
317318
}
318319

319-
/*!!! Why is this read() and not Nread()? */
320-
if ((rval = read(test->ctrl_sck, (char*) &test->state, sizeof(signed char))) <= 0) {
320+
if ((rval = Nread(test->ctrl_sck, (char*) &test->state, sizeof(signed char), Ptcp)) <= 0) {
321321
if (rval == 0) {
322322
i_errno = IECTRLCLOSE;
323323
return -1;
@@ -429,29 +429,36 @@ iperf_connect(struct iperf_test *test)
429429
make_cookie(test->cookie);
430430

431431
/* Create and connect the control channel */
432-
if (test->ctrl_sck < 0)
433-
// Create the control channel using an ephemeral port
434-
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);
435432
if (test->ctrl_sck < 0) {
436-
i_errno = IECONNECT;
437-
return -1;
438-
}
439-
440-
// set TCP_NODELAY for lower latency on control messages
441-
int flag = 1;
442-
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int))) {
443-
i_errno = IESETNODELAY;
444-
return -1;
445-
}
446-
433+
// Create the control channel using an ephemeral port
434+
if (test->udp_ctrl_sck) { // UDP Control Socket
435+
test->ctrl_sck = iperf_udp_connect(test);
436+
if (test->ctrl_sck < 0) {
437+
i_errno = IECONNECT;
438+
return -1;
439+
}
440+
} else { // TCP Control Socket
441+
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);
442+
if (test->ctrl_sck < 0) {
443+
i_errno = IECONNECT;
444+
return -1;
445+
}
446+
// set TCP_NODELAY for lower latency on control messages
447+
int flag = 1;
448+
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int))) {
449+
i_errno = IESETNODELAY;
450+
return -1;
451+
}
447452
#if defined(HAVE_TCP_USER_TIMEOUT)
448-
if ((opt = test->settings->snd_timeout)) {
449-
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
450-
i_errno = IESETUSERTIMEOUT;
451-
return -1;
453+
if ((opt = test->settings->snd_timeout)) {
454+
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
455+
i_errno = IESETUSERTIMEOUT;
456+
return -1;
457+
}
458+
}
459+
#endif /* HAVE_TCP_USER_TIMEOUT */
452460
}
453461
}
454-
#endif /* HAVE_TCP_USER_TIMEOUT */
455462

456463
if (Nwrite(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
457464
i_errno = IESENDCOOKIE;
@@ -461,21 +468,22 @@ iperf_connect(struct iperf_test *test)
461468
FD_SET(test->ctrl_sck, &test->read_set);
462469
if (test->ctrl_sck > test->max_fd) test->max_fd = test->ctrl_sck;
463470

464-
len = sizeof(opt);
465-
if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) {
466-
test->ctrl_sck_mss = 0;
467-
}
468-
else {
469-
if (opt > 0 && opt <= MAX_UDP_BLOCKSIZE) {
470-
test->ctrl_sck_mss = opt;
471+
if (!test->udp_ctrl_sck) { // TCP Control Socket
472+
len = sizeof(opt);
473+
if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len) < 0) {
474+
test->ctrl_sck_mss = 0;
471475
}
472476
else {
473-
char str[WARN_STR_LEN];
474-
snprintf(str, sizeof(str),
475-
"Ignoring nonsense TCP MSS %d", opt);
476-
warning(str);
477-
478-
test->ctrl_sck_mss = 0;
477+
if (opt > 0 && opt <= MAX_UDP_BLOCKSIZE) {
478+
test->ctrl_sck_mss = opt;
479+
} else {
480+
char str[WARN_STR_LEN];
481+
snprintf(str, sizeof(str),
482+
"Ignoring nonsense TCP MSS %d", opt);
483+
warning(str);
484+
485+
test->ctrl_sck_mss = 0;
486+
}
479487
}
480488
}
481489

src/iperf_error.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ iperf_strerror(int int_errno)
188188
case IEUDPBLOCKSIZE:
189189
snprintf(errstr, len, "block size invalid (minimum = %d bytes, maximum = %d bytes)", MIN_UDP_BLOCKSIZE, MAX_UDP_BLOCKSIZE);
190190
break;
191+
case IEUDPCNTLONLYUDP:
192+
snprintf(errstr, len, "UDP Control Socket is supported only in UDP test");
193+
break;
191194
case IEBADTOS:
192195
snprintf(errstr, len, "bad TOS value (must be between 0 and 255 inclusive)");
193196
break;

src/iperf_locale.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
131131
#if defined(HAVE_IPPROTO_MPTCP)
132132
" -m, --mptcp use MPTCP rather than plain TCP\n"
133133
#endif
134+
" --udp-control use UDP for the control socket (instead of default TCP)\n"
134135
" -d, --debug[=#] emit debugging output\n"
135136
" (optional optional \"=\" and debug level: 1-4. Default is 4 - all messages)\n"
136137
" -v, --version show version information and quit\n"

src/iperf_server_api.c

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,10 @@ iperf_server_worker_run(void *s) {
112112
int
113113
iperf_server_listen(struct iperf_test *test)
114114
{
115+
int proto = (test->udp_ctrl_sck) ? Pudp : Ptcp;
116+
115117
retry:
116-
if((test->listener = netannounce(test->settings->domain, Ptcp, test->bind_address, test->bind_dev, test->server_port)) < 0) {
118+
if((test->listener = netannounce(test->settings->domain, proto, test->bind_address, test->bind_dev, test->server_port)) < 0) {
117119
if (errno == EAFNOSUPPORT && (test->settings->domain == AF_INET6 || test->settings->domain == AF_UNSPEC)) {
118120
/* If we get "Address family not supported by protocol", that
119121
** probably means we were compiled with IPv6 but the running
@@ -157,32 +159,50 @@ iperf_accept(struct iperf_test *test)
157159
signed char rbuf = ACCESS_DENIED;
158160
socklen_t len;
159161
struct sockaddr_storage addr;
162+
int rc;
160163

161-
len = sizeof(addr);
162-
if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
163-
i_errno = IEACCEPT;
164-
return ret;
164+
if (test->udp_ctrl_sck) { // UDP Control Socket
165+
s = test->listener;
166+
}
167+
else { // TCP Control Socket
168+
len = sizeof(addr);
169+
if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
170+
i_errno = IEACCEPT;
171+
return ret;
172+
}
173+
}
174+
175+
/* UDP listener socket should be accepted to allow communication (including for sending Deny) */
176+
if (test->udp_ctrl_sck) { // UDP Control Socket
177+
if (test->debug_level >= DEBUG_LEVEL_INFO) {
178+
printf("Accepting new Connection Request over UDP socket %d\n", s);
179+
}
180+
if ((rc = iperf_udp_accept_socket(test, s)) < 0) {
181+
return rc;
182+
}
165183
}
166184

167185
if (test->ctrl_sck == -1) {
168186
/* Server free, accept new client */
169187
test->ctrl_sck = s;
170-
// set TCP_NODELAY for lower latency on control messages
171-
int flag = 1;
172-
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int))) {
173-
i_errno = IESETNODELAY;
174-
goto error_handling;
175-
}
188+
if (!test->udp_ctrl_sck) { // TCP Control Socket
189+
// set TCP_NODELAY for lower latency on control messages
190+
int flag = 1;
191+
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int))) {
192+
i_errno = IESETNODELAY;
193+
goto error_handling;
194+
}
176195

177196
#if defined(HAVE_TCP_USER_TIMEOUT)
178-
int opt;
179-
if ((opt = test->settings->snd_timeout)) {
180-
if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
181-
i_errno = IESETUSERTIMEOUT;
182-
goto error_handling;
197+
int opt;
198+
if ((opt = test->settings->snd_timeout)) {
199+
if (setsockopt(s, IPPROTO_TCP, TCP_USER_TIMEOUT, &opt, sizeof(opt)) < 0) {
200+
i_errno = IESETUSERTIMEOUT;
201+
goto error_handling;
202+
}
183203
}
184-
}
185204
#endif /* HAVE_TCP_USER_TIMEOUT */
205+
}
186206

187207
if (Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) != COOKIE_SIZE) {
188208
/*
@@ -220,6 +240,24 @@ iperf_accept(struct iperf_test *test)
220240
if (test->debug)
221241
printf("successfully sent ACCESS_DENIED to an unsolicited connection request during active test\n");
222242
}
243+
244+
// Create new UDP listener socket. Done before closing the previous listener socket to allow the
245+
// ACCESS_DENIED message to be sent out of the server before the socket is closed.
246+
if (test->udp_ctrl_sck) {
247+
FD_CLR(s, &test->read_set);
248+
if (test->debug_level >= DEBUG_LEVEL_INFO) {
249+
printf("Creating new UDP Listener socket\n");
250+
}
251+
if ((test->listener = iperf_udp_listen(test)) < 0) {
252+
return -1;
253+
}
254+
if (test->debug_level >= DEBUG_LEVEL_INFO) {
255+
printf("Created new UDP Listener socket=%d\n", test->listener);
256+
}
257+
FD_SET(test->listener, &test->read_set);
258+
test->max_fd = (test->max_fd < test->listener) ? test->listener : test->max_fd;
259+
}
260+
223261
close(s);
224262
}
225263
return 0;
@@ -839,9 +877,14 @@ iperf_run_server(struct iperf_test *test)
839877

840878
if (rec_streams_accepted == streams_to_rec && send_streams_accepted == streams_to_send) {
841879
if (test->protocol->id != Ptcp) {
842-
FD_CLR(test->prot_listener, &test->read_set);
843-
close(test->prot_listener);
844-
test->prot_listener = -1;
880+
if (test->udp_ctrl_sck) {
881+
test->listener = test->prot_listener;
882+
test->prot_listener = -1;
883+
} else {
884+
FD_CLR(test->prot_listener, &test->read_set);
885+
close(test->prot_listener);
886+
test->prot_listener = -1;
887+
}
845888
} else {
846889
if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
847890
FD_CLR(test->listener, &test->read_set);

0 commit comments

Comments
 (0)