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,
-                         &timestamp, ecn_ ? &buffer.ecn : nullptr);
+                         &timestamp, 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);
 }