@@ -1155,6 +1155,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
1155
1155
{"idle-timeout" , required_argument , NULL , OPT_IDLE_TIMEOUT },
1156
1156
{"rcv-timeout" , required_argument , NULL , OPT_RCV_TIMEOUT },
1157
1157
{"snd-timeout" , required_argument , NULL , OPT_SND_TIMEOUT },
1158
+ #if defined(HAVE_TCP_KEEPALIVE )
1159
+ {"cntl-ka" , optional_argument , NULL , OPT_CNTL_KA },
1160
+ #endif /* HAVE_TCP_KEEPALIVE */
1158
1161
#if defined(HAVE_IPPROTO_MPTCP )
1159
1162
{"mptcp" , no_argument , NULL , 'm' },
1160
1163
#endif
@@ -1171,6 +1174,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
1171
1174
char * comma ;
1172
1175
#endif /* HAVE_CPU_AFFINITY */
1173
1176
char * slash ;
1177
+ #if defined(HAVE_TCP_KEEPALIVE )
1178
+ char * slash2 ;
1179
+ #endif /* HAVE_TCP_KEEPALIVE */
1174
1180
char * p , * p1 ;
1175
1181
struct xbind_entry * xbe ;
1176
1182
double farg ;
@@ -1539,6 +1545,39 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
1539
1545
snd_timeout_flag = 1 ;
1540
1546
break ;
1541
1547
#endif /* HAVE_TCP_USER_TIMEOUT */
1548
+ #if defined (HAVE_TCP_KEEPALIVE )
1549
+ case OPT_CNTL_KA :
1550
+ test -> settings -> cntl_ka = 1 ;
1551
+ if (optarg ) {
1552
+ slash = strchr (optarg , '/' );
1553
+ if (slash ) {
1554
+ * slash = '\0' ;
1555
+ ++ slash ;
1556
+ slash2 = strchr (slash , '/' );
1557
+ if (slash2 ) {
1558
+ * slash2 = '\0' ;
1559
+ ++ slash2 ;
1560
+ if (strlen (slash2 ) > 0 ) {
1561
+ test -> settings -> cntl_ka_count = atoi (slash2 );
1562
+ }
1563
+ }
1564
+ if (strlen (slash ) > 0 ) {
1565
+ test -> settings -> cntl_ka_interval = atoi (slash );
1566
+ }
1567
+ }
1568
+ if (strlen (optarg ) > 0 ) {
1569
+ test -> settings -> cntl_ka_keepidle = atoi (optarg );
1570
+ }
1571
+ }
1572
+ // Seems that at least in Windows WSL2, TCP keepalive retries full inteval must be
1573
+ // smaller than the idle interval. Otherwise, the keepalive message is sent only once.
1574
+ if (test -> settings -> cntl_ka_keepidle &&
1575
+ test -> settings -> cntl_ka_keepidle <= (test -> settings -> cntl_ka_count * test -> settings -> cntl_ka_interval )) {
1576
+ i_errno = IECNTLKA ;
1577
+ return -1 ;
1578
+ }
1579
+ break ;
1580
+ #endif /* HAVE_TCP_KEEPALIVE */
1542
1581
case 'A' :
1543
1582
#if defined(HAVE_CPU_AFFINITY )
1544
1583
test -> affinity = strtol (optarg , & endptr , 0 );
@@ -3069,6 +3108,10 @@ iperf_defaults(struct iperf_test *testp)
3069
3108
testp -> settings -> rcv_timeout .secs = DEFAULT_NO_MSG_RCVD_TIMEOUT / SEC_TO_mS ;
3070
3109
testp -> settings -> rcv_timeout .usecs = (DEFAULT_NO_MSG_RCVD_TIMEOUT % SEC_TO_mS ) * mS_TO_US ;
3071
3110
testp -> zerocopy = 0 ;
3111
+ testp -> settings -> cntl_ka = 0 ;
3112
+ testp -> settings -> cntl_ka_keepidle = 0 ;
3113
+ testp -> settings -> cntl_ka_interval = 0 ;
3114
+ testp -> settings -> cntl_ka_count = 0 ;
3072
3115
3073
3116
testp -> json_callback = NULL ;
3074
3117
@@ -5296,3 +5339,82 @@ iflush(struct iperf_test *test)
5296
5339
5297
5340
return rc2 ;
5298
5341
}
5342
+
5343
+ #if defined (HAVE_TCP_KEEPALIVE )
5344
+ // Set Control Connection TCP Keepalive (especially useful for long UDP test sessions)
5345
+ int
5346
+ iperf_set_control_keepalive (struct iperf_test * test )
5347
+ {
5348
+ int opt , kaidle , kainterval , kacount ;
5349
+ socklen_t len ;
5350
+
5351
+ if (test -> settings -> cntl_ka ) {
5352
+ // Set keepalive using system defaults
5353
+ opt = 1 ;
5354
+ if (setsockopt (test -> ctrl_sck , SOL_SOCKET , SO_KEEPALIVE , (char * ) & opt , sizeof (opt ))) {
5355
+ i_errno = IESETCNTLKA ;
5356
+ return -1 ;
5357
+ }
5358
+
5359
+ // Get default values when not specified
5360
+ if ((kaidle = test -> settings -> cntl_ka_keepidle ) == 0 ) {
5361
+ len = sizeof (kaidle );
5362
+ if (getsockopt (test -> ctrl_sck , IPPROTO_TCP , TCP_KEEPIDLE , (char * ) & kaidle , & len )) {
5363
+ i_errno = IESETCNTLKAINTERVAL ;
5364
+ return -1 ;
5365
+ }
5366
+ }
5367
+ if ((kainterval = test -> settings -> cntl_ka_interval ) == 0 ) {
5368
+ len = sizeof (kainterval );
5369
+ if (getsockopt (test -> ctrl_sck , IPPROTO_TCP , TCP_KEEPINTVL , (char * ) & kainterval , & len )) {
5370
+ i_errno = IESETCNTLKAINTERVAL ;
5371
+ return -1 ;
5372
+ }
5373
+ }
5374
+ if ((kacount = test -> settings -> cntl_ka_count ) == 0 ) {
5375
+ len = sizeof (kacount );
5376
+ if (getsockopt (test -> ctrl_sck , IPPROTO_TCP , TCP_KEEPCNT , (char * ) & kacount , & len )) {
5377
+ i_errno = IESETCNTLKACOUNT ;
5378
+ return -1 ;
5379
+ }
5380
+ }
5381
+
5382
+ // Seems that at least in Windows WSL2, TCP keepalive retries full inteval must be
5383
+ // smaller than the idle interval. Otherwise, the keepalive message is sent only once.
5384
+ if (test -> settings -> cntl_ka_keepidle ) {
5385
+ if (test -> settings -> cntl_ka_keepidle <= (kainterval * kacount )) {
5386
+ iperf_err (test , "Keepalive Idle time (%d) should be greater than Retries-interval (%d) times Retries-count (%d)" , kaidle , kainterval , kacount );
5387
+ i_errno = IECNTLKA ;
5388
+ return -1 ;
5389
+ }
5390
+ }
5391
+
5392
+ // Set keep alive values when specified
5393
+ if ((opt = test -> settings -> cntl_ka_keepidle )) {
5394
+ if (setsockopt (test -> ctrl_sck , IPPROTO_TCP , TCP_KEEPIDLE , (char * ) & opt , sizeof (opt ))) {
5395
+ i_errno = IESETCNTLKAKEEPIDLE ;
5396
+ return -1 ;
5397
+ }
5398
+ }
5399
+ if ((opt = test -> settings -> cntl_ka_interval )) {
5400
+ if (setsockopt (test -> ctrl_sck , IPPROTO_TCP , TCP_KEEPINTVL , (char * ) & opt , sizeof (opt ))) {
5401
+ i_errno = IESETCNTLKAINTERVAL ;
5402
+ return -1 ;
5403
+ }
5404
+ }
5405
+ if ((opt = test -> settings -> cntl_ka_count )) {
5406
+ if (setsockopt (test -> ctrl_sck , IPPROTO_TCP , TCP_KEEPCNT , (char * ) & opt , sizeof (opt ))) {
5407
+ i_errno = IESETCNTLKACOUNT ;
5408
+ return -1 ;
5409
+ }
5410
+ }
5411
+
5412
+ if (test -> verbose ) {
5413
+ printf ("Control connection TCP Keepalive TCP_KEEPIDLE/TCP_KEEPINTVL/TCP_KEEPCNT are set to %d/%d/%d\n" ,
5414
+ kaidle , kainterval , kacount );
5415
+ }
5416
+ }
5417
+
5418
+ return 0 ;
5419
+ }
5420
+ #endif //HAVE_TCP_KEEPALIVE
0 commit comments