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,