Add TCP keep-alive options to rtc::Socket

Enabling Socket options on keep-alive related function that may enable clients to detect any stale connection early on.

Bug: webrtc:15866
Change-Id: Ib4f15e0c933aeb6cf4fd18ff8cc708d118ea8645
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/342223
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Tim Na <natim@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41888}
This commit is contained in:
Tim Na 2024-03-12 10:48:19 -07:00 committed by WebRTC LUCI CQ
parent f3096afd48
commit 4473d75651
3 changed files with 73 additions and 1 deletions

View file

@ -782,6 +782,35 @@ int PhysicalSocket::TranslateOption(Option opt, int* slevel, int* sopt) {
#endif
case OPT_RTP_SENDTIME_EXTN_ID:
return -1; // No logging is necessary as this not a OS socket option.
case OPT_KEEPALIVE:
*slevel = SOL_SOCKET;
*sopt = SO_KEEPALIVE;
break;
case OPT_TCP_KEEPCNT:
*slevel = IPPROTO_TCP;
*sopt = TCP_KEEPCNT;
break;
case OPT_TCP_KEEPIDLE:
*slevel = IPPROTO_TCP;
#if !defined(WEBRTC_MAC)
*sopt = TCP_KEEPIDLE;
#else
*sopt = TCP_KEEPALIVE;
#endif
break;
case OPT_TCP_KEEPINTVL:
*slevel = IPPROTO_TCP;
*sopt = TCP_KEEPINTVL;
break;
case OPT_TCP_USER_TIMEOUT:
#if defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
*slevel = IPPROTO_TCP;
*sopt = TCP_USER_TIMEOUT;
break;
#else
RTC_LOG(LS_WARNING) << "Socket::OPT_TCP_USER_TIMEOUT not supported.";
return -1;
#endif
default:
RTC_DCHECK_NOTREACHED();
return -1;

View file

@ -147,7 +147,12 @@ class RTC_EXPORT Socket {
// This is specific to libjingle and will be used
// if SendTime option is needed at socket level.
OPT_SEND_ECN, // 2-bit ECN
OPT_RECV_ECN
OPT_RECV_ECN,
OPT_KEEPALIVE, // Enable socket keep alive
OPT_TCP_KEEPCNT, // Set TCP keep alive count
OPT_TCP_KEEPIDLE, // Set TCP keep alive idle time in seconds
OPT_TCP_KEEPINTVL, // Set TCP keep alive interval in seconds
OPT_TCP_USER_TIMEOUT, // Set TCP user timeout
};
virtual int GetOption(Option opt, int* value) = 0;
virtual int SetOption(Option opt, int value) = 0;

View file

@ -1101,6 +1101,44 @@ void SocketTest::GetSetOptionsInternal(const IPAddress& loopback) {
ASSERT_NE(-1, socket->GetOption(Socket::OPT_RECV_ECN, &current_recv_esn));
ASSERT_EQ(current_recv_esn, desired_recv_esn);
#endif
// Prepare on TCP specific options.
socket.reset(socket_factory_->CreateSocket(loopback.family(), SOCK_STREAM));
socket->Bind(SocketAddress(loopback, 0));
// Check that we can set NODELAY on a TCP socket.
ASSERT_NE(-1, socket->SetOption(Socket::OPT_NODELAY, desired_nd));
ASSERT_NE(-1, socket->GetOption(Socket::OPT_NODELAY, &current_nd));
ASSERT_NE(0, current_nd);
// Check TCP Keep Alive settings.
int current_kl, desired_kl = 1;
ASSERT_NE(-1, socket->SetOption(Socket::OPT_KEEPALIVE, desired_kl));
ASSERT_NE(-1, socket->GetOption(Socket::OPT_KEEPALIVE, &current_kl));
ASSERT_NE(0, current_kl);
int current_kl_cnt, desired_kl_cnt = 3;
ASSERT_NE(-1, socket->SetOption(Socket::OPT_TCP_KEEPCNT, desired_kl_cnt));
ASSERT_NE(-1, socket->GetOption(Socket::OPT_TCP_KEEPCNT, &current_kl_cnt));
ASSERT_EQ(desired_kl_cnt, current_kl_cnt);
int current_kl_idle, desired_kl_idle = 2;
ASSERT_NE(-1, socket->SetOption(Socket::OPT_TCP_KEEPIDLE, desired_kl_idle));
ASSERT_NE(-1, socket->GetOption(Socket::OPT_TCP_KEEPIDLE, &current_kl_idle));
ASSERT_EQ(desired_kl_idle, current_kl_idle);
int current_kl_intvl, desired_kl_intvl = 2;
ASSERT_NE(-1, socket->SetOption(Socket::OPT_TCP_KEEPINTVL, desired_kl_intvl));
ASSERT_NE(-1,
socket->GetOption(Socket::OPT_TCP_KEEPINTVL, &current_kl_intvl));
ASSERT_EQ(desired_kl_intvl, current_kl_intvl);
#if defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
int current_ut, desired_ut = 10;
ASSERT_NE(-1, socket->SetOption(Socket::OPT_TCP_USER_TIMEOUT, desired_ut));
ASSERT_NE(-1, socket->GetOption(Socket::OPT_TCP_USER_TIMEOUT, &current_ut));
ASSERT_EQ(desired_ut, current_ut);
#endif
}
void SocketTest::SocketRecvTimestamp(const IPAddress& loopback) {