Enable QUIC spin bit configuration via QuicConfig: Only enable spin bit if both config requests it and ShouldEnableSpinBit() allows it (GFE flag is true and coin flip success).

Protected by FLAGS_quic_reloadable_flag_quic_enable_spin_bit.

PiperOrigin-RevId: 952064277
diff --git a/quiche/quic/core/quic_config.cc b/quiche/quic/core/quic_config.cc
index 4b9c404..abb5913 100644
--- a/quiche/quic/core/quic_config.cc
+++ b/quiche/quic/core/quic_config.cc
@@ -1059,6 +1059,7 @@
   SetReliableStreamReset(false);
   scone_packet_interval_ = QuicTimeDelta::Zero();
   parse_scone_packets_ = false;
+  enable_spin_bit_ = false;
 }
 
 void QuicConfig::ToHandshakeMessage(
@@ -1537,4 +1538,8 @@
   return reliable_stream_reset_;
 }
 
+void QuicConfig::set_enable_spin_bit(bool enable) { enable_spin_bit_ = enable; }
+
+bool QuicConfig::enable_spin_bit() const { return enable_spin_bit_; }
+
 }  // namespace quic
diff --git a/quiche/quic/core/quic_config.h b/quiche/quic/core/quic_config.h
index 79487d2..691a166 100644
--- a/quiche/quic/core/quic_config.h
+++ b/quiche/quic/core/quic_config.h
@@ -475,6 +475,10 @@
   void SetReliableStreamReset(bool reliable_stream_reset);
   bool SupportsReliableStreamReset() const;
 
+  // Whether the spin bit is enabled.
+  void set_enable_spin_bit(bool enable);
+  bool enable_spin_bit() const;
+
   // Original destination connection ID.
   void SetOriginalConnectionIdToSend(
       const QuicConnectionId& original_destination_connection_id);
@@ -777,6 +781,9 @@
 
   // Support for RESET_STREAM_AT frame.
   bool reliable_stream_reset_;
+
+  // Whether the spin bit is enabled.
+  bool enable_spin_bit_;
 };
 
 }  // namespace quic
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index c7df04f..eedbef6 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -447,6 +447,10 @@
                        config.max_idle_time_before_crypto_handshake());
   }
 
+  if (config.enable_spin_bit()) {
+    spin_bit_enabled_ = ShouldEnableSpinBit();
+  }
+
   if (version().IsIetfQuic() &&
       config.HasReceivedPreferredAddressConnectionIdAndToken()) {
     QuicNewConnectionIdFrame frame;
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index e8db6f5..80f4104 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -2596,7 +2596,7 @@
   bool quic_close_on_idle_timeout_ : 1 =
       GetQuicReloadableFlag(quic_close_on_idle_timeout);
   // True if spin bit is enabled for this connection.
-  bool spin_bit_enabled_ : 1 = ShouldEnableSpinBit();
+  bool spin_bit_enabled_ : 1 = false;
   bool fix_mtu_discovery_ : 1 = GetQuicReloadableFlag(quic_fix_mtu_discovery);
 };
 
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index f0b0b3c..2639ded 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -18890,6 +18890,7 @@
 
   SetQuicReloadableFlag(quic_enable_spin_bit, false);
 
+  EXPECT_CALL(random_generator_, RandBytes(_, _)).Times(0);
   EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
   EXPECT_CALL(*send_algorithm_, EnableECT1()).WillRepeatedly(Return(false));
   EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
@@ -18905,8 +18906,35 @@
 
 TEST_P(QuicConnectionTest, EnabledSpinBit) {
   SetQuicReloadableFlag(quic_enable_spin_bit, true);
-  ON_CALL(random_generator_, RandBytes(_, 1))
-      .WillByDefault([](void* data, size_t len) {
+
+  EXPECT_CALL(random_generator_, RandBytes(_, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillRepeatedly(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
+
+  QuicConfig config;
+  connection_.SetFromConfig(config);
+  EXPECT_FALSE(QuicConnectionPeer::GetSpinBitEnabled(&connection_));
+}
+
+TEST_P(QuicConnectionTest, ConfigCannotEnableSpinBitIfFlagIsFalse) {
+  SetQuicReloadableFlag(quic_enable_spin_bit, false);
+
+  EXPECT_CALL(random_generator_, RandBytes(_, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillRepeatedly(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
+
+  QuicConfig config;
+  config.set_enable_spin_bit(true);
+  connection_.SetFromConfig(config);
+  EXPECT_FALSE(QuicConnectionPeer::GetSpinBitEnabled(&connection_));
+}
+
+TEST_P(QuicConnectionTest, ConfigEnablesSpinBitIfFlagIsTrueAndCoinFlipSuccess) {
+  SetQuicReloadableFlag(quic_enable_spin_bit, true);
+  EXPECT_CALL(random_generator_, RandBytes(_, 1))
+      .WillOnce([](void* data, size_t len) {
         ASSERT_EQ(1u, len);
         *static_cast<uint8_t*>(data) = 0x00;
       });
@@ -18916,6 +18944,34 @@
   EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
 
   QuicConfig config;
+  config.set_enable_spin_bit(true);
+  connection_.SetFromConfig(config);
+  EXPECT_TRUE(QuicConnectionPeer::GetSpinBitEnabled(&connection_));
+}
+
+TEST_P(QuicConnectionTest, ConfigDisablesSpinBit) {
+  SetQuicReloadableFlag(quic_enable_spin_bit, true);
+
+  EXPECT_CALL(random_generator_, RandBytes(_, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillRepeatedly(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
+
+  QuicConfig config;
+  config.set_enable_spin_bit(false);
+  connection_.SetFromConfig(config);
+  EXPECT_FALSE(QuicConnectionPeer::GetSpinBitEnabled(&connection_));
+}
+
+TEST_P(QuicConnectionTest, ConfigWithoutSpinBitDisablesSpinBit) {
+  SetQuicReloadableFlag(quic_enable_spin_bit, true);
+
+  EXPECT_CALL(random_generator_, RandBytes(_, _)).Times(0);
+  EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+  EXPECT_CALL(*send_algorithm_, EnableECT1()).WillRepeatedly(Return(false));
+  EXPECT_CALL(*send_algorithm_, EnableECT0()).WillRepeatedly(Return(false));
+
+  QuicConfig config;
   connection_.SetFromConfig(config);
   EXPECT_FALSE(QuicConnectionPeer::GetSpinBitEnabled(&connection_));
 }