Support the use of MESSAGE/DATAGRAM frames in QBONE. Received MESSAGE frames are always processed. By default, sending MESSAGE frames is disabled, but can be enabled via flags. gfe-relnote: n/a (QBONE-only change) PiperOrigin-RevId: 267679822 Change-Id: I1263435cc16c17bd6ff8efa82d78b11c761164b2
diff --git a/quic/qbone/qbone_session_base.cc b/quic/qbone/qbone_session_base.cc index 23b29d2..01917d2 100644 --- a/quic/qbone/qbone_session_base.cc +++ b/quic/qbone/qbone_session_base.cc
@@ -81,6 +81,11 @@ QuicSession::OnStreamFrame(frame); } +void QboneSessionBase::OnMessageReceived(QuicStringPiece message) { + ++num_message_packets_; + ProcessPacketFromPeer(message); +} + QuicStream* QboneSessionBase::CreateIncomingStream(QuicStreamId id) { return ActivateDataStream(CreateDataStream(id)); } @@ -122,6 +127,23 @@ } void QboneSessionBase::SendPacketToPeer(QuicStringPiece packet) { + if (crypto_stream_ == nullptr) { + QUIC_BUG << "Attempting to send packet before encryption established"; + return; + } + + if (send_packets_as_messages_) { + QuicMemSlice slice(connection()->helper()->GetStreamSendBufferAllocator(), + packet.size()); + memcpy(const_cast<char*>(slice.data()), packet.data(), packet.size()); + if (SendMessage(QuicMemSliceSpan(&slice)).status == + MESSAGE_STATUS_SUCCESS) { + return; + } + // If SendMessage() fails for any reason, fall back to ephemeral streams. + num_fallback_to_stream_++; + } + // Qbone streams are ephemeral. QuicStream* stream = CreateOutgoingStream(); if (!stream) { @@ -142,6 +164,14 @@ return num_streamed_packets_; } +uint64_t QboneSessionBase::GetNumMessagePackets() const { + return num_message_packets_; +} + +uint64_t QboneSessionBase::GetNumFallbackToStream() const { + return num_fallback_to_stream_; +} + void QboneSessionBase::set_writer(QbonePacketWriter* writer) { writer_ = writer; testing::testvalue::Adjust("quic_QbonePacketWriter", &writer_);
diff --git a/quic/qbone/qbone_session_base.h b/quic/qbone/qbone_session_base.h index 5bfc9be..41afc6b 100644 --- a/quic/qbone/qbone_session_base.h +++ b/quic/qbone/qbone_session_base.h
@@ -35,6 +35,8 @@ void CloseStream(QuicStreamId stream_id) override; // This will check if the packet is wholly contained. void OnStreamFrame(const QuicStreamFrame& frame) override; + // Called whenever a MESSAGE frame is received. + void OnMessageReceived(QuicStringPiece message) override; virtual void ProcessPacketFromNetwork(QuicStringPiece packet) = 0; virtual void ProcessPacketFromPeer(QuicStringPiece packet) = 0; @@ -48,7 +50,18 @@ // multiple packets, requiring the creation of a QboneReadOnlyStream. uint64_t GetNumStreamedPackets() const; + // Returns the number of QBONE network packets that were received using QUIC + // MESSAGE frame. + uint64_t GetNumMessagePackets() const; + + // Returns the number of times sending a MESSAGE frame failed, and the session + // used an ephemeral stream instead. + uint64_t GetNumFallbackToStream() const; + void set_writer(QbonePacketWriter* writer); + void set_send_packets_as_messages(bool send_packets_as_messages) { + send_packets_as_messages_ = send_packets_as_messages; + } protected: virtual std::unique_ptr<QuicCryptoStream> CreateCryptoStream() = 0; @@ -79,12 +92,24 @@ QbonePacketWriter* writer_; + // If true, MESSAGE frames are used for short datagrams. If false, ephemeral + // streams are used instead. Note that receiving MESSAGE frames is always + // supported. + bool send_packets_as_messages_ = false; + private: // Used for the crypto handshake. std::unique_ptr<QuicCryptoStream> crypto_stream_; + // Statistics for the packets received by the session. uint64_t num_ephemeral_packets_ = 0; + uint64_t num_message_packets_ = 0; uint64_t num_streamed_packets_ = 0; + + // Number of times the connection has failed to send packets as MESSAGE frame + // and used streams as a fallback. + uint64_t num_fallback_to_stream_ = 0; + QuicUnorderedSet<QuicStreamId> reliable_streams_; };
diff --git a/quic/qbone/qbone_session_test.cc b/quic/qbone/qbone_session_test.cc index 016b2f3..b58f39e 100644 --- a/quic/qbone/qbone_session_test.cc +++ b/quic/qbone/qbone_session_test.cc
@@ -354,7 +354,7 @@ // Test handshake establishment and sending/receiving of data for two // directions. - void TestStreamConnection() { + void TestStreamConnection(bool use_messages) { ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed()); ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed()); ASSERT_TRUE(server_peer_->IsEncryptionEstablished()); @@ -406,10 +406,19 @@ EXPECT_THAT(server_writer_->data(), Contains(TestPacketOut(long_data))); EXPECT_THAT(client_peer_->GetNumSentClientHellos(), Eq(2)); EXPECT_THAT(client_peer_->GetNumReceivedServerConfigUpdates(), Eq(0)); - EXPECT_THAT(client_peer_->GetNumEphemeralPackets(), Eq(2)); EXPECT_THAT(client_peer_->GetNumStreamedPackets(), Eq(1)); - EXPECT_THAT(server_peer_->GetNumEphemeralPackets(), Eq(2)); EXPECT_THAT(server_peer_->GetNumStreamedPackets(), Eq(1)); + if (use_messages) { + EXPECT_THAT(client_peer_->GetNumEphemeralPackets(), Eq(0)); + EXPECT_THAT(server_peer_->GetNumEphemeralPackets(), Eq(0)); + EXPECT_THAT(client_peer_->GetNumMessagePackets(), Eq(2)); + EXPECT_THAT(server_peer_->GetNumMessagePackets(), Eq(2)); + } else { + EXPECT_THAT(client_peer_->GetNumEphemeralPackets(), Eq(2)); + EXPECT_THAT(server_peer_->GetNumEphemeralPackets(), Eq(2)); + EXPECT_THAT(client_peer_->GetNumMessagePackets(), Eq(0)); + EXPECT_THAT(server_peer_->GetNumMessagePackets(), Eq(0)); + } // All streams are ephemeral and should be gone. EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); @@ -449,8 +458,18 @@ TEST_F(QboneSessionTest, StreamConnection) { CreateClientAndServerSessions(); + client_peer_->set_send_packets_as_messages(false); + server_peer_->set_send_packets_as_messages(false); StartHandshake(); - TestStreamConnection(); + TestStreamConnection(false); +} + +TEST_F(QboneSessionTest, Messages) { + CreateClientAndServerSessions(); + client_peer_->set_send_packets_as_messages(true); + server_peer_->set_send_packets_as_messages(true); + StartHandshake(); + TestStreamConnection(true); } TEST_F(QboneSessionTest, ClientRejection) { @@ -481,9 +500,9 @@ TEST_F(QboneSessionTest, CannotCreateDataStreamBeforeHandshake) { CreateClientAndServerSessions(); EXPECT_QUIC_BUG(client_peer_->ProcessPacketFromNetwork(TestPacketIn("hello")), - "Failed to create an outgoing QBONE stream"); + "Attempting to send packet before encryption established"); EXPECT_QUIC_BUG(server_peer_->ProcessPacketFromNetwork(TestPacketIn("hello")), - "Failed to create an outgoing QBONE stream"); + "Attempting to send packet before encryption established"); EXPECT_EQ(0u, server_peer_->GetNumActiveStreams()); EXPECT_EQ(0u, client_peer_->GetNumActiveStreams()); }