From ecd6fc84cf070865eaa131a35b77ef9cdff4cbfc Mon Sep 17 00:00:00 2001 From: Taylor Brandstetter Date: Wed, 5 Feb 2020 17:26:37 -0800 Subject: [PATCH] Add DSCP support for POSIX platforms. This CL only includes the necessary changes in PhysicalSocketServer, and doesn't include the Java or Objective C API. Note that this is doing exactly the same thing as UDPSocketPosix in chromium. BUG=webrtc:5658 Change-Id: I295455eaccba2a83cdd1bc55848f325c310f8d32 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168260 Reviewed-by: Harald Alvestrand Reviewed-by: Qingsi Wang Commit-Queue: Taylor Cr-Commit-Position: refs/heads/master@{#30478} --- rtc_base/physical_socket_server.cc | 33 +++++++++++++++++++++++++++++- rtc_base/physical_socket_server.h | 3 ++- rtc_base/socket_unittest.cc | 9 ++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/rtc_base/physical_socket_server.cc b/rtc_base/physical_socket_server.cc index bd6a324ca9..08947e16e4 100644 --- a/rtc_base/physical_socket_server.cc +++ b/rtc_base/physical_socket_server.cc @@ -140,6 +140,7 @@ bool PhysicalSocket::Create(int family, int type) { Close(); s_ = ::socket(family, type, 0); udp_ = (SOCK_DGRAM == type); + family_ = family; UpdateLastError(); if (udp_) { SetEnabledEvents(DE_READ | DE_WRITE); @@ -289,9 +290,17 @@ int PhysicalSocket::GetOption(Option opt, int* value) { return -1; socklen_t optlen = sizeof(*value); int ret = ::getsockopt(s_, slevel, sopt, (SockOptArg)value, &optlen); - if (ret != -1 && opt == OPT_DONTFRAGMENT) { + if (ret == -1) { + return -1; + } + if (opt == OPT_DONTFRAGMENT) { #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) *value = (*value != IP_PMTUDISC_DONT) ? 1 : 0; +#endif + } else if (opt == OPT_DSCP) { +#if defined(WEBRTC_POSIX) + // unshift DSCP value to get six most significant bits of IP DiffServ field + *value >>= 2; #endif } return ret; @@ -305,8 +314,19 @@ int PhysicalSocket::SetOption(Option opt, int value) { if (opt == OPT_DONTFRAGMENT) { #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) value = (value) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; +#endif + } else if (opt == OPT_DSCP) { +#if defined(WEBRTC_POSIX) + // shift DSCP value to fit six most significant bits of IP DiffServ field + value <<= 2; #endif } +#if defined(WEBRTC_POSIX) + if (sopt == IPV6_TCLASS) { + // Set the IPv4 option in all cases to support dual-stack sockets. + ::setsockopt(s_, IPPROTO_IP, IP_TOS, (SockOptArg)&value, sizeof(value)); + } +#endif return ::setsockopt(s_, slevel, sopt, (SockOptArg)&value, sizeof(value)); } @@ -554,8 +574,19 @@ int PhysicalSocket::TranslateOption(Option opt, int* slevel, int* sopt) { *sopt = TCP_NODELAY; break; case OPT_DSCP: +#if defined(WEBRTC_POSIX) + if (family_ == AF_INET6) { + *slevel = IPPROTO_IPV6; + *sopt = IPV6_TCLASS; + } else { + *slevel = IPPROTO_IP; + *sopt = IP_TOS; + } + break; +#else RTC_LOG(LS_WARNING) << "Socket::OPT_DSCP not supported."; return -1; +#endif case OPT_RTP_SENDTIME_EXTN_ID: return -1; // No logging is necessary as this not a OS socket option. default: diff --git a/rtc_base/physical_socket_server.h b/rtc_base/physical_socket_server.h index e85b2b0f1e..a71810f3db 100644 --- a/rtc_base/physical_socket_server.h +++ b/rtc_base/physical_socket_server.h @@ -199,11 +199,12 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> { virtual void EnableEvents(uint8_t events); virtual void DisableEvents(uint8_t events); - static int TranslateOption(Option opt, int* slevel, int* sopt); + int TranslateOption(Option opt, int* slevel, int* sopt); PhysicalSocketServer* ss_; SOCKET s_; bool udp_; + int family_ = 0; CriticalSection crit_; int error_ RTC_GUARDED_BY(crit_); ConnState state_; diff --git a/rtc_base/socket_unittest.cc b/rtc_base/socket_unittest.cc index 2af3a8ef88..6ea4b47bd1 100644 --- a/rtc_base/socket_unittest.cc +++ b/rtc_base/socket_unittest.cc @@ -1027,6 +1027,15 @@ void SocketTest::GetSetOptionsInternal(const IPAddress& loopback) { int current_nd, desired_nd = 1; ASSERT_EQ(-1, socket->GetOption(Socket::OPT_NODELAY, ¤t_nd)); ASSERT_EQ(-1, socket->SetOption(Socket::OPT_NODELAY, desired_nd)); + +#if defined(WEBRTC_POSIX) + // Check DSCP. + int current_dscp, desired_dscp = 1; + ASSERT_NE(-1, socket->GetOption(Socket::OPT_DSCP, ¤t_dscp)); + ASSERT_NE(-1, socket->SetOption(Socket::OPT_DSCP, desired_dscp)); + ASSERT_NE(-1, socket->GetOption(Socket::OPT_DSCP, ¤t_dscp)); + ASSERT_EQ(desired_dscp, current_dscp); +#endif } void SocketTest::SocketRecvTimestamp(const IPAddress& loopback) {