Skip to content

Commit 022772d

Browse files
committed
Fix for issues #472/1161 - support parallel UDP stearms under Cygwin
1 parent 3b31c4b commit 022772d

File tree

7 files changed

+100
-8
lines changed

7 files changed

+100
-8
lines changed

src/iperf.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ struct iperf_test
272272
TAILQ_HEAD(xbind_addrhead, xbind_entry) xbind_addrs; /* all -X opts */
273273
int bind_port; /* --cport option */
274274
int server_port;
275+
int num_of_server_ports; /* second value of --port option */
276+
int server_udp_streams_accepted; /* offset of last server port used - 0 means none used (max `num_of_server_ports`) */
275277
int omit; /* duration of omit period (-O flag) */
276278
int duration; /* total duration of test (-t flag) */
277279
char *diskfile_name; /* -F option */
@@ -397,6 +399,9 @@ struct iperf_test
397399
#define OMIT 0 /* seconds */
398400
#define DURATION 10 /* seconds */
399401

402+
#define UDP_STREAM_INIT_REQ_DATAGRAM 123456789
403+
#define UDP_STREAM_INIT_RESP_DATAGRAM 987654321
404+
400405
#define SEC_TO_NS 1000000000LL /* too big for enum/const on some platforms */
401406
#define MAX_RESULT_STRING 4096
402407

src/iperf_api.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,21 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
10331033
while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) {
10341034
switch (flag) {
10351035
case 'p':
1036+
slash = strchr(optarg, '/');
1037+
if (slash) {
1038+
*slash = '\0';
1039+
++slash;
1040+
if (*slash != '\0') {
1041+
test->num_of_server_ports = atoi(slash);
1042+
if (test->num_of_server_ports < 1 || test->num_of_server_ports > MAX_STREAMS) {
1043+
i_errno = IENUMPORTS;
1044+
return -1;
1045+
}
1046+
if (test->num_of_server_ports > 1) {
1047+
server_flag = 1;
1048+
}
1049+
}
1050+
}
10361051
portno = atoi(optarg);
10371052
if (portno < 1 || portno > 65535) {
10381053
i_errno = IEBADPORT;
@@ -1898,6 +1913,26 @@ iperf_exchange_parameters(struct iperf_test *test)
18981913
if (get_parameters(test) < 0)
18991914
return -1;
19001915

1916+
// Check spcific conditions required for UDP under Cygwin as it does not support parallel stream using same port
1917+
if (test->protocol->id == Pudp) {
1918+
// Ensure UDP ports pool size if large enough for the required number of streams
1919+
if (test->num_of_server_ports > 1) {
1920+
if (test->num_of_server_ports < test->num_streams) {
1921+
i_errno = IEPORTNUM;
1922+
return -1;
1923+
}
1924+
}
1925+
#if defined(__CYGWIN__)
1926+
else {
1927+
// Parallel UDP streams under Cygwin must use different port number per stream
1928+
if (test->num_streams > 1) {
1929+
i_errno = IECYGWINPORTSUDP;
1930+
return -1;
1931+
}
1932+
}
1933+
#endif /* __CYGWIN__ */
1934+
}
1935+
19011936
#if defined(HAVE_SSL)
19021937
if (test_is_authorized(test) < 0){
19031938
if (iperf_set_send_state(test, SERVER_ERROR) != 0)
@@ -1913,7 +1948,7 @@ iperf_exchange_parameters(struct iperf_test *test)
19131948
#endif //HAVE_SSL
19141949

19151950
if ((s = test->protocol->listen(test)) < 0) {
1916-
if (iperf_set_send_state(test, SERVER_ERROR) != 0)
1951+
if (iperf_set_send_state(test, SERVER_ERROR) != 0)
19171952
return -1;
19181953
err = htonl(i_errno);
19191954
if (Nwrite(test->ctrl_sck, (char*) &err, sizeof(err), Ptcp) < 0) {
@@ -2631,6 +2666,8 @@ iperf_defaults(struct iperf_test *testp)
26312666
testp->congestion_used = NULL;
26322667
testp->remote_congestion_used = NULL;
26332668
testp->server_port = PORT;
2669+
testp->num_of_server_ports = 0;
2670+
testp->server_udp_streams_accepted = 0;
26342671
testp->ctrl_sck = -1;
26352672
testp->prot_listener = -1;
26362673
testp->other_side_has_retransmits = 0;
@@ -2904,6 +2941,7 @@ iperf_reset_test(struct iperf_test *test)
29042941
test->mode = RECEIVER;
29052942
test->sender_has_retransmits = 0;
29062943
set_protocol(test, Ptcp);
2944+
test->server_udp_streams_accepted = 0;
29072945
test->omit = OMIT;
29082946
test->duration = DURATION;
29092947
test->server_affinity = -1;

src/iperf_api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,9 @@ enum {
379379
IEIDLETIMEOUT = 30, // Invalid value specified as idle state timeout
380380
IERCVTIMEOUT = 31, // Illegal message receive timeout
381381
IERVRSONLYRCVTIMEOUT = 32, // Client receive timeout is valid only in reverse mode
382+
IENUMPORTS = 33, // number of ports is less than 1 or larger than server limit
383+
IEPORTNUM = 34, // requested number of parallel streams is larger than the number of ports set for the server
384+
IECYGWINPORTSUDP = 35, // different port (parameter `-p #/<num of ports>`) should be available for parallel UDP streams under Cygwin
382385
/* Test errors */
383386
IENEWTEST = 100, // Unable to create a new test (check perror)
384387
IEINITTEST = 101, // Test initialization failed (check perror)

src/iperf_error.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ iperf_strerror(int int_errno)
432432
case IETOTALRATE:
433433
snprintf(errstr, len, "total required bandwidth is larger than server limit");
434434
break;
435-
case IESKEWTHRESHOLD:
435+
case IESKEWTHRESHOLD:
436436
snprintf(errstr, len, "skew threshold must be a positive number");
437437
break;
438438
case IEIDLETIMEOUT:
@@ -441,9 +441,18 @@ iperf_strerror(int int_errno)
441441
case IENOMSG:
442442
snprintf(errstr, len, "idle timeout for receiving data");
443443
break;
444-
case IESETDONTFRAGMENT:
444+
case IESETDONTFRAGMENT:
445445
snprintf(errstr, len, "unable to set IP Do-Not-Fragment flag");
446446
break;
447+
case IENUMPORTS:
448+
snprintf(errstr, len, "number of ports is less than 1 or larger than server limit");
449+
break;
450+
case IEPORTNUM:
451+
snprintf(errstr, len, "requested number of parallel streams is larger than the number of ports set for the server");
452+
break;
453+
case IECYGWINPORTSUDP:
454+
snprintf(errstr, len, "different port (parameter `-p #/<num of ports>`) should be available for parallel UDP streams under Cygwin");
455+
break;
447456
default:
448457
snprintf(errstr, len, "int_errno=%d", int_errno);
449458
perr = 1;

src/iperf_locale.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ const char usage_shortstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
9797
const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
9898
" iperf3 [-h|--help] [-v|--version]\n\n"
9999
"Server or Client:\n"
100-
" -p, --port # server port to listen on/connect to\n"
100+
" -p, --port #[/#] server port to listen on/connect to\n"
101+
" (optional for server UDP: pool size of ports starting with\n"
102+
" port # - required for parallel UDP sterams under cygwin)\n"
101103
" -f, --format [kmgtKMGT] format to report: Kbits, Mbits, Gbits, Tbits\n"
102104
" -i, --interval # seconds between periodic throughput reports\n"
103105
" -I, --pidfile file write PID file\n"

src/iperf_server_api.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ static void
371371
cleanup_server(struct iperf_test *test)
372372
{
373373
struct iperf_stream *sp;
374+
int i;
374375

375376
/* Close open streams */
376377
SLIST_FOREACH(sp, &test->streams, streams) {
@@ -390,6 +391,12 @@ cleanup_server(struct iperf_test *test)
390391
close(test->prot_listener);
391392
}
392393

394+
/* Close all listening ports in case pool of listening ports is used */
395+
for (i = 0; i <= test->server_udp_streams_accepted; i++) {
396+
printf("***** Closing UDP port %d;\n", test->server_port + i);
397+
close(test->server_port + i);
398+
}
399+
393400
/* Cancel any remaining timers. */
394401
if (test->stats_timer != NULL) {
395402
tmr_cancel(test->stats_timer);

src/iperf_udp.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ iperf_udp_accept(struct iperf_test *test)
369369
socklen_t len;
370370
int sz, s;
371371
int rc;
372+
int port;
372373

373374
/*
374375
* Get the current outstanding socket. This socket will be used to handle
@@ -437,10 +438,28 @@ iperf_udp_accept(struct iperf_test *test)
437438
}
438439
}
439440

441+
442+
/*
443+
* Set listening por for accepting next parallel stream request.
444+
* Use differet port per stream when pool of ports was defined.
445+
* (required to support parallel stream under Windows cygwin.)
446+
*/
447+
buf = UDP_STREAM_INIT_RESP_DATAGRAM;
448+
port = test->server_port;
449+
if (test->num_of_server_ports > 1) {
450+
if (test->server_udp_streams_accepted >= test->num_of_server_ports) {
451+
i_errno = IEPORTNUM;
452+
return -1;
453+
}
454+
test->server_udp_streams_accepted++;
455+
port += test->server_udp_streams_accepted;
456+
buf = port;
457+
}
458+
440459
/*
441460
* Create a new "listening" socket to replace the one we were using before.
442461
*/
443-
test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, test->server_port);
462+
test->prot_listener = netannounce(test->settings->domain, Pudp, test->bind_address, test->bind_dev, port);
444463
if (test->prot_listener < 0) {
445464
i_errno = IESTREAMLISTEN;
446465
return -1;
@@ -449,8 +468,10 @@ iperf_udp_accept(struct iperf_test *test)
449468
FD_SET(test->prot_listener, &test->read_set);
450469
test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd;
451470

452-
/* Let the client know we're ready "accept" another UDP "stream" */
453-
buf = 987654321; /* any content will work here */
471+
/*
472+
* Let the client know we're ready "accept" another UDP "stream",
473+
* and send the listening port when applicable.
474+
*/
454475
if (write(s, &buf, sizeof(buf)) < 0) {
455476
i_errno = IESTREAMWRITE;
456477
return -1;
@@ -560,7 +581,7 @@ iperf_udp_connect(struct iperf_test *test)
560581
* Write a datagram to the UDP stream to let the server know we're here.
561582
* The server learns our address by obtaining its peer's address.
562583
*/
563-
buf = 123456789; /* this can be pretty much anything */
584+
buf = UDP_STREAM_INIT_REQ_DATAGRAM; /* this can be pretty much anything */
564585
if (write(s, &buf, sizeof(buf)) < 0) {
565586
// XXX: Should this be changed to IESTREAMCONNECT?
566587
i_errno = IESTREAMWRITE;
@@ -575,6 +596,13 @@ iperf_udp_connect(struct iperf_test *test)
575596
return -1;
576597
}
577598

599+
/*
600+
* If the recived value is a port number, use it as the next connection port
601+
*/
602+
if (buf != UDP_STREAM_INIT_RESP_DATAGRAM) {
603+
test->server_port = buf;
604+
}
605+
578606
return s;
579607
}
580608

0 commit comments

Comments
 (0)