The TCP_USER_TIMEOUT semantic means when you send an packet, how long time no received the ACK should disconnect the connection. In tcp retransmits case, retransmits_timed_out checkout this timeout, it walks well. but in keepalive case. the code below may have bugs: .... elapsed = keepalive_time_elapsed(tp); if (elapsed >= keepalive_time_when(tp)) { /* If the TCP_USER_TIMEOUT option is enabled, use that * to determine when to timeout instead. */ if ((icsk->icsk_user_timeout != 0 && elapsed >= icsk->icsk_user_timeout && icsk->icsk_probes_out > 0) || (icsk->icsk_user_timeout == 0 && icsk->icsk_probes_out >= keepalive_probes(tp))) { tcp_send_active_reset(sk, GFP_ATOMIC); tcp_write_err(sk); goto out; } ..... elapsed >= icsk->icsk_user_timeout should be elapsed-keepalive_time_when(tp) >= icsk->icsk_user_timeout here is the timeline: idle ....... keepalive1 ...... keepalive2 ... keepalive_probes <- katime_when -> <- keepalive_intvl -> <- TCP_USER_TIMEOUT -> // user expected timeout <---------------elapsed----------------> <-elapsed-katime_when-> /* test code */ int v; v=1;setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &v, 4); v=30;setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &v, 4); v=5;setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &v, 4); v=3;setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &v, 4); v=20*1000; setsockopt(fd, SOL_TCP, TCP_USER_TIMEOUT, &v, 4); connect(fd, addr, sizeof(addr); // when connect // drop the recv data // iptables -t filter -A INPUT --protocol tcp --dport 8888 -j DROP pause(); we can see 30s later, tcp start keepalive, and close connection without do the first retransmits (because 30+5 > 20) but we want waiting 20 second.
That is not a complete program can you send me the complete code as a attachment so I can make sure that there is indeed a issue here. Seems correct but would like to verify it.
your should use tcpdump to catch packet and paste your message.