Automated g4 rollback of changelist 432178898.
*** Reason for rollback ***
TAP has detected 10 or more targets failed to build at cl/432178898.
TO ROLLFORWARD (without additional approval): Use go/undo-autorollback and consider filing a go/autorollback-bug.
To see all broken targets visit http://test/432178898 or go/newly-broken?p=cl:432178898 if the former is slow to load.
To prevent noise from flakes, TAP double-checked the following target fails to build:
http://sponge2/label%3Atap%20label%3Apostsubmit%20cl%3A432178898%20target%3A%2F%2Fthird_party%2Farcore%2Fjava%2Fcom%2Fgoogle%2Far%2Fcore%3AARCore_arm_32_security_test_audit_android_security
but used to build fine:
http://sponge2/label%3Atap%20label%3Apostsubmit%20cl%3A432178897%20target%3A%2F%2Fthird_party%2Farcore%2Fjava%2Fcom%2Fgoogle%2Far%2Fcore%3AARCore_arm_32_security_test_audit_android_security
Questions? Comments? See the URL: go/autorollback
*** Original change description ***
Simplify QuicStreamSendBuffer::SaveStreamData().
This method is called at two places in production:
QuicCryptoStream::WriteCryptoData() and QuicStream::WriteOrBufferDataAtLevel(),
both times with an iovec created locally from an absl::string_view. In order to
reduce complexity, this CL changes SaveStreamData() to take an absl::string_view
directly instead of an iovec.
***
PiperOrigin-RevId: 432192634
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index a629827..311cf1f 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -341,12 +341,14 @@
}
QuicConsumedData SendStreamData(QuicStream* stream) {
+ struct iovec iov;
if (!QuicUtils::IsCryptoStreamId(connection()->transport_version(),
stream->id()) &&
connection()->encryption_level() != ENCRYPTION_FORWARD_SECURE) {
this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
}
- QuicStreamPeer::SendBuffer(stream).SaveStreamData("not empty");
+ MakeIOVector("not empty", &iov);
+ QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9);
QuicConsumedData consumed =
WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION,
GetEncryptionLevelToSendApplicationData());
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 84f0bce..fc4df23 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -230,15 +230,16 @@
}
QuicConsumedData SaveAndSendStreamData(QuicStreamId id,
- absl::string_view data,
+ const struct iovec* iov, int iov_count,
+ size_t total_length,
QuicStreamOffset offset,
StreamSendingState state) {
ScopedPacketFlusher flusher(this);
- producer_.SaveStreamData(id, data);
+ producer_.SaveStreamData(id, iov, iov_count, 0u, total_length);
if (notifier_ != nullptr) {
- return notifier_->WriteOrBufferData(id, data.length(), state);
+ return notifier_->WriteOrBufferData(id, total_length, state);
}
- return QuicConnection::SendStreamData(id, data.length(), offset, state);
+ return QuicConnection::SendStreamData(id, total_length, offset, state);
}
QuicConsumedData SendStreamDataWithString(QuicStreamId id,
@@ -256,7 +257,9 @@
QuicConnectionPeer::SetAddressValidated(this);
}
}
- return SaveAndSendStreamData(id, data, offset, state);
+ struct iovec iov;
+ MakeIOVector(data, &iov);
+ return SaveAndSendStreamData(id, &iov, 1, data.length(), offset, state);
}
QuicConsumedData SendApplicationDataAtLevel(EncryptionLevel encryption_level,
@@ -268,7 +271,9 @@
QUICHE_DCHECK(encryption_level >= ENCRYPTION_ZERO_RTT);
SetEncrypter(encryption_level, std::make_unique<TaggingEncrypter>(0x01));
SetDefaultEncryptionLevel(encryption_level);
- return SaveAndSendStreamData(id, data, offset, state);
+ struct iovec iov;
+ MakeIOVector(data, &iov);
+ return SaveAndSendStreamData(id, &iov, 1, data.length(), offset, state);
}
QuicConsumedData SendStreamData3() {
@@ -3702,11 +3707,19 @@
TEST_P(QuicConnectionTest, FramePackingSendv) {
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Send data in 1 packet by writing multiple blocks in a single iovector
+ // using writev.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
+ char data[] = "ABCDEF";
+ struct iovec iov[2];
+ iov[0].iov_base = data;
+ iov[0].iov_len = 4;
+ iov[1].iov_base = data + 4;
+ iov[1].iov_len = 2;
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
connection_.transport_version(), Perspective::IS_CLIENT);
- connection_.SaveAndSendStreamData(stream_id, "ABCDEF", 0, NO_FIN);
+ connection_.SaveAndSendStreamData(stream_id, iov, 2, 6, 0, NO_FIN);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
@@ -3724,12 +3737,19 @@
TEST_P(QuicConnectionTest, FramePackingSendvQueued) {
connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
+ // Try to send two stream frames in 1 packet by using writev.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
BlockOnNextWrite();
+ char data[] = "ABCDEF";
+ struct iovec iov[2];
+ iov[0].iov_base = data;
+ iov[0].iov_len = 4;
+ iov[1].iov_base = data + 4;
+ iov[1].iov_len = 2;
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
connection_.transport_version(), Perspective::IS_CLIENT);
- connection_.SaveAndSendStreamData(stream_id, "ABCDEF", 0, NO_FIN);
+ connection_.SaveAndSendStreamData(stream_id, iov, 2, 6, 0, NO_FIN);
EXPECT_EQ(1u, connection_.NumQueuedPackets());
EXPECT_TRUE(connection_.HasQueuedData());
@@ -3743,10 +3763,7 @@
EXPECT_EQ(1u, writer_->frame_count());
EXPECT_EQ(1u, writer_->stream_frames().size());
EXPECT_EQ(0u, writer_->padding_frames().size());
- QuicStreamFrame* frame = writer_->stream_frames()[0].get();
- EXPECT_EQ(stream_id, frame->stream_id);
- EXPECT_EQ("ABCDEF",
- absl::string_view(frame->data_buffer, frame->data_length));
+ EXPECT_EQ(stream_id, writer_->stream_frames()[0]->stream_id);
}
TEST_P(QuicConnectionTest, SendingZeroBytes) {
@@ -3755,7 +3772,7 @@
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
connection_.transport_version(), Perspective::IS_CLIENT);
- connection_.SaveAndSendStreamData(stream_id, {}, 0, FIN);
+ connection_.SaveAndSendStreamData(stream_id, nullptr, 0, 0, 0, FIN);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
@@ -3788,11 +3805,16 @@
// Send data and ensure the ack is bundled.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(9);
- const std::string data(10000, '?');
+ size_t len = 10000;
+ std::unique_ptr<char[]> data_array(new char[len]);
+ memset(data_array.get(), '?', len);
+ struct iovec iov;
+ iov.iov_base = data_array.get();
+ iov.iov_len = len;
QuicConsumedData consumed = connection_.SaveAndSendStreamData(
- GetNthClientInitiatedStreamId(0, connection_.transport_version()), data,
- 0, FIN);
- EXPECT_EQ(data.length(), consumed.bytes_consumed);
+ GetNthClientInitiatedStreamId(0, connection_.transport_version()), &iov,
+ 1, len, 0, FIN);
+ EXPECT_EQ(len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_EQ(0u, connection_.NumQueuedPackets());
EXPECT_FALSE(connection_.HasQueuedData());
@@ -7387,7 +7409,9 @@
EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF))
.WillOnce(Invoke(this, &QuicConnectionTest::SaveConnectionCloseFrame));
- EXPECT_QUIC_BUG(connection_.SaveAndSendStreamData(3, {}, 0, FIN),
+ struct iovec iov;
+ MakeIOVector("", &iov);
+ EXPECT_QUIC_BUG(connection_.SaveAndSendStreamData(3, &iov, 1, 0, 0, FIN),
"Cannot send stream data with level: ENCRYPTION_INITIAL");
EXPECT_FALSE(connection_.connected());
EXPECT_EQ(1, connection_close_frame_count_);
@@ -12268,8 +12292,11 @@
.WillOnce(Invoke([=](const QuicStreamFrame& frame) {
// Send some data on the stream. The STREAM_FRAME should be built into
// one packet together with the latter PATH_RESPONSE and PATH_CHALLENGE.
- const std::string data{"response body"};
- connection_.producer()->SaveStreamData(frame.stream_id, data);
+ std::string data{"response body"};
+ struct iovec iov;
+ MakeIOVector(data, &iov);
+ connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u,
+ data.length());
return notifier_.WriteOrBufferData(frame.stream_id, data.length(),
NO_FIN);
}));
@@ -12338,8 +12365,11 @@
.WillOnce(Invoke([=](const QuicStreamFrame& frame) {
// Send some data on the stream. The STREAM_FRAME should be built into a
// new packet but throttled by anti-amplifciation limit.
- const std::string data{"response body"};
- connection_.producer()->SaveStreamData(frame.stream_id, data);
+ std::string data{"response body"};
+ struct iovec iov;
+ MakeIOVector(data, &iov);
+ connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u,
+ data.length());
return notifier_.WriteOrBufferData(frame.stream_id, data.length(),
NO_FIN);
}));
@@ -12379,8 +12409,11 @@
.WillRepeatedly(Invoke([=](const QuicStreamFrame& frame) {
// Send some data on the stream. The STREAM_FRAME should be built into
// one packet together with the latter PATH_RESPONSE.
- const std::string data{"response body"};
- connection_.producer()->SaveStreamData(frame.stream_id, data);
+ std::string data{"response body"};
+ struct iovec iov;
+ MakeIOVector(data, &iov);
+ connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u,
+ data.length());
return notifier_.WriteOrBufferData(frame.stream_id, data.length(),
NO_FIN);
}));
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc
index 5690743..b579ff5 100644
--- a/quic/core/quic_crypto_stream.cc
+++ b/quic/core/quic_crypto_stream.cc
@@ -140,9 +140,11 @@
}
const bool had_buffered_data = HasBufferedCryptoFrames();
// Append |data| to the send buffer for this encryption level.
+ struct iovec iov(QuicUtils::MakeIovec(data));
QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer;
QuicStreamOffset offset = send_buffer->stream_offset();
- send_buffer->SaveStreamData(data);
+ send_buffer->SaveStreamData(&iov, /*iov_count=*/1, /*iov_offset=*/0,
+ data.length());
if (kMaxStreamLength - offset < data.length()) {
QUIC_BUG(quic_bug_10322_2) << "Writing too much crypto handshake data";
// TODO(nharper): Switch this to an IETF QUIC error code, possibly
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc
index f038e33..3b56f82 100644
--- a/quic/core/quic_packet_creator_test.cc
+++ b/quic/core/quic_packet_creator_test.cc
@@ -104,18 +104,24 @@
producer_(producer),
version_(framer->version()) {}
- bool ConsumeDataToFillCurrentPacket(QuicStreamId id, absl::string_view data,
- QuicStreamOffset offset, bool fin,
+ bool ConsumeDataToFillCurrentPacket(QuicStreamId id,
+ const struct iovec* iov,
+ int iov_count,
+ size_t total_length,
+ size_t iov_offset,
+ QuicStreamOffset offset,
+ bool fin,
bool needs_full_padding,
TransmissionType transmission_type,
QuicFrame* frame) {
// Save data before data is consumed.
- if (!data.empty()) {
- producer_->SaveStreamData(id, data);
+ QuicByteCount data_length = total_length - iov_offset;
+ if (data_length > 0) {
+ producer_->SaveStreamData(id, iov, iov_count, iov_offset, data_length);
}
return QuicPacketCreator::ConsumeDataToFillCurrentPacket(
- id, data.length(), offset, fin, needs_full_padding, transmission_type,
- frame);
+ id, data_length - iov_offset, offset, fin, needs_full_padding,
+ transmission_type, frame);
}
void StopSendingVersion() {
@@ -277,6 +283,7 @@
StrictMock<MockFramerVisitor> framer_visitor_;
StrictMock<MockPacketCreatorDelegate> delegate_;
std::string data_;
+ struct iovec iov_;
TestPacketCreator creator_;
std::unique_ptr<SerializedPacket> serialized_packet_;
SimpleDataProducer producer_;
@@ -377,11 +384,12 @@
TEST_P(QuicPacketCreatorTest, ConsumeDataToFillCurrentPacket) {
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
QuicFrame frame;
+ MakeIOVector("test", &iov_);
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
client_framer_.transport_version(), Perspective::IS_CLIENT);
- const std::string data("test");
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id, data, 0u, false, false, NOT_RETRANSMISSION, &frame));
+ stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false,
+ NOT_RETRANSMISSION, &frame));
size_t consumed = frame.stream_frame.data_length;
EXPECT_EQ(4u, consumed);
CheckStreamFrame(frame, stream_id, "test", 0u, false);
@@ -391,11 +399,12 @@
TEST_P(QuicPacketCreatorTest, ConsumeDataFin) {
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
QuicFrame frame;
+ MakeIOVector("test", &iov_);
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
client_framer_.transport_version(), Perspective::IS_CLIENT);
- const std::string data("test");
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id, data, 0u, true, false, NOT_RETRANSMISSION, &frame));
+ stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, true, false,
+ NOT_RETRANSMISSION, &frame));
size_t consumed = frame.stream_frame.data_length;
EXPECT_EQ(4u, consumed);
CheckStreamFrame(frame, stream_id, "test", 0u, true);
@@ -408,7 +417,8 @@
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
client_framer_.transport_version(), Perspective::IS_CLIENT);
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id, {}, 0u, true, false, NOT_RETRANSMISSION, &frame));
+ stream_id, nullptr, 0u, 0u, 0u, 0u, true, false, NOT_RETRANSMISSION,
+ &frame));
size_t consumed = frame.stream_frame.data_length;
EXPECT_EQ(0u, consumed);
CheckStreamFrame(frame, stream_id, std::string(), 0u, true);
@@ -435,13 +445,13 @@
kOffset, /* data_size=*/0xffff));
if (should_have_room) {
QuicFrame frame;
- const std::string data("testdata");
+ MakeIOVector("testdata", &iov_);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(Invoke(
this, &QuicPacketCreatorTest::ClearSerializedPacketForTests));
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- GetNthClientInitiatedStreamId(1), data, kOffset, false, false,
- NOT_RETRANSMISSION, &frame));
+ GetNthClientInitiatedStreamId(1), &iov_, 1u, iov_.iov_len, 0u,
+ kOffset, false, false, NOT_RETRANSMISSION, &frame));
size_t bytes_consumed = frame.stream_frame.data_length;
EXPECT_LT(0u, bytes_consumed);
creator_.FlushCurrentPacket();
@@ -462,9 +472,10 @@
std::string data(capacity + delta, 'A');
size_t bytes_free = delta > 0 ? 0 : 0 - delta;
QuicFrame frame;
+ MakeIOVector(data, &iov_);
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- GetNthClientInitiatedStreamId(1), data, kOffset, false, false,
- NOT_RETRANSMISSION, &frame));
+ GetNthClientInitiatedStreamId(1), &iov_, 1u, iov_.iov_len, 0u, kOffset,
+ false, false, NOT_RETRANSMISSION, &frame));
// BytesFree() returns bytes available for the next frame, which will
// be two bytes smaller since the stream frame would need to be grown.
@@ -502,6 +513,7 @@
size_t bytes_free = delta > 0 ? 0 : 0 - delta;
QuicFrame frame;
+ MakeIOVector(data, &iov_);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
@@ -512,7 +524,8 @@
if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) {
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
QuicUtils::GetCryptoStreamId(client_framer_.transport_version()),
- data, kOffset, false, true, NOT_RETRANSMISSION, &frame));
+ &iov_, 1u, iov_.iov_len, 0u, kOffset, false, true, NOT_RETRANSMISSION,
+ &frame));
size_t bytes_consumed = frame.stream_frame.data_length;
EXPECT_LT(0u, bytes_consumed);
} else {
@@ -556,11 +569,12 @@
size_t bytes_free = delta > 0 ? 0 : 0 - delta;
QuicFrame frame;
+ MakeIOVector(data, &iov_);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- GetNthClientInitiatedStreamId(1), data, kOffset, false, false,
- NOT_RETRANSMISSION, &frame));
+ GetNthClientInitiatedStreamId(1), &iov_, 1u, iov_.iov_len, 0u, kOffset,
+ false, false, NOT_RETRANSMISSION, &frame));
size_t bytes_consumed = frame.stream_frame.data_length;
EXPECT_LT(0u, bytes_consumed);
creator_.FlushCurrentPacket();
@@ -1384,13 +1398,14 @@
QuicFrame frame;
size_t payload_length = creator_.max_packet_length();
const std::string too_long_payload(payload_length, 'a');
+ MakeIOVector(too_long_payload, &iov_);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
client_framer_.transport_version(), Perspective::IS_CLIENT);
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id, too_long_payload, 0u, true, false, NOT_RETRANSMISSION,
- &frame));
+ stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, true, false,
+ NOT_RETRANSMISSION, &frame));
size_t consumed = frame.stream_frame.data_length;
// The entire payload could not be consumed.
EXPECT_GT(payload_length, consumed);
@@ -1435,10 +1450,11 @@
EXPECT_FALSE(creator_.HasPendingStreamFramesOfStream(stream_id));
QuicFrame frame;
- const std::string data("test");
+ MakeIOVector("test", &iov_);
EXPECT_CALL(debug, OnFrameAddedToPacket(_));
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id, data, 0u, false, false, NOT_RETRANSMISSION, &frame));
+ stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false,
+ NOT_RETRANSMISSION, &frame));
size_t consumed = frame.stream_frame.data_length;
EXPECT_EQ(4u, consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
@@ -1488,8 +1504,9 @@
}
EXPECT_FALSE(creator_.HasPendingFrames());
- const std::string data("test");
- producer_.SaveStreamData(GetNthClientInitiatedStreamId(0), data);
+ MakeIOVector("test", &iov_);
+ producer_.SaveStreamData(GetNthClientInitiatedStreamId(0), &iov_, 1u, 0u,
+ iov_.iov_len);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
size_t num_bytes_consumed;
@@ -1497,7 +1514,7 @@
creator_.set_debug_delegate(&debug);
EXPECT_CALL(debug, OnFrameAddedToPacket(_));
creator_.CreateAndSerializeStreamFrame(
- GetNthClientInitiatedStreamId(0), data.length(), 0, 0, true,
+ GetNthClientInitiatedStreamId(0), iov_.iov_len, 0, 0, true,
NOT_RETRANSMISSION, &num_bytes_consumed);
EXPECT_EQ(4u, num_bytes_consumed);
@@ -1524,13 +1541,14 @@
EXPECT_FALSE(creator_.HasPendingFrames());
// Send one byte of stream data.
- const std::string data("a");
- producer_.SaveStreamData(GetNthClientInitiatedStreamId(0), data);
+ MakeIOVector("a", &iov_);
+ producer_.SaveStreamData(GetNthClientInitiatedStreamId(0), &iov_, 1u, 0u,
+ iov_.iov_len);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
size_t num_bytes_consumed;
creator_.CreateAndSerializeStreamFrame(
- GetNthClientInitiatedStreamId(0), data.length(), 0, 0, true,
+ GetNthClientInitiatedStreamId(0), iov_.iov_len, 0, 0, true,
NOT_RETRANSMISSION, &num_bytes_consumed);
EXPECT_EQ(1u, num_bytes_consumed);
@@ -1603,13 +1621,16 @@
std::unique_ptr<QuicData> message_data;
message_data = framer.ConstructHandshakeMessage(message);
+ struct iovec iov;
+ MakeIOVector(absl::string_view(message_data->data(), message_data->length()),
+ &iov);
QuicFrame frame;
EXPECT_CALL(delegate_, OnUnrecoverableError(QUIC_CRYPTO_CHLO_TOO_LARGE, _));
EXPECT_QUIC_BUG(
creator_.ConsumeDataToFillCurrentPacket(
QuicUtils::GetCryptoStreamId(client_framer_.transport_version()),
- absl::string_view(message_data->data(), message_data->length()), 0u,
- false, false, NOT_RETRANSMISSION, &frame),
+ &iov, 1u, iov.iov_len, 0u, 0u, false, false, NOT_RETRANSMISSION,
+ &frame),
"Client hello won't fit in a single packet.");
}
@@ -1644,11 +1665,11 @@
creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE);
creator_.AddPendingPadding(kMaxNumRandomPaddingBytes);
QuicFrame frame;
+ MakeIOVector("test", &iov_);
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
client_framer_.transport_version(), Perspective::IS_CLIENT);
- const std::string data("test");
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id, data, 0u, false,
+ stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, false,
/*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame));
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
@@ -1679,16 +1700,18 @@
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
// Send stream frame of size kStreamFramePayloadSize.
- creator_.ConsumeDataToFillCurrentPacket(
- stream_id, absl::string_view(buf, kStreamFramePayloadSize), 0u, false,
- false, NOT_RETRANSMISSION, &frame);
+ MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize), &iov_);
+ creator_.ConsumeDataToFillCurrentPacket(stream_id, &iov_, 1u, iov_.iov_len,
+ 0u, 0u, false, false,
+ NOT_RETRANSMISSION, &frame);
creator_.FlushCurrentPacket();
// 1 byte padding is sent.
EXPECT_EQ(pending_padding_bytes - 1, creator_.pending_padding_bytes());
// Send stream frame of size kStreamFramePayloadSize + 1.
- creator_.ConsumeDataToFillCurrentPacket(
- stream_id, absl::string_view(buf, kStreamFramePayloadSize + 1),
- kStreamFramePayloadSize, false, false, NOT_RETRANSMISSION, &frame);
+ MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize + 1), &iov_);
+ creator_.ConsumeDataToFillCurrentPacket(stream_id, &iov_, 1u, iov_.iov_len,
+ 0u, kStreamFramePayloadSize, false,
+ false, NOT_RETRANSMISSION, &frame);
// No padding is sent.
creator_.FlushCurrentPacket();
EXPECT_EQ(pending_padding_bytes - 1, creator_.pending_padding_bytes());
@@ -1707,11 +1730,11 @@
EXPECT_CALL(delegate_, GetPacketBuffer()).WillOnce(Return(external_buffer));
QuicFrame frame;
+ MakeIOVector("test", &iov_);
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
client_framer_.transport_version(), Perspective::IS_CLIENT);
- const std::string data("test");
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id, data, 0u, false,
+ stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, false,
/*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame));
EXPECT_CALL(delegate_, OnSerializedPacket(_))
@@ -1769,11 +1792,12 @@
creator_.FlushCurrentPacket();
QuicFrame frame;
+ MakeIOVector("test", &iov_);
QuicStreamId stream_id = QuicUtils::GetFirstBidirectionalStreamId(
client_framer_.transport_version(), Perspective::IS_CLIENT);
- const std::string data("test");
EXPECT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id, data, 0u, false, false, NOT_RETRANSMISSION, &frame));
+ stream_id, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false,
+ NOT_RETRANSMISSION, &frame));
QuicMessageFrame* frame4 =
new QuicMessageFrame(4, MemSliceFromString("message"));
EXPECT_TRUE(creator_.AddFrame(QuicFrame(frame4), NOT_RETRANSMISSION));
@@ -2038,38 +2062,43 @@
StrictMock<MockDebugDelegate> debug;
creator_.set_debug_delegate(&debug);
+ MakeIOVector("test", &iov_);
QuicFrame frame;
- const std::string data1("test");
EXPECT_CALL(debug, OnFrameAddedToPacket(_));
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id1, data1, 0u, false, false, NOT_RETRANSMISSION, &frame));
+ stream_id1, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false,
+ NOT_RETRANSMISSION, &frame));
EXPECT_TRUE(creator_.HasPendingFrames());
EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream(stream_id1));
- const std::string data2("coalesce");
+ MakeIOVector("coalesce", &iov_);
// frame will be coalesced with the first frame.
const auto previous_size = creator_.PacketSize();
- QuicStreamFrame target(stream_id1, true, 0, data1.length() + data2.length());
+ QuicStreamFrame target(stream_id1, true, 0, 12);
EXPECT_CALL(debug, OnStreamFrameCoalesced(target));
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id1, data2, 4u, true, false, NOT_RETRANSMISSION, &frame));
+ stream_id1, &iov_, 1u, iov_.iov_len, 0u, 4u, true, false,
+ NOT_RETRANSMISSION, &frame));
EXPECT_EQ(frame.stream_frame.data_length,
creator_.PacketSize() - previous_size);
// frame is for another stream, so it won't be coalesced.
const auto length = creator_.BytesFree() - 10u;
- const std::string data3(length, 'x');
+ std::string large_data(length, 'x');
+ MakeIOVector(large_data, &iov_);
EXPECT_CALL(debug, OnFrameAddedToPacket(_));
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id2, data3, 0u, false, false, NOT_RETRANSMISSION, &frame));
+ stream_id2, &iov_, 1u, iov_.iov_len, 0u, 0u, false, false,
+ NOT_RETRANSMISSION, &frame));
EXPECT_TRUE(creator_.HasPendingStreamFramesOfStream(stream_id2));
// The packet doesn't have enough free bytes for all data, but will still be
// able to consume and coalesce part of them.
EXPECT_CALL(debug, OnStreamFrameCoalesced(_));
- const std::string data4("somerandomdata");
+ MakeIOVector("somerandomdata", &iov_);
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- stream_id2, data4, length, false, false, NOT_RETRANSMISSION, &frame));
+ stream_id2, &iov_, 1u, iov_.iov_len, 0u, length, false, false,
+ NOT_RETRANSMISSION, &frame));
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket));
@@ -2225,12 +2254,14 @@
// restored.
creator_.SetSoftMaxPacketLength(overhead);
EXPECT_EQ(overhead, creator_.max_packet_length());
- const std::string data = "crypto data";
+ std::string data = "crypto data";
+ MakeIOVector(data, &iov_);
QuicFrame frame;
if (!QuicVersionUsesCryptoFrames(client_framer_.transport_version())) {
ASSERT_TRUE(creator_.ConsumeDataToFillCurrentPacket(
- QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), data,
- kOffset, false, true, NOT_RETRANSMISSION, &frame));
+ QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_,
+ 1u, iov_.iov_len, 0u, kOffset, false, true, NOT_RETRANSMISSION,
+ &frame));
size_t bytes_consumed = frame.stream_frame.data_length;
EXPECT_LT(0u, bytes_consumed);
} else {
@@ -2386,28 +2417,34 @@
}
QuicConsumedData ConsumeDataFastPath(QuicStreamId id,
- absl::string_view data) {
+ const struct iovec* iov,
+ int iov_count,
+ size_t total_length,
+ QuicStreamOffset offset,
+ bool fin) {
// Save data before data is consumed.
- if (!data.empty()) {
- producer_->SaveStreamData(id, data);
+ if (total_length > 0) {
+ producer_->SaveStreamData(id, iov, iov_count, 0, total_length);
}
- return QuicPacketCreator::ConsumeDataFastPath(id, data.length(),
- /* offset = */ 0,
- /* fin = */ true, 0);
+ return QuicPacketCreator::ConsumeDataFastPath(id, total_length, offset, fin,
+ 0);
}
- QuicConsumedData ConsumeData(QuicStreamId id, absl::string_view data,
+ QuicConsumedData ConsumeData(QuicStreamId id,
+ const struct iovec* iov,
+ int iov_count,
+ size_t total_length,
QuicStreamOffset offset,
StreamSendingState state) {
// Save data before data is consumed.
- if (!data.empty()) {
- producer_->SaveStreamData(id, data);
+ if (total_length > 0) {
+ producer_->SaveStreamData(id, iov, iov_count, 0, total_length);
}
if (!has_ack() && delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA,
NOT_HANDSHAKE)) {
EXPECT_CALL(*delegate_, MaybeBundleAckOpportunistically()).Times(1);
}
- return QuicPacketCreator::ConsumeData(id, data.length(), offset, state);
+ return QuicPacketCreator::ConsumeData(id, total_length, offset, state);
}
MessageStatus AddMessageFrame(QuicMessageId message_id,
@@ -2554,6 +2591,13 @@
}
}
+ void CreateData(size_t len) {
+ data_array_.reset(new char[len]);
+ memset(data_array_.get(), '?', len);
+ iov_.iov_base = data_array_.get();
+ iov_.iov_len = len;
+ }
+
QuicFramer framer_;
MockRandom random_creator_;
StrictMock<MockDelegate> delegate_;
@@ -2586,13 +2630,14 @@
WrongEncryptionLevelForStreamDataFastPath) {
creator_.set_encryption_level(ENCRYPTION_HANDSHAKE);
delegate_.SetCanWriteAnything();
- const std::string data(10000, '?');
+ // Create a 10000 byte IOVector.
+ CreateData(10000);
EXPECT_CALL(delegate_, OnSerializedPacket(_)).Times(0);
EXPECT_CALL(delegate_, OnUnrecoverableError(_, _));
EXPECT_QUIC_BUG(creator_.ConsumeDataFastPath(
QuicUtils::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT),
- data),
+ &iov_, 1u, iov_.iov_len, 0, true),
"");
}
@@ -2689,10 +2734,11 @@
TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_NotWritable) {
delegate_.SetCanNotWrite();
+ MakeIOVector("foo", &iov_);
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- "foo", 0, FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(0u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_FALSE(creator_.HasPendingFrames());
@@ -2703,10 +2749,11 @@
ConsumeData_WritableAndShouldNotFlush) {
delegate_.SetCanWriteAnything();
+ MakeIOVector("foo", &iov_);
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- "foo", 0, FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
@@ -2720,10 +2767,11 @@
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ MakeIOVector("foo", &iov_);
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- "foo", 0, FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
creator_.Flush();
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
@@ -2744,7 +2792,8 @@
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
- const std::string data = "foo bar";
+ std::string data = "foo bar";
+ MakeIOVector(data, &iov_);
size_t consumed_bytes = 0;
if (QuicVersionUsesCryptoFrames(framer_.transport_version())) {
consumed_bytes = creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0);
@@ -2752,8 +2801,8 @@
consumed_bytes =
creator_
.ConsumeData(
- QuicUtils::GetCryptoStreamId(framer_.transport_version()), data,
- 0, NO_FIN)
+ QuicUtils::GetCryptoStreamId(framer_.transport_version()),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN)
.bytes_consumed;
}
EXPECT_EQ(7u, consumed_bytes);
@@ -2785,7 +2834,8 @@
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
- const std::string data = "foo";
+ std::string data = "foo";
+ MakeIOVector(data, &iov_);
size_t bytes_consumed = 0;
if (QuicVersionUsesCryptoFrames(framer_.transport_version())) {
bytes_consumed = creator_.ConsumeCryptoData(ENCRYPTION_INITIAL, data, 0);
@@ -2793,8 +2843,8 @@
bytes_consumed =
creator_
.ConsumeData(
- QuicUtils::GetCryptoStreamId(framer_.transport_version()), data,
- 0, NO_FIN)
+ QuicUtils::GetCryptoStreamId(framer_.transport_version()),
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN)
.bytes_consumed;
}
EXPECT_EQ(3u, bytes_consumed);
@@ -2832,7 +2882,7 @@
EXPECT_QUIC_BUG(creator_.ConsumeData(
QuicUtils::QuicUtils::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT),
- {}, 0, NO_FIN),
+ nullptr, 0, 0, 0, NO_FIN),
"Attempt to consume empty data without FIN.");
}
@@ -2840,10 +2890,13 @@
ConsumeDataMultipleTimes_WritableAndShouldNotFlush) {
delegate_.SetCanWriteAnything();
+ MakeIOVector("foo", &iov_);
creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT),
- "foo", 0, FIN);
- QuicConsumedData consumed = creator_.ConsumeData(3, "quux", 3, NO_FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
+ MakeIOVector("quux", &iov_);
+ QuicConsumedData consumed =
+ creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 3, NO_FIN);
EXPECT_EQ(4u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
@@ -2853,13 +2906,15 @@
TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeData_BatchOperations) {
delegate_.SetCanWriteAnything();
+ MakeIOVector("foo", &iov_);
creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT),
- "foo", 0, NO_FIN);
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
+ MakeIOVector("quux", &iov_);
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- "quux", 3, FIN);
+ &iov_, 1u, iov_.iov_len, 3, FIN);
EXPECT_EQ(4u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
@@ -2914,10 +2969,11 @@
}
// Queue enough data to prevent a stream frame with a non-zero offset from
// fitting.
+ MakeIOVector("foo", &iov_);
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- "foo", 0, NO_FIN);
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
@@ -2925,10 +2981,11 @@
// This frame will not fit with the existing frame, causing the queued frame
// to be serialized, and it will be added to a new open packet.
+ MakeIOVector("bar", &iov_);
consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- "bar", 3, FIN);
+ &iov_, 1u, iov_.iov_len, 3, FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
@@ -2948,14 +3005,15 @@
delegate_.SetCanWriteAnything();
creator_.SetTransmissionType(LOSS_RETRANSMISSION);
- const std::string data(10000, '?');
+ // Create a 10000 byte IOVector.
+ CreateData(10000);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
QuicConsumedData consumed = creator_.ConsumeDataFastPath(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- data);
+ &iov_, 1u, iov_.iov_len, 0, true);
EXPECT_EQ(10000u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(creator_.HasPendingFrames());
@@ -2977,14 +3035,15 @@
TEST_F(QuicPacketCreatorMultiplePacketsTest, ConsumeDataLarge) {
delegate_.SetCanWriteAnything();
- const std::string data(10000, '?');
+ // Create a 10000 byte IOVector.
+ CreateData(10000);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- data, 0, FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(10000u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
EXPECT_FALSE(creator_.HasPendingFrames());
@@ -3018,7 +3077,8 @@
creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
/*bundle_ack=*/false);
- const std::string data(10000, '?');
+ // Create a 10000 byte IOVector.
+ CreateData(10000);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
@@ -3027,7 +3087,7 @@
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- data, 0, FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
creator_.Flush();
EXPECT_EQ(10000u, consumed.bytes_consumed);
@@ -3048,14 +3108,15 @@
delegate_.SetCanNotWrite();
delegate_.SetCanWriteAnything();
- const std::string data(10000, '?');
+ // Create a 10000 byte IOVector.
+ CreateData(10000);
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- data, 0, FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
creator_.Flush();
EXPECT_EQ(10000u, consumed.bytes_consumed);
@@ -3090,7 +3151,8 @@
creator_.ConsumeRetransmittableControlFrame(QuicFrame(rst_frame),
/*bundle_ack=*/false));
// Send some data and a control frame
- creator_.ConsumeData(3, "quux", 0, NO_FIN);
+ MakeIOVector("quux", &iov_);
+ creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
creator_.ConsumeRetransmittableControlFrame(QuicFrame(CreateGoAwayFrame()),
/*bundle_ack=*/false);
@@ -3147,8 +3209,9 @@
/*bundle_ack=*/false));
// Send enough data to exceed one packet
size_t data_len = kDefaultMaxPacketSize + 100;
- const std::string data(data_len, '?');
- QuicConsumedData consumed = creator_.ConsumeData(3, data, 0, FIN);
+ CreateData(data_len);
+ QuicConsumedData consumed =
+ creator_.ConsumeData(3, &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
if (!VersionHasIetfQuicFrames(framer_.transport_version())) {
@@ -3187,10 +3250,11 @@
creator_.SetTransmissionType(LOSS_RETRANSMISSION);
size_t data_len = 1224;
- const std::string data(data_len, '?');
+ CreateData(data_len);
QuicStreamId stream1_id = QuicUtils::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT);
- QuicConsumedData consumed = creator_.ConsumeData(stream1_id, data, 0, NO_FIN);
+ QuicConsumedData consumed =
+ creator_.ConsumeData(stream1_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
EXPECT_EQ(data_len, consumed.bytes_consumed);
ASSERT_EQ(0u, creator_.BytesFree())
<< "Test setup failed: Please increase data_len to "
@@ -3205,7 +3269,8 @@
QuicStreamId stream2_id = stream1_id + 4;
- consumed = creator_.ConsumeData(stream2_id, data, 0, NO_FIN);
+ consumed =
+ creator_.ConsumeData(stream2_id, &iov_, 1u, iov_.iov_len, 0, NO_FIN);
EXPECT_EQ(data_len, consumed.bytes_consumed);
// Ensure the packet is successfully created.
@@ -3254,11 +3319,11 @@
.Times(3)
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
- const std::string data(data_len, '?');
+ CreateData(data_len);
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- data,
+ &iov_, 1u, iov_.iov_len,
/*offset=*/0, FIN);
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
@@ -3293,11 +3358,11 @@
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
// Send two packets before packet size change.
- const std::string data(data_len, '?');
+ CreateData(data_len);
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- data,
+ &iov_, 1u, iov_.iov_len,
/*offset=*/0, NO_FIN);
creator_.Flush();
EXPECT_EQ(data_len, consumed.bytes_consumed);
@@ -3313,11 +3378,12 @@
EXPECT_EQ(packet_len, creator_.max_packet_length());
// Send a packet after packet size change.
+ CreateData(data_len);
creator_.AttachPacketFlusher();
consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- data, data_len, FIN);
+ &iov_, 1u, iov_.iov_len, data_len, FIN);
creator_.Flush();
EXPECT_EQ(data_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
@@ -3345,11 +3411,11 @@
// First send half of the packet worth of data. We are in the batch mode, so
// should not cause packet serialization.
- const std::string first_write(first_write_len, '?');
+ CreateData(first_write_len);
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- first_write,
+ &iov_, 1u, iov_.iov_len,
/*offset=*/0, NO_FIN);
EXPECT_EQ(first_write_len, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
@@ -3381,11 +3447,11 @@
// Send a more than a packet worth of data to the same stream. This should
// trigger serialization of one packet, and queue another one.
- const std::string second_write(second_write_len, '?');
+ CreateData(second_write_len);
consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- second_write,
+ &iov_, 1u, iov_.iov_len,
/*offset=*/first_write_len, FIN);
EXPECT_EQ(second_write_len, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
@@ -3475,11 +3541,11 @@
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
// Send data before the MTU probe.
- const std::string data(data_len, '?');
+ CreateData(data_len);
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- data,
+ &iov_, 1u, iov_.iov_len,
/*offset=*/0, NO_FIN);
creator_.Flush();
EXPECT_EQ(data_len, consumed.bytes_consumed);
@@ -3493,11 +3559,12 @@
EXPECT_FALSE(creator_.HasPendingRetransmittableFrames());
// Send data after the MTU probe.
+ CreateData(data_len);
creator_.AttachPacketFlusher();
consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(framer_.transport_version(),
Perspective::IS_CLIENT),
- data,
+ &iov_, 1u, iov_.iov_len,
/*offset=*/data_len, FIN);
creator_.Flush();
EXPECT_EQ(data_len, consumed.bytes_consumed);
@@ -3588,9 +3655,9 @@
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize), &iov_);
QuicConsumedData consumed = creator_.ConsumeData(
- kDataStreamId, absl::string_view(buf, kStreamFramePayloadSize), 0,
- FIN_AND_PADDING);
+ kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING);
creator_.Flush();
EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
EXPECT_FALSE(creator_.HasPendingFrames());
@@ -3631,9 +3698,9 @@
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize), &iov_);
QuicConsumedData consumed = creator_.ConsumeData(
- kDataStreamId, absl::string_view(buf, kStreamFramePayloadSize), 0,
- FIN_AND_PADDING);
+ kDataStreamId, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING);
creator_.Flush();
EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
EXPECT_FALSE(creator_.HasPendingFrames());
@@ -3686,13 +3753,13 @@
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillRepeatedly(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize), &iov_);
QuicConsumedData consumed = creator_.ConsumeData(
- kDataStreamId1, absl::string_view(buf, kStreamFramePayloadSize), 0,
- FIN_AND_PADDING);
+ kDataStreamId1, &iov_, 1u, iov_.iov_len, 0, FIN_AND_PADDING);
EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
- consumed = creator_.ConsumeData(
- kDataStreamId2, absl::string_view(buf, kStreamFramePayloadSize), 0,
- FIN_AND_PADDING);
+ MakeIOVector(absl::string_view(buf, kStreamFramePayloadSize), &iov_);
+ consumed = creator_.ConsumeData(kDataStreamId2, &iov_, 1u, iov_.iov_len, 0,
+ FIN_AND_PADDING);
EXPECT_EQ(kStreamFramePayloadSize, consumed.bytes_consumed);
creator_.Flush();
EXPECT_FALSE(creator_.HasPendingFrames());
@@ -3729,9 +3796,10 @@
.WillOnce(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ MakeIOVector("foo", &iov_);
creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT),
- "foo", 0, FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(MESSAGE_STATUS_SUCCESS,
creator_.AddMessageFrame(1, MemSliceFromString("message")));
EXPECT_TRUE(creator_.HasPendingFrames());
@@ -3773,9 +3841,10 @@
EXPECT_CALL(delegate_, OnSerializedPacket(_))
.WillOnce(
Invoke(this, &QuicPacketCreatorMultiplePacketsTest::SavePacket));
+ MakeIOVector("a", &iov_);
creator_.ConsumeData(QuicUtils::GetFirstBidirectionalStreamId(
framer_.transport_version(), Perspective::IS_CLIENT),
- "a", 0, FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
creator_.Flush();
ASSERT_FALSE(packets_[0].nonretransmittable_frames.empty());
QuicFrame padding = packets_[0].nonretransmittable_frames[0];
@@ -3792,12 +3861,13 @@
creator_.SetClientConnectionId(client_connection_id);
creator_.SetServerConnectionId(server_connection_id);
// Send some stream data.
+ MakeIOVector("foo", &iov_);
EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
.WillRepeatedly(Return(true));
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
Perspective::IS_CLIENT),
- "foo", 0, NO_FIN);
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
{
@@ -3812,7 +3882,7 @@
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
Perspective::IS_CLIENT),
- "foo", 0, FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
}
// After exiting the scope, the last queued frame should be flushed.
@@ -3832,12 +3902,13 @@
QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345);
creator_.SetDefaultPeerAddress(peer_addr);
// Send some stream data.
+ MakeIOVector("foo", &iov_);
EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
.WillRepeatedly(Return(true));
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
Perspective::IS_CLIENT),
- "foo", 0, NO_FIN);
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
QuicSocketAddress peer_addr1(QuicIpAddress::Any4(), 12346);
@@ -3867,7 +3938,7 @@
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
Perspective::IS_CLIENT),
- "foo", 0, FIN);
+ &iov_, 1u, iov_.iov_len, 0, FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
}
@@ -3888,12 +3959,13 @@
ASSERT_EQ(server_connection_id1, creator_.GetServerConnectionId());
// Send some stream data.
+ MakeIOVector("foo", &iov_);
EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
.WillRepeatedly(Return(true));
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(),
Perspective::IS_CLIENT),
- "foo", 0, NO_FIN);
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
@@ -3912,12 +3984,13 @@
/*update_connection_id=*/true);
ASSERT_EQ(client_connection_id2, creator_.GetClientConnectionId());
ASSERT_EQ(server_connection_id2, creator_.GetServerConnectionId());
+ MakeIOVector("foo", &iov_);
EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _))
.WillRepeatedly(Return(true));
QuicConsumedData consumed = creator_.ConsumeData(
QuicUtils::GetFirstBidirectionalStreamId(
creator_.transport_version(), Perspective::IS_CLIENT),
- "foo", 0, NO_FIN);
+ &iov_, 1u, iov_.iov_len, 0, NO_FIN);
EXPECT_EQ(3u, consumed.bytes_consumed);
EXPECT_TRUE(creator_.HasPendingFrames());
// This should trigger another OnSerializedPacket() with the 2nd
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc
index 4d5eed5..68ae9f9 100644
--- a/quic/core/quic_session_test.cc
+++ b/quic/core/quic_session_test.cc
@@ -352,12 +352,14 @@
}
QuicConsumedData SendStreamData(QuicStream* stream) {
+ struct iovec iov;
if (!QuicUtils::IsCryptoStreamId(connection()->transport_version(),
stream->id()) &&
this->connection()->encryption_level() != ENCRYPTION_FORWARD_SECURE) {
this->connection()->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
}
- QuicStreamPeer::SendBuffer(stream).SaveStreamData("not empty");
+ MakeIOVector("not empty", &iov);
+ QuicStreamPeer::SendBuffer(stream).SaveStreamData(&iov, 1, 0, 9);
QuicConsumedData consumed =
WritevData(stream->id(), 9, 0, FIN, NOT_RETRANSMISSION,
GetEncryptionLevelToSendApplicationData());
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc
index 8737044..f8e00b4 100644
--- a/quic/core/quic_stream.cc
+++ b/quic/core/quic_stream.cc
@@ -688,6 +688,7 @@
// Do not respect buffered data upper limit as WriteOrBufferData guarantees
// all data to be consumed.
if (data.length() > 0) {
+ struct iovec iov(QuicUtils::MakeIovec(data));
QuicStreamOffset offset = send_buffer_.stream_offset();
if (kMaxStreamLength - offset < data.length()) {
QUIC_BUG(quic_bug_10586_4) << "Write too many data via stream " << id_;
@@ -696,7 +697,7 @@
absl::StrCat("Write too many data via stream ", id_));
return;
}
- send_buffer_.SaveStreamData(data);
+ send_buffer_.SaveStreamData(&iov, 1, 0, data.length());
OnDataBuffered(offset, data.length(), ack_listener);
}
if (!had_buffered_data && (HasBufferedData() || fin_buffered_)) {
diff --git a/quic/core/quic_stream_send_buffer.cc b/quic/core/quic_stream_send_buffer.cc
index 6017768..aa58ead 100644
--- a/quic/core/quic_stream_send_buffer.cc
+++ b/quic/core/quic_stream_send_buffer.cc
@@ -58,19 +58,22 @@
QuicStreamSendBuffer::~QuicStreamSendBuffer() {}
-void QuicStreamSendBuffer::SaveStreamData(absl::string_view data) {
- QUICHE_DCHECK(!data.empty());
-
+void QuicStreamSendBuffer::SaveStreamData(const struct iovec* iov,
+ int iov_count,
+ size_t iov_offset,
+ QuicByteCount data_length) {
+ QUICHE_DCHECK_LT(0u, data_length);
// Latch the maximum data slice size.
const QuicByteCount max_data_slice_size =
GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size);
- while (!data.empty()) {
- size_t slice_len = std::min(data.length(), max_data_slice_size);
- auto buffer =
- quiche::QuicheBuffer::Copy(allocator_, data.substr(0, slice_len));
+ while (data_length > 0) {
+ size_t slice_len = std::min(data_length, max_data_slice_size);
+ quiche::QuicheBuffer buffer(allocator_, slice_len);
+ QuicUtils::CopyToBuffer(iov, iov_count, iov_offset, slice_len,
+ buffer.data());
SaveMemSlice(quiche::QuicheMemSlice(std::move(buffer)));
-
- data = data.substr(slice_len);
+ data_length -= slice_len;
+ iov_offset += slice_len;
}
}
diff --git a/quic/core/quic_stream_send_buffer.h b/quic/core/quic_stream_send_buffer.h
index cf3fa13..6fe7b75 100644
--- a/quic/core/quic_stream_send_buffer.h
+++ b/quic/core/quic_stream_send_buffer.h
@@ -69,8 +69,11 @@
QuicStreamSendBuffer(QuicStreamSendBuffer&& other) = delete;
~QuicStreamSendBuffer();
- // Save |data| to send buffer.
- void SaveStreamData(absl::string_view data);
+ // Save |data_length| of data starts at |iov_offset| in |iov| to send buffer.
+ void SaveStreamData(const struct iovec* iov,
+ int iov_count,
+ size_t iov_offset,
+ QuicByteCount data_length);
// Save |slice| to send buffer.
void SaveMemSlice(quiche::QuicheMemSlice slice);
diff --git a/quic/core/quic_stream_send_buffer_test.cc b/quic/core/quic_stream_send_buffer_test.cc
index 599ebf4..2e0f9dc 100644
--- a/quic/core/quic_stream_send_buffer_test.cc
+++ b/quic/core/quic_stream_send_buffer_test.cc
@@ -20,41 +20,46 @@
namespace test {
namespace {
+struct iovec MakeIovec(absl::string_view data) {
+ struct iovec iov = {const_cast<char*>(data.data()),
+ static_cast<size_t>(data.size())};
+ return iov;
+}
+
class QuicStreamSendBufferTest : public QuicTest {
public:
QuicStreamSendBufferTest() : send_buffer_(&allocator_) {
EXPECT_EQ(0u, send_buffer_.size());
EXPECT_EQ(0u, send_buffer_.stream_bytes_written());
EXPECT_EQ(0u, send_buffer_.stream_bytes_outstanding());
- // The stream offset should be 0 since nothing is written.
- EXPECT_EQ(0u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_));
-
- std::string data1 = absl::StrCat(
- std::string(1536, 'a'), std::string(256, 'b'), std::string(256, 'c'));
+ std::string data1(1536, 'a');
+ std::string data2 = std::string(256, 'b') + std::string(256, 'c');
+ struct iovec iov[2];
+ iov[0] = MakeIovec(absl::string_view(data1));
+ iov[1] = MakeIovec(absl::string_view(data2));
quiche::QuicheBuffer buffer1(&allocator_, 1024);
memset(buffer1.data(), 'c', buffer1.size());
quiche::QuicheMemSlice slice1(std::move(buffer1));
-
quiche::QuicheBuffer buffer2(&allocator_, 768);
memset(buffer2.data(), 'd', buffer2.size());
quiche::QuicheMemSlice slice2(std::move(buffer2));
- // `data` will be split into two BufferedSlices.
- SetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size, 1024);
- send_buffer_.SaveStreamData(data1);
+ // The stream offset should be 0 since nothing is written.
+ EXPECT_EQ(0u, QuicStreamSendBufferPeer::EndOffset(&send_buffer_));
+ // Save all data.
+ SetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size, 1024);
+ send_buffer_.SaveStreamData(iov, 2, 0, 2048);
send_buffer_.SaveMemSlice(std::move(slice1));
EXPECT_TRUE(slice1.empty());
send_buffer_.SaveMemSlice(std::move(slice2));
EXPECT_TRUE(slice2.empty());
EXPECT_EQ(4u, send_buffer_.size());
- // At this point, `send_buffer_.interval_deque_` looks like this:
- // BufferedSlice1: 'a' * 1024
- // BufferedSlice2: 'a' * 512 + 'b' * 256 + 'c' * 256
- // BufferedSlice3: 'c' * 1024
- // BufferedSlice4: 'd' * 768
+ // At this point, the whole buffer looks like:
+ // | a * 1536 |b * 256| c * 1280 | d * 768 |
+ // | slice1 | slice2 | slice3 | slice4 |
}
void WriteAllData() {
diff --git a/quic/core/quic_utils.cc b/quic/core/quic_utils.cc
index aa8f59e..caffd7f 100644
--- a/quic/core/quic_utils.cc
+++ b/quic/core/quic_utils.cc
@@ -290,6 +290,13 @@
}
// static
+struct iovec QuicUtils::MakeIovec(absl::string_view data) {
+ struct iovec iov = {const_cast<char*>(data.data()),
+ static_cast<size_t>(data.size())};
+ return iov;
+}
+
+// static
bool QuicUtils::IsAckable(SentPacketState state) {
return state != NEVER_SENT && state != ACKED && state != UNACKABLE;
}
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h
index 085f532..43e6470 100644
--- a/quic/core/quic_utils.h
+++ b/quic/core/quic_utils.h
@@ -81,6 +81,9 @@
size_t buffer_length,
char* buffer);
+ // Creates an iovec pointing to the same data as |data|.
+ static struct iovec MakeIovec(absl::string_view data);
+
// Returns the opposite Perspective of the |perspective| passed in.
static constexpr Perspective InvertPerspective(Perspective perspective) {
return perspective == Perspective::IS_CLIENT ? Perspective::IS_SERVER
diff --git a/quic/test_tools/simple_data_producer.cc b/quic/test_tools/simple_data_producer.cc
index 64c0a2c..aaab1d1 100644
--- a/quic/test_tools/simple_data_producer.cc
+++ b/quic/test_tools/simple_data_producer.cc
@@ -20,14 +20,17 @@
SimpleDataProducer::~SimpleDataProducer() {}
void SimpleDataProducer::SaveStreamData(QuicStreamId id,
- absl::string_view data) {
- if (data.empty()) {
+ const struct iovec* iov,
+ int iov_count,
+ size_t iov_offset,
+ QuicByteCount data_length) {
+ if (data_length == 0) {
return;
}
if (!send_buffer_map_.contains(id)) {
send_buffer_map_[id] = std::make_unique<QuicStreamSendBuffer>(&allocator_);
}
- send_buffer_map_[id]->SaveStreamData(data);
+ send_buffer_map_[id]->SaveStreamData(iov, iov_count, iov_offset, data_length);
}
void SimpleDataProducer::SaveCryptoData(EncryptionLevel level,
diff --git a/quic/test_tools/simple_data_producer.h b/quic/test_tools/simple_data_producer.h
index 9564f86..e8dd4e4 100644
--- a/quic/test_tools/simple_data_producer.h
+++ b/quic/test_tools/simple_data_producer.h
@@ -23,10 +23,17 @@
SimpleDataProducer();
~SimpleDataProducer() override;
- // Saves `data` to be provided when WriteStreamData() is called. Multiple
- // calls to SaveStreamData() for the same stream ID append to the buffer for
- // that stream.
- void SaveStreamData(QuicStreamId id, absl::string_view data);
+ // Saves data to be provided when WriteStreamData is called. Data of length
+ // |data_length| is buffered to be provided for stream |id|. Multiple calls to
+ // SaveStreamData for the same stream ID append to the buffer for that stream.
+ // The data to be buffered is provided in |iov_count| iovec structs, with
+ // |iov| pointing to the first, and |iov_offset| indicating how many bytes
+ // into the iovec structs the data starts.
+ void SaveStreamData(QuicStreamId id,
+ const struct iovec* iov,
+ int iov_count,
+ size_t iov_offset,
+ QuicByteCount data_length);
void SaveCryptoData(EncryptionLevel level,
QuicStreamOffset offset,