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,