Skip to content

Commit 266ca8d

Browse files
committed
Set Control Connection Keepalive also on server side (with some improvements)
1 parent 1c736a6 commit 266ca8d

File tree

8 files changed

+2950
-3585
lines changed

8 files changed

+2950
-3585
lines changed

configure

Lines changed: 2838 additions & 3502 deletions
Large diffs are not rendered by default.

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
# file for complete information.
2525

2626
# Initialize the autoconf system for the specified tool, version and mailing list
27-
AC_PREREQ([2.71])
27+
AC_PREREQ([2.69])
2828
AC_INIT([iperf],[3.13],[https://github.com/esnet/iperf],[iperf],[https://software.es.net/iperf/])
2929
m4_include([config/ax_check_openssl.m4])
3030
m4_include([config/iperf_config_static_bin.m4])

src/iperf_api.c

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,6 +1510,13 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
15101510
test->settings->cntl_ka_keepidle = atoi(optarg);
15111511
}
15121512
}
1513+
// Seems that at least in Windows WSL2, TCP keepalive retries full inteval must be
1514+
// smaller than the idle interval. Otherwise, the keepalive message is sent only once.
1515+
if (test->settings->cntl_ka_keepidle &&
1516+
test->settings->cntl_ka_keepidle <= (test->settings->cntl_ka_count * test->settings->cntl_ka_interval)) {
1517+
i_errno = IECNTLKA;
1518+
return -1;
1519+
}
15131520
break;
15141521
#endif /* HAVE_TCP_KEEPALIVE */
15151522
case 'A':
@@ -3155,10 +3162,6 @@ iperf_reset_test(struct iperf_test *test)
31553162
test->settings->tos = 0;
31563163
test->settings->dont_fragment = 0;
31573164
test->zerocopy = 0;
3158-
test->settings->cntl_ka = 0;
3159-
test->settings->cntl_ka_keepidle = 0;
3160-
test->settings->cntl_ka_interval = 0;
3161-
test->settings->cntl_ka_count = 0;
31623165

31633166
#if defined(HAVE_SSL)
31643167
if (test->settings->authtoken) {
@@ -4911,3 +4914,82 @@ iflush(struct iperf_test *test)
49114914
{
49124915
return fflush(test->outfile);
49134916
}
4917+
4918+
#if defined (HAVE_TCP_KEEPALIVE)
4919+
// Set Control Connection TCP Keepalive (especially useful for long UDP test sessions)
4920+
int
4921+
iperf_set_control_keepalive(struct iperf_test *test)
4922+
{
4923+
int opt, kaidle, kainterval, kacount;
4924+
socklen_t len;
4925+
4926+
if (test->settings->cntl_ka) {
4927+
// Set keepalive using system defaults
4928+
opt = 1;
4929+
if (setsockopt(test->ctrl_sck, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt))) {
4930+
i_errno = IESETCNTLKA;
4931+
return -1;
4932+
}
4933+
4934+
// Get default values when not specified
4935+
if ((kaidle = test->settings->cntl_ka_keepidle) == 0) {
4936+
len = sizeof(kaidle);
4937+
if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPIDLE, (char *) &kaidle, &len)) {
4938+
i_errno = IESETCNTLKAINTERVAL;
4939+
return -1;
4940+
}
4941+
}
4942+
if ((kainterval = test->settings->cntl_ka_interval) == 0) {
4943+
len = sizeof(kainterval);
4944+
if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &kainterval, &len)) {
4945+
i_errno = IESETCNTLKAINTERVAL;
4946+
return -1;
4947+
}
4948+
}
4949+
if ((kacount = test->settings->cntl_ka_count) == 0) {
4950+
len = sizeof(kacount);
4951+
if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPCNT, (char *) &kacount, &len)) {
4952+
i_errno = IESETCNTLKACOUNT;
4953+
return -1;
4954+
}
4955+
}
4956+
4957+
if (test->verbose) {
4958+
printf("Control connection TCP Keepalive TCP_KEEPIDLE/TCP_KEEPINTVL/TCP_KEEPCNT are set to %d/%d/%d\n",
4959+
kaidle, kainterval, kacount);
4960+
}
4961+
4962+
// Seems that at least in Windows WSL2, TCP keepalive retries full inteval must be
4963+
// smaller than the idle interval. Otherwise, the keepalive message is sent only once.
4964+
if (test->settings->cntl_ka_keepidle) {
4965+
if (test->settings->cntl_ka_keepidle <= (kainterval * kacount)) {
4966+
iperf_err(test, "Keepalive Idle time (%d) should be greater than Retries-interval (%d) times Retries-count (%d)", kaidle, kainterval, kacount);
4967+
i_errno = IECNTLKA;
4968+
return -1;
4969+
}
4970+
}
4971+
4972+
// Set keep alive values when specified
4973+
if ((opt = test->settings->cntl_ka_keepidle)) {
4974+
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPIDLE, (char *) &opt, sizeof(opt))) {
4975+
i_errno = IESETCNTLKAKEEPIDLE;
4976+
return -1;
4977+
}
4978+
}
4979+
if ((opt = test->settings->cntl_ka_interval)) {
4980+
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &opt, sizeof(opt))) {
4981+
i_errno = IESETCNTLKAINTERVAL;
4982+
return -1;
4983+
}
4984+
}
4985+
if ((opt = test->settings->cntl_ka_count)) {
4986+
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPCNT, (char *) &opt, sizeof(opt))) {
4987+
i_errno = IESETCNTLKACOUNT;
4988+
return -1;
4989+
}
4990+
}
4991+
}
4992+
4993+
return 0;
4994+
}
4995+
#endif //HAVE_TCP_KEEPALIVE

src/iperf_api.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,14 @@ void iperf_free_stream(struct iperf_stream * sp);
293293
*/
294294
int iperf_common_sockopts(struct iperf_test *, int s);
295295

296+
#if defined (HAVE_TCP_KEEPALIVE)
297+
/**
298+
* iperf_set_control_keepalive -- set control connection TCP keepalive
299+
*
300+
*/
301+
int iperf_set_control_keepalive(struct iperf_test *test);
302+
#endif //HAVE_TCP_KEEPALIVE
303+
296304
int has_tcpinfo(void);
297305
int has_tcpinfo_retransmits(void);
298306
void save_tcpinfo(struct iperf_stream *sp, struct iperf_interval_results *irp);
@@ -402,7 +410,7 @@ enum {
402410
IERCVTIMEOUT = 31, // Illegal message receive timeout
403411
IERVRSONLYRCVTIMEOUT = 32, // Client receive timeout is valid only in reverse mode
404412
IESNDTIMEOUT = 33, // Illegal message send timeout
405-
IECNTLKA = 34, // Control connection Keepalive period should be larger than retry period (interval * count)
413+
IECNTLKA = 34, // Control connection Keepalive period should be larger than the full retry period (interval * count)
406414
/* Test errors */
407415
IENEWTEST = 100, // Unable to create a new test (check perror)
408416
IEINITTEST = 101, // Test initialization failed (check perror)

src/iperf_client_api.c

Lines changed: 2 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,6 @@ iperf_connect(struct iperf_test *test)
364364
{
365365
int opt;
366366
socklen_t len;
367-
#if defined(HAVE_TCP_KEEPALIVE)
368-
int kainterval, kacount;
369-
#endif /* HAVE_TCP_KEEPALIVE */
370367

371368
if (NULL == test)
372369
{
@@ -395,74 +392,9 @@ iperf_connect(struct iperf_test *test)
395392
}
396393

397394
#if defined (HAVE_TCP_KEEPALIVE)
398-
// Set Control Connection TCP Keepalive (especially useful for long UDP test sessions)
399-
if (test->settings->cntl_ka) {
400-
opt = 1;
401-
if (setsockopt(test->ctrl_sck, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof(opt))) {
402-
i_errno = IESETCNTLKA;
395+
// Set Control Connection TCP Keepalive (especially useful for long UDP test sessions)
396+
if (iperf_set_control_keepalive(test) < 0)
403397
return -1;
404-
}
405-
406-
if ((opt = test->settings->cntl_ka_keepidle)) {
407-
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPIDLE, (char *) &opt, sizeof(opt))) {
408-
i_errno = IESETCNTLKAKEEPIDLE;
409-
return -1;
410-
}
411-
}
412-
413-
// Seems that at least in Windows WSL2, TCP keepalive retries inteval must be smaller
414-
// than keepalive interval. Otherwise, the keepalive message is sent only once.
415-
// To make sure issues will not impact the tests in case the keepalive period was set,
416-
// when possible it is made sure that the full keepalive retries interval is less
417-
// than the the keepalive period.
418-
if (test->settings->cntl_ka_keepidle) {
419-
if ((kainterval = test->settings->cntl_ka_interval) == 0) {
420-
len = sizeof(kainterval);
421-
if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &kainterval, &len)) {
422-
i_errno = IESETCNTLKAINTERVAL;
423-
return -1;
424-
}
425-
}
426-
if ((kacount = test->settings->cntl_ka_count) == 0) {
427-
len = sizeof(kacount);
428-
if (getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPCNT, (char *) &kacount, &len)) {
429-
i_errno = IESETCNTLKACOUNT;
430-
return -1;
431-
}
432-
}
433-
434-
if (test->settings->cntl_ka_keepidle <= (kainterval * kacount)) {
435-
if (test->settings->cntl_ka_interval > 0 || test->settings->cntl_ka_count > 0) {
436-
i_errno = IECNTLKA;
437-
return -1;
438-
}
439-
if (kacount > 0) {
440-
test->settings->cntl_ka_interval = ((test->settings->cntl_ka_keepidle - 1) / kacount);
441-
if (test->settings->cntl_ka_interval <= 0) {
442-
test->settings->cntl_ka_interval = 1;
443-
}
444-
}
445-
}
446-
}
447-
448-
if ((opt = test->settings->cntl_ka_interval)) {
449-
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPINTVL, (char *) &opt, sizeof(opt))) {
450-
i_errno = IESETCNTLKAINTERVAL;
451-
return -1;
452-
}
453-
}
454-
if ((opt = test->settings->cntl_ka_count)) {
455-
if (setsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_KEEPCNT, (char *) &opt, sizeof(opt))) {
456-
i_errno = IESETCNTLKACOUNT;
457-
return -1;
458-
}
459-
}
460-
461-
if (test->verbose) {
462-
printf("Control connection TCP Keepalive TCP_KEEPIDLE/TCP_KEEPINTVL/TCP_KEEPCNT set to %d/%d/%d (0 is system default)\n",
463-
test->settings->cntl_ka_keepidle, test->settings->cntl_ka_interval, test->settings->cntl_ka_count);
464-
}
465-
}
466398
#endif //HAVE_TCP_KEEPALIVE
467399

468400
#if defined(HAVE_TCP_USER_TIMEOUT)

src/iperf_config.h.in

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
/* Define to 1 if you have the <linux/tcp.h> header file. */
4343
#undef HAVE_LINUX_TCP_H
4444

45+
/* Define to 1 if you have the <memory.h> header file. */
46+
#undef HAVE_MEMORY_H
47+
4548
/* Define to 1 if you have the <netinet/sctp.h> header file. */
4649
#undef HAVE_NETINET_SCTP_H
4750

@@ -72,9 +75,6 @@
7275
/* Define to 1 if you have the <stdint.h> header file. */
7376
#undef HAVE_STDINT_H
7477

75-
/* Define to 1 if you have the <stdio.h> header file. */
76-
#undef HAVE_STDIO_H
77-
7878
/* Define to 1 if you have the <stdlib.h> header file. */
7979
#undef HAVE_STDLIB_H
8080

@@ -105,6 +105,9 @@
105105
/* Have tcpi_snd_wnd field in tcp_info. */
106106
#undef HAVE_TCP_INFO_SND_WND
107107

108+
/* Have TCP_KEEPIDLE sockopt. */
109+
#undef HAVE_TCP_KEEPALIVE
110+
108111
/* Have TCP_USER_TIMEOUT sockopt. */
109112
#undef HAVE_TCP_USER_TIMEOUT
110113

@@ -135,9 +138,7 @@
135138
/* Define to the version of this package. */
136139
#undef PACKAGE_VERSION
137140

138-
/* Define to 1 if all of the C90 standard headers exist (not just the ones
139-
required in a freestanding environment). This macro is provided for
140-
backward compatibility; new code need not use it. */
141+
/* Define to 1 if you have the ANSI C header files. */
141142
#undef STDC_HEADERS
142143

143144
/* Version number of package */

src/iperf_error.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ iperf_strerror(int int_errno)
463463
perr = 1;
464464
break;
465465
case IECNTLKA:
466-
snprintf(errstr, len, "control connection Keepalive period should be larger than retry period (interval * count)");
466+
snprintf(errstr, len, "control connection Keepalive period should be larger than the full retry period (interval * count)");
467467
perr = 1;
468468
break;
469469
case IESETCNTLKA:

src/iperf_server_api.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ iperf_accept(struct iperf_test *test)
140140
}
141141
#endif /* HAVE_TCP_USER_TIMEOUT */
142142

143+
#if defined (HAVE_TCP_KEEPALIVE)
144+
// Set Control Connection TCP Keepalive (especially useful for long UDP test sessions)
145+
if (iperf_set_control_keepalive(test) < 0)
146+
return -1;
147+
#endif //HAVE_TCP_KEEPALIVE
148+
143149
if (Nread(test->ctrl_sck, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
144150
i_errno = IERECVCOOKIE;
145151
return -1;

0 commit comments

Comments
 (0)