Move HTTP/3 Datagram Flow ID Allocation Service to QuicSpdySession

This CL is part of a chain of refactors of the CONNECT-UDP code aimed at allowing code reuse between MASQUE and WebTransport.

The modified code is not used in production.

PiperOrigin-RevId: 359618731
Change-Id: Ia97597e31a28ff602ee3910fb9b5667b9ac82924
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc
index 91530d3..346add8 100644
--- a/quic/core/http/quic_spdy_session.cc
+++ b/quic/core/http/quic_spdy_session.cc
@@ -509,7 +509,10 @@
           GetQuicFlag(FLAGS_quic_enable_http3_server_push)),
       http3_max_push_id_sent_(false),
       goaway_with_max_stream_id_(
-          GetQuicReloadableFlag(quic_goaway_with_max_stream_id)) {
+          GetQuicReloadableFlag(quic_goaway_with_max_stream_id)),
+      next_available_datagram_flow_id_(perspective() == Perspective::IS_SERVER
+                                           ? kFirstDatagramFlowIdServer
+                                           : kFirstDatagramFlowIdClient) {
   if (goaway_with_max_stream_id_) {
     QUIC_RELOADABLE_FLAG_COUNT_N(quic_goaway_with_max_stream_id, 1, 2);
   }
@@ -1703,6 +1706,12 @@
   }
 }
 
+QuicDatagramFlowId QuicSpdySession::GetNextDatagramFlowId() {
+  QuicDatagramFlowId result = next_available_datagram_flow_id_;
+  next_available_datagram_flow_id_ += kDatagramFlowIdIncrement;
+  return result;
+}
+
 #undef ENDPOINT  // undef for jumbo builds
 
 }  // namespace quic
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h
index 3c3d558..ad5fa02 100644
--- a/quic/core/http/quic_spdy_session.h
+++ b/quic/core/http/quic_spdy_session.h
@@ -417,6 +417,9 @@
   // extension.
   virtual void OnAcceptChFrameReceivedViaAlps(const AcceptChFrame& /*frame*/);
 
+  // Generates a new HTTP/3 datagram flow ID.
+  QuicDatagramFlowId GetNextDatagramFlowId();
+
  protected:
   // Override CreateIncomingStream(), CreateOutgoingBidirectionalStream() and
   // CreateOutgoingUnidirectionalStream() with QuicSpdyStream return type to
@@ -622,6 +625,10 @@
 
   // Latched value of reloadable flag quic_goaway_with_max_stream_id.
   const bool goaway_with_max_stream_id_;
+
+  // Value of the smallest unused HTTP/3 datagram flow ID that this endpoint's
+  // datagram flow ID allocation service will use next.
+  QuicDatagramFlowId next_available_datagram_flow_id_;
 };
 
 }  // namespace quic
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index c2ab731..d173917 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -442,6 +442,8 @@
     closed_streams_.insert(id);
   }
 
+  ParsedQuicVersion version() const { return connection_->version(); }
+
   QuicTransportVersion transport_version() const {
     return connection_->transport_version();
   }
@@ -3375,6 +3377,26 @@
   EXPECT_EQ("incomplete HTTP/3 frame", error.value());
 }
 
+TEST_P(QuicSpdySessionTestClient, GetNextDatagramFlowId) {
+  if (!version().UsesHttp3()) {
+    return;
+  }
+  EXPECT_EQ(session_.GetNextDatagramFlowId(), 0u);
+  EXPECT_EQ(session_.GetNextDatagramFlowId(), 2u);
+  EXPECT_EQ(session_.GetNextDatagramFlowId(), 4u);
+  EXPECT_EQ(session_.GetNextDatagramFlowId(), 6u);
+}
+
+TEST_P(QuicSpdySessionTestServer, GetNextDatagramFlowId) {
+  if (!version().UsesHttp3()) {
+    return;
+  }
+  EXPECT_EQ(session_.GetNextDatagramFlowId(), 1u);
+  EXPECT_EQ(session_.GetNextDatagramFlowId(), 3u);
+  EXPECT_EQ(session_.GetNextDatagramFlowId(), 5u);
+  EXPECT_EQ(session_.GetNextDatagramFlowId(), 7u);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_constants.h b/quic/core/quic_constants.h
index 2de827f..fcfec62 100644
--- a/quic/core/quic_constants.h
+++ b/quic/core/quic_constants.h
@@ -291,6 +291,13 @@
 QUIC_EXPORT_PRIVATE extern const char* const kEPIDGoogleFrontEnd;
 QUIC_EXPORT_PRIVATE extern const char* const kEPIDGoogleFrontEnd0;
 
+// HTTP/3 Datagrams.
+enum : QuicDatagramFlowId {
+  kFirstDatagramFlowIdClient = 0,
+  kFirstDatagramFlowIdServer = 1,
+  kDatagramFlowIdIncrement = 2,
+};
+
 }  // namespace quic
 
 #endif  // QUICHE_QUIC_CORE_QUIC_CONSTANTS_H_
diff --git a/quic/masque/masque_client_session.cc b/quic/masque/masque_client_session.cc
index 5663c4a..6c7859e 100644
--- a/quic/masque/masque_client_session.cc
+++ b/quic/masque/masque_client_session.cc
@@ -114,7 +114,7 @@
     return nullptr;
   }
 
-  QuicDatagramFlowId flow_id = compression_engine_.GetNextFlowId();
+  QuicDatagramFlowId flow_id = GetNextDatagramFlowId();
 
   // Send the request.
   spdy::Http2HeaderBlock headers;
diff --git a/quic/masque/masque_compression_engine.cc b/quic/masque/masque_compression_engine.cc
index af6758a..2867b3d 100644
--- a/quic/masque/masque_compression_engine.cc
+++ b/quic/masque/masque_compression_engine.cc
@@ -30,14 +30,9 @@
 
 }  // namespace
 
-MasqueCompressionEngine::MasqueCompressionEngine(QuicSession* masque_session)
-    : masque_session_(masque_session) {
-  if (masque_session_->perspective() == Perspective::IS_SERVER) {
-    next_flow_id_ = 1;
-  } else {
-    next_flow_id_ = 2;
-  }
-}
+MasqueCompressionEngine::MasqueCompressionEngine(
+    QuicSpdySession* masque_session)
+    : masque_session_(masque_session) {}
 
 QuicDatagramFlowId MasqueCompressionEngine::FindOrCreateCompressionContext(
     QuicConnectionId client_connection_id,
@@ -79,7 +74,11 @@
   }
 
   // Create new compression context.
-  flow_id = GetNextFlowId();
+  flow_id = masque_session_->GetNextDatagramFlowId();
+  if (flow_id == kFlowId0) {
+    // Do not use value zero which is reserved in this mode.
+    flow_id = masque_session_->GetNextDatagramFlowId();
+  }
   QUIC_DVLOG(1) << "Compression assigning new flow_id " << flow_id << " to "
                 << server_address << " client " << client_connection_id
                 << " server " << server_connection_id;
@@ -520,12 +519,6 @@
   return true;
 }
 
-QuicDatagramFlowId MasqueCompressionEngine::GetNextFlowId() {
-  const QuicDatagramFlowId next_flow_id = next_flow_id_;
-  next_flow_id_ += 2;
-  return next_flow_id;
-}
-
 void MasqueCompressionEngine::UnregisterClientConnectionId(
     QuicConnectionId client_connection_id) {
   std::vector<QuicDatagramFlowId> flow_ids_to_remove;
diff --git a/quic/masque/masque_compression_engine.h b/quic/masque/masque_compression_engine.h
index 16b4549..9bea618 100644
--- a/quic/masque/masque_compression_engine.h
+++ b/quic/masque/masque_compression_engine.h
@@ -7,8 +7,8 @@
 
 #include "absl/container/flat_hash_map.h"
 #include "absl/strings/string_view.h"
+#include "quic/core/http/quic_spdy_session.h"
 #include "quic/core/quic_connection_id.h"
-#include "quic/core/quic_session.h"
 #include "quic/core/quic_types.h"
 #include "quic/platform/api/quic_containers.h"
 #include "quic/platform/api/quic_export.h"
@@ -35,7 +35,7 @@
  public:
   // Caller must ensure that |masque_session| has a lifetime longer than the
   // newly constructed MasqueCompressionEngine.
-  explicit MasqueCompressionEngine(QuicSession* masque_session);
+  explicit MasqueCompressionEngine(QuicSpdySession* masque_session);
 
   // Disallow copy and assign.
   MasqueCompressionEngine(const MasqueCompressionEngine&) = delete;
@@ -70,9 +70,6 @@
   // compression table.
   void UnregisterClientConnectionId(QuicConnectionId client_connection_id);
 
-  // Generates a new datagram flow ID.
-  QuicDatagramFlowId GetNextFlowId();
-
  private:
   struct QUIC_NO_EXPORT MasqueCompressionContext {
     QuicConnectionId client_connection_id;
@@ -117,9 +114,8 @@
                                std::vector<char>* packet,
                                bool* version_present);
 
-  QuicSession* masque_session_;  // Unowned.
+  QuicSpdySession* masque_session_;  // Unowned.
   absl::flat_hash_map<QuicDatagramFlowId, MasqueCompressionContext> contexts_;
-  QuicDatagramFlowId next_flow_id_;
 };
 
 }  // namespace quic