gfe-relnote: Update QuicConnection's SendMessage to allow specifying if the message being sent is retransmittable. PiperOrigin-RevId: 281363715 Change-Id: I81966b19cda8405adb6e6f5d7804c3f042fa4ba8
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index d077196..479cfaf 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -3864,7 +3864,8 @@ } MessageStatus QuicConnection::SendMessage(QuicMessageId message_id, - QuicMemSliceSpan message) { + QuicMemSliceSpan message, + bool flush) { if (!VersionSupportsMessageFrames(transport_version())) { QUIC_BUG << "MESSAGE frame is not supported for version " << transport_version(); @@ -3873,7 +3874,7 @@ if (message.total_length() > GetCurrentLargestMessagePayload()) { return MESSAGE_STATUS_TOO_LARGE; } - if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) { + if (!connected_ || (!flush && !CanWrite(HAS_RETRANSMITTABLE_DATA))) { return MESSAGE_STATUS_BLOCKED; } ScopedPacketFlusher flusher(this);
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index 90369fc..de26b3c 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -758,8 +758,11 @@ void SetTransmissionType(TransmissionType type); // Tries to send |message| and returns the message status. + // If |flush| is false, this will return a MESSAGE_STATUS_BLOCKED + // when the connection is deemed unwritable. virtual MessageStatus SendMessage(QuicMessageId message_id, - QuicMemSliceSpan message); + QuicMemSliceSpan message, + bool flush); // Returns the largest payload that will fit into a single MESSAGE frame. // Because overhead can vary during a connection, this method should be
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index 9c2a1c8..f5f1287 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -8737,33 +8737,36 @@ // get sent, one contains stream frame, and the other only contains the // message frame. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); - EXPECT_EQ( - MESSAGE_STATUS_SUCCESS, - connection_.SendMessage( - 1, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), - QuicStringPiece( - message_data.data(), - connection_.GetCurrentLargestMessagePayload()), - &storage))); + EXPECT_EQ(MESSAGE_STATUS_SUCCESS, + connection_.SendMessage( + 1, + MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), + QuicStringPiece( + message_data.data(), + connection_.GetCurrentLargestMessagePayload()), + &storage), + false)); } // Fail to send a message if connection is congestion control blocked. EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false)); - EXPECT_EQ( - MESSAGE_STATUS_BLOCKED, - connection_.SendMessage( - 2, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), - "message", &storage))); + EXPECT_EQ(MESSAGE_STATUS_BLOCKED, + connection_.SendMessage( + 2, + MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), + "message", &storage), + false)); // Always fail to send a message which cannot fit into one packet. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - EXPECT_EQ( - MESSAGE_STATUS_TOO_LARGE, - connection_.SendMessage( - 3, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), - QuicStringPiece( - message_data.data(), - connection_.GetCurrentLargestMessagePayload() + 1), - &storage))); + EXPECT_EQ(MESSAGE_STATUS_TOO_LARGE, + connection_.SendMessage( + 3, + MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), + QuicStringPiece( + message_data.data(), + connection_.GetCurrentLargestMessagePayload() + 1), + &storage), + false)); } // Test to check that the path challenge/path response logic works
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc index 3ec2401..1c85430 100644 --- a/quic/core/quic_session.cc +++ b/quic/core/quic_session.cc
@@ -1894,11 +1894,15 @@ } MessageResult QuicSession::SendMessage(QuicMemSliceSpan message) { + return SendMessage(message, /*flush=*/false); +} + +MessageResult QuicSession::SendMessage(QuicMemSliceSpan message, bool flush) { if (!IsEncryptionEstablished()) { return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0}; } MessageStatus result = - connection_->SendMessage(last_message_id_ + 1, message); + connection_->SendMessage(last_message_id_ + 1, message, flush); if (result == MESSAGE_STATUS_SUCCESS) { return {result, ++last_message_id_}; }
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h index 03090d8..2d0f252 100644 --- a/quic/core/quic_session.h +++ b/quic/core/quic_session.h
@@ -199,6 +199,10 @@ // callback. MessageResult SendMessage(QuicMemSliceSpan message); + // Same as above SendMessage, except caller can specify if the given |message| + // should be flushed even if the underlying connection is deemed unwritable. + MessageResult SendMessage(QuicMemSliceSpan message, bool flush); + // Called when message with |message_id| gets acked. virtual void OnMessageAcked(QuicMessageId message_id, QuicTime receive_timestamp);
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc index 4ee1230..16a9917 100644 --- a/quic/core/quic_session_test.cc +++ b/quic/core/quic_session_test.cc
@@ -2343,21 +2343,21 @@ EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed()); QuicStringPiece message; - EXPECT_CALL(*connection_, SendMessage(1, _)) + EXPECT_CALL(*connection_, SendMessage(1, _, false)) .WillOnce(Return(MESSAGE_STATUS_SUCCESS)); EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 1), session_.SendMessage( MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(), message, &storage))); // Verify message_id increases. - EXPECT_CALL(*connection_, SendMessage(2, _)) + EXPECT_CALL(*connection_, SendMessage(2, _, false)) .WillOnce(Return(MESSAGE_STATUS_TOO_LARGE)); EXPECT_EQ(MessageResult(MESSAGE_STATUS_TOO_LARGE, 0), session_.SendMessage( MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(), message, &storage))); // Verify unsent message does not consume a message_id. - EXPECT_CALL(*connection_, SendMessage(2, _)) + EXPECT_CALL(*connection_, SendMessage(2, _, false)) .WillOnce(Return(MESSAGE_STATUS_SUCCESS)); EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 2), session_.SendMessage(
diff --git a/quic/qbone/qbone_session_base.cc b/quic/qbone/qbone_session_base.cc index 9c8479c..c3e7731 100644 --- a/quic/qbone/qbone_session_base.cc +++ b/quic/qbone/qbone_session_base.cc
@@ -141,7 +141,7 @@ QuicMemSlice slice(connection()->helper()->GetStreamSendBufferAllocator(), packet.size()); memcpy(const_cast<char*>(slice.data()), packet.data(), packet.size()); - switch (SendMessage(QuicMemSliceSpan(&slice)).status) { + switch (SendMessage(QuicMemSliceSpan(&slice), /*flush=*/true).status) { case MESSAGE_STATUS_SUCCESS: break; case MESSAGE_STATUS_TOO_LARGE: {
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h index f428e87..544d1fb 100644 --- a/quic/test_tools/quic_test_utils.h +++ b/quic/test_tools/quic_test_utils.h
@@ -534,7 +534,8 @@ MOCK_METHOD2(OnStreamReset, void(QuicStreamId, QuicRstStreamErrorCode)); MOCK_METHOD1(SendControlFrame, bool(const QuicFrame& frame)); - MOCK_METHOD2(SendMessage, MessageStatus(QuicMessageId, QuicMemSliceSpan)); + MOCK_METHOD3(SendMessage, + MessageStatus(QuicMessageId, QuicMemSliceSpan, bool)); MOCK_METHOD3(OnConnectionClosed, void(QuicErrorCode error, const std::string& error_details,