Ensure ECN can be read from posix socket without OPT_SEND_ECN=1 This fixes a bug where ECN can not be read on a socket even if OPT_RECV_ECN has been called. Bug: webrtc:504789166 Change-Id: Ibc52561502fd84c38e44f886f6759aa6d98a8246 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/465560 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#47494}
diff --git a/rtc_base/physical_socket_server.cc b/rtc_base/physical_socket_server.cc index fb916fb..c439d5f 100644 --- a/rtc_base/physical_socket_server.cc +++ b/rtc_base/physical_socket_server.cc
@@ -372,10 +372,10 @@ // IP DiffServ consists of DSCP 6 most significant, ECN 2 least // significant. dscp_ = value << 2; - value = dscp_ + (ecn_ & kEcnMask); + value = dscp_ + (ecn_send_options_ & kEcnMask); } else if (opt == OPT_SEND_ECN) { - ecn_ = value; - value = dscp_ + (ecn_ & kEcnMask); + ecn_send_options_ = value; + value = dscp_ + (ecn_send_options_ & kEcnMask); } #if defined(WEBRTC_POSIX) if (sopt == IPV6_TCLASS) { @@ -390,6 +390,10 @@ if (result != 0) { UpdateLastError(); } + if (opt == OPT_RECV_ECN) { + read_ecn_ = value == 1; + } + return result; } @@ -496,7 +500,7 @@ buffer.payload.SetData(BUF_SIZE, [&](std::span<uint8_t> payload) { received = DoReadFromSocket(payload.data(), payload.size(), &buffer.source_address, - ×tamp, ecn_ ? &buffer.ecn : nullptr); + ×tamp, read_ecn_ ? &buffer.ecn : nullptr); // return 0 if received is -1, indicating error. return std::max(received, 0); });
diff --git a/rtc_base/physical_socket_server.h b/rtc_base/physical_socket_server.h index 0fb410b..80743f5 100644 --- a/rtc_base/physical_socket_server.h +++ b/rtc_base/physical_socket_server.h
@@ -249,7 +249,8 @@ ConnState state_; std::unique_ptr<AsyncDnsResolverInterface> resolver_; uint8_t dscp_ = 0; // 6bit. - uint8_t ecn_ = 0; // 2bits. + uint8_t ecn_send_options_ = 0; // 2bits. + bool read_ecn_ = false; #if RTC_DCHECK_IS_ON std::string dbg_addr_;
diff --git a/rtc_base/socket_unittest.cc b/rtc_base/socket_unittest.cc index ff3c054..5d9f8c8 100644 --- a/rtc_base/socket_unittest.cc +++ b/rtc_base/socket_unittest.cc
@@ -1288,45 +1288,52 @@ void SocketTest::SocketSendRecvWithEcn(const IPAddress& loopback) { StreamSink sink; - std::unique_ptr<Socket> socket = + std::unique_ptr<Socket> receiving_socket = socket_factory_->Create(loopback.family(), SOCK_DGRAM); - EXPECT_EQ(0, socket->Bind(SocketAddress(loopback, 0))); - SocketAddress address = socket->GetLocalAddress(); - sink.Monitor(socket.get()); + std::unique_ptr<Socket> sending_socket = + socket_factory_->Create(loopback.family(), SOCK_DGRAM); + EXPECT_EQ(0, receiving_socket->Bind(SocketAddress(loopback, 0))); + EXPECT_EQ(0, sending_socket->Bind(SocketAddress(loopback, 0))); + SocketAddress address = receiving_socket->GetLocalAddress(); + sink.Monitor(receiving_socket.get()); Buffer buffer; Socket::ReceiveBuffer receive_buffer(buffer); - socket->SendTo("foo", 3, address); - EXPECT_THAT(WaitUntil([&] { return sink.Check(socket.get(), SSE_READ); }, - ::testing::IsTrue()), - IsRtcOk()); - ASSERT_GT(socket->RecvFrom(receive_buffer), 0); + sending_socket->SendTo("foo", 3, address); + EXPECT_THAT( + WaitUntil([&] { return sink.Check(receiving_socket.get(), SSE_READ); }, + ::testing::IsTrue()), + IsRtcOk()); + ASSERT_GT(receiving_socket->RecvFrom(receive_buffer), 0); EXPECT_EQ(receive_buffer.ecn, EcnMarking::kNotEct); - socket->SetOption(Socket::OPT_SEND_ECN, 1); // Ect(1) - socket->SetOption(Socket::OPT_RECV_ECN, 1); + sending_socket->SetOption(Socket::OPT_SEND_ECN, 1); // Ect(1) + receiving_socket->SetOption(Socket::OPT_RECV_ECN, 1); - socket->SendTo("bar", 3, address); - EXPECT_THAT(WaitUntil([&] { return sink.Check(socket.get(), SSE_READ); }, - ::testing::IsTrue()), - IsRtcOk()); - ASSERT_GT(socket->RecvFrom(receive_buffer), 0); + sending_socket->SendTo("bar", 3, address); + EXPECT_THAT( + WaitUntil([&] { return sink.Check(receiving_socket.get(), SSE_READ); }, + ::testing::IsTrue()), + IsRtcOk()); + ASSERT_GT(receiving_socket->RecvFrom(receive_buffer), 0); EXPECT_EQ(receive_buffer.ecn, EcnMarking::kEct1); - socket->SetOption(Socket::OPT_SEND_ECN, 2); // Ect(0) - socket->SendTo("bar", 3, address); - EXPECT_THAT(WaitUntil([&] { return sink.Check(socket.get(), SSE_READ); }, - ::testing::IsTrue()), - IsRtcOk()); - ASSERT_GT(socket->RecvFrom(receive_buffer), 0); + sending_socket->SetOption(Socket::OPT_SEND_ECN, 2); // Ect(0) + sending_socket->SendTo("bar", 3, address); + EXPECT_THAT( + WaitUntil([&] { return sink.Check(receiving_socket.get(), SSE_READ); }, + ::testing::IsTrue()), + IsRtcOk()); + ASSERT_GT(receiving_socket->RecvFrom(receive_buffer), 0); EXPECT_EQ(receive_buffer.ecn, EcnMarking::kEct0); - socket->SetOption(Socket::OPT_SEND_ECN, 3); // Ce - socket->SendTo("bar", 3, address); - EXPECT_THAT(WaitUntil([&] { return sink.Check(socket.get(), SSE_READ); }, - ::testing::IsTrue()), - IsRtcOk()); - ASSERT_GT(socket->RecvFrom(receive_buffer), 0); + sending_socket->SetOption(Socket::OPT_SEND_ECN, 3); // Ce + sending_socket->SendTo("bar", 3, address); + EXPECT_THAT( + WaitUntil([&] { return sink.Check(receiving_socket.get(), SSE_READ); }, + ::testing::IsTrue()), + IsRtcOk()); + ASSERT_GT(receiving_socket->RecvFrom(receive_buffer), 0); EXPECT_EQ(receive_buffer.ecn, EcnMarking::kCe); }