Commit 43f63588 authored by Hasan Khalil's avatar Hasan Khalil Committed by Commit Bot

Landing recent QUIC changes until Sun Nov 11 05:01:18 2018 +0000

====

Flip flags FLAGS_quic_reloadable_flag_quic_session_faster_get_stream and
FLAGS_quic_reloadable_flag_quic_enable_server_epid_in_public_reset to
true.

====

Ensure that QuicSession::OnCanCreateNewOutgoingStream is invoked
when a the final by offset is received, even if the stream
was previously closed.

Merge internal change: 220855840

https://chromium-review.googlesource.com/c/1340886/

====

all code driven from app, which has not been modified to call it

Add API and code path to generate IETF QUIC STOP_SENDING Frames

This CL adds an API facing the QUIC Application and the internal code
path required to generate an IETF QUIC STOP_SENDING frame and unit tests
of this path are added as well.

The api is QuicStream::SendStopSending(). The application invokes this
to generate an IETF QUIC STOP_SENDING frame and send it to the peer.
This CL consists of the logic from QuicStream::SendStopSending through
the generation of the frame and adding it ot the set of control frames
that are to be transmitted. QuicStream::StopSending invokes
QuicSession::StopSending, which in turn requests that
QuicControlFrameManager create and transmit (or enqueue for later
transmission) a STOP_SENDING frame.

Additional STOP_SENDING work will be in follow on CLs.

Merge internal change: 220799380

https://chromium-review.googlesource.com/c/1340885/

====

logging only

Add SNI to the QUIC_LOG about expected SCTs being empty.

Merge internal change: 220686048

https://chromium-review.googlesource.com/c/1340884/

====

test changes only

Modify quic_stream_test so that parameterized tests are available.

This CL extends quic_stream_test so that parameterized tests (different
versions) can be executed. This is needed in support of IETF QUIC
(version 99)
STOP_SENDING work -- subject of a follow-on CL.

Two tests have been converted over to be parameterized; this is not
strictly
necessary as they both failed during development due to an error in
initialization. They've been kept as parameterized to provide a
back-stop
against other potential issues and to demonstrate that the parameterized
tests actually are parameterized...

Merge internal change: 220654875

https://chromium-review.googlesource.com/c/1340883/

====

Add flag count only.

Add a QUIC_FLAG_COUNT for flag
FLAGS_quic_reloadable_flag_quic_aggregate_acked_stream_frames_2.

Merge internal change: 220469321

https://chromium-review.googlesource.com/c/1340882/

====

comment-only change

Clarification for QuicSession::SendMessgage about blocked connection

It was not obvious to me that SendMessage could fail if connection was
congession controlled, so I wanted to add comments to the API.

See also my comment about calling under OnCanWrite and assumption that
message is alive until exiting the flusher's scope. Even if it's not a
problem with OnCanWrite it's a dangerous assumption. Why not to copy
message or accept a string by value and move to be on a safe side?

Merge internal change: 220119478

https://chromium-review.googlesource.com/c/1340880/

====

test only change

Disable tests relying on goaway for QUIC v99.

Merge internal change: 220095515

https: //chromium-review.googlesource.com/c/1340879/
Change-Id: Idade360d6baa9215e0825bddf8994c953fb43b37
Reviewed-on: https://chromium-review.googlesource.com/c/1340888
Commit-Queue: Hasan Khalil <hkhalil@google.com>
Commit-Queue: Ryan Hamilton <rch@chromium.org>
Reviewed-by: default avatarRyan Hamilton <rch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#609056}
parent 7e86ed65
......@@ -1466,9 +1466,6 @@ void QuicChromiumClientSession::OnGoAway(const quic::QuicGoAwayFrame& frame) {
void QuicChromiumClientSession::OnRstStream(
const quic::QuicRstStreamFrame& frame) {
quic::QuicSession::OnRstStream(frame);
// TODO(zhongyi): remove the call to OnCanCreateNewOutgoingStream when
// b/119278038 is fixed and the bugfix is merged to chromium.
OnCanCreateNewOutgoingStream();
}
void QuicChromiumClientSession::OnConnectionClosed(
......
......@@ -171,9 +171,7 @@ QUIC_FLAG(bool,
// If ture, make QuicSession::GetStream faster by skipping the lookup into
// static stream map, when possible.
QUIC_FLAG(bool,
FLAGS_quic_reloadable_flag_quic_session_faster_get_stream,
false)
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_session_faster_get_stream, true)
// If true, when session decides what to write, set a approximate retransmission
// for packets to be retransmitted. Also check packet state in
......@@ -304,7 +302,7 @@ QUIC_FLAG(bool,
// If true, public reset packets sent from GFE will include a kEPID tag.
QUIC_FLAG(bool,
FLAGS_quic_reloadable_flag_quic_enable_server_epid_in_public_reset,
false)
true)
// If true, public reset packets sent from GFE will include a kEPID tag.
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_spurious_ack_alarm, false)
......
......@@ -1555,6 +1555,7 @@ QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
client_common_set_hashes_(params.client_common_set_hashes),
client_cached_cert_hashes_(params.client_cached_cert_hashes),
sct_supported_by_client_(params.sct_supported_by_client),
sni_(params.sni),
message_(std::move(message)),
cb_(std::move(cb)) {}
......@@ -1566,7 +1567,7 @@ void QuicCryptoServerConfig::BuildServerConfigUpdateMessageProofSourceCallback::
config_->FinishBuildServerConfigUpdateMessage(
version_, compressed_certs_cache_, common_cert_sets_,
client_common_set_hashes_, client_cached_cert_hashes_,
sct_supported_by_client_, ok, chain, proof.signature,
sct_supported_by_client_, sni_, ok, chain, proof.signature,
proof.leaf_cert_scts, std::move(details), std::move(message_),
std::move(cb_));
}
......@@ -1578,6 +1579,7 @@ void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage(
const QuicString& client_common_set_hashes,
const QuicString& client_cached_cert_hashes,
bool sct_supported_by_client,
const QuicString& sni,
bool ok,
const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
const QuicString& signature,
......@@ -1598,7 +1600,8 @@ void QuicCryptoServerConfig::FinishBuildServerConfigUpdateMessage(
message.SetStringPiece(kPROF, signature);
if (sct_supported_by_client && enable_serving_sct_) {
if (leaf_cert_sct.empty()) {
QUIC_LOG_EVERY_N_SEC(WARNING, 60) << "SCT is expected but it is empty.";
QUIC_LOG_EVERY_N_SEC(WARNING, 60)
<< "SCT is expected but it is empty. SNI: " << sni;
} else {
message.SetStringPiece(kCertificateSCTTag, leaf_cert_sct);
}
......
......@@ -730,6 +730,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
const QuicString client_common_set_hashes_;
const QuicString client_cached_cert_hashes_;
const bool sct_supported_by_client_;
const QuicString sni_;
CryptoHandshakeMessage message_;
std::unique_ptr<BuildServerConfigUpdateMessageResultCallback> cb_;
};
......@@ -744,6 +745,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerConfig {
const QuicString& client_common_set_hashes,
const QuicString& client_cached_cert_hashes,
bool sct_supported_by_client,
const QuicString& sni,
bool ok,
const QuicReferenceCountedPointer<ProofSource::Chain>& chain,
const QuicString& signature,
......
......@@ -166,6 +166,7 @@ bool IsControlFrame(QuicFrameType type) {
case STREAM_ID_BLOCKED_FRAME:
case MAX_STREAM_ID_FRAME:
case PING_FRAME:
case STOP_SENDING_FRAME:
return true;
default:
return false;
......@@ -188,6 +189,8 @@ QuicControlFrameId GetControlFrameId(const QuicFrame& frame) {
return frame.max_stream_id_frame.control_frame_id;
case PING_FRAME:
return frame.ping_frame.control_frame_id;
case STOP_SENDING_FRAME:
return frame.stop_sending_frame->control_frame_id;
default:
return kInvalidControlFrameId;
}
......@@ -216,6 +219,9 @@ void SetControlFrameId(QuicControlFrameId control_frame_id, QuicFrame* frame) {
case MAX_STREAM_ID_FRAME:
frame->max_stream_id_frame.control_frame_id = control_frame_id;
return;
case STOP_SENDING_FRAME:
frame->stop_sending_frame->control_frame_id = control_frame_id;
return;
default:
QUIC_BUG
<< "Try to set control frame id of a frame without control frame id";
......@@ -240,6 +246,9 @@ QuicFrame CopyRetransmittableControlFrame(const QuicFrame& frame) {
case PING_FRAME:
copy = QuicFrame(QuicPingFrame(frame.ping_frame.control_frame_id));
break;
case STOP_SENDING_FRAME:
copy = QuicFrame(new QuicStopSendingFrame(*frame.stop_sending_frame));
break;
default:
QUIC_BUG << "Try to copy a non-retransmittable control frame: " << frame;
copy = QuicFrame(QuicPingFrame(kInvalidControlFrameId));
......
......@@ -39,6 +39,8 @@ TEST_F(QuicFramesTest, AckFrameToString) {
"{ largest_acked: 5, ack_delay_time: 3, packets: [ 4 5 ], "
"received_packets: [ 6 at 7 ], ecn_counters_populated: 0 }\n",
stream.str());
QuicFrame quic_frame(&frame);
EXPECT_FALSE(IsControlFrame(quic_frame.type));
}
TEST_F(QuicFramesTest, BigAckFrameToString) {
......@@ -54,6 +56,8 @@ TEST_F(QuicFramesTest, BigAckFrameToString) {
"{ largest_acked: 500, ack_delay_time: 3, packets: [ 4...500 ], "
"received_packets: [ 500 at 7 ], ecn_counters_populated: 0 }\n",
stream.str());
QuicFrame quic_frame(&frame);
EXPECT_FALSE(IsControlFrame(quic_frame.type));
}
TEST_F(QuicFramesTest, PaddingFrameToString) {
......@@ -62,6 +66,8 @@ TEST_F(QuicFramesTest, PaddingFrameToString) {
std::ostringstream stream;
stream << frame;
EXPECT_EQ("{ num_padding_bytes: 1 }\n", stream.str());
QuicFrame quic_frame(frame);
EXPECT_FALSE(IsControlFrame(quic_frame.type));
}
TEST_F(QuicFramesTest, RstStreamFrameToString) {
......@@ -75,6 +81,52 @@ TEST_F(QuicFramesTest, RstStreamFrameToString) {
stream << rst_stream;
EXPECT_EQ("{ control_frame_id: 1, stream_id: 1, error_code: 6 }\n",
stream.str());
EXPECT_TRUE(IsControlFrame(frame.type));
}
TEST_F(QuicFramesTest, StopSendingFrameToString) {
QuicStopSendingFrame stop_sending;
QuicFrame frame(&stop_sending);
SetControlFrameId(1, &frame);
EXPECT_EQ(1u, GetControlFrameId(frame));
stop_sending.stream_id = 321;
stop_sending.application_error_code = QUIC_STREAM_CANCELLED;
std::ostringstream stream;
stream << stop_sending;
EXPECT_EQ(
"{ control_frame_id: 1, stream_id: 321, application_error_code: 6 }\n",
stream.str());
EXPECT_TRUE(IsControlFrame(frame.type));
}
TEST_F(QuicFramesTest, StreamIdBlockedFrameToString) {
QuicStreamIdBlockedFrame stream_id_blocked;
QuicFrame frame(stream_id_blocked);
SetControlFrameId(1, &frame);
EXPECT_EQ(1u, GetControlFrameId(frame));
// QuicStreamIdBlocked is copied into a QuicFrame (as opposed to putting a
// pointer to it into QuicFrame) so need to work with the copy in |frame| and
// not the original one, stream_id_blocked.
frame.stream_id_blocked_frame.stream_id = 321;
std::ostringstream stream;
stream << frame.stream_id_blocked_frame;
EXPECT_EQ("{ control_frame_id: 1, stream id: 321 }\n", stream.str());
EXPECT_TRUE(IsControlFrame(frame.type));
}
TEST_F(QuicFramesTest, MaxStreamIdFrameToString) {
QuicMaxStreamIdFrame max_stream_id;
QuicFrame frame(max_stream_id);
SetControlFrameId(1, &frame);
EXPECT_EQ(1u, GetControlFrameId(frame));
// QuicMaxStreamId is copied into a QuicFrame (as opposed to putting a
// pointer to it into QuicFrame) so need to work with the copy in |frame| and
// not the original one, max_stream_id.
frame.max_stream_id_frame.max_stream_id = 321;
std::ostringstream stream;
stream << frame.max_stream_id_frame;
EXPECT_EQ("{ control_frame_id: 1, stream_id: 321 }\n", stream.str());
EXPECT_TRUE(IsControlFrame(frame.type));
}
TEST_F(QuicFramesTest, ConnectionCloseFrameToString) {
......@@ -88,6 +140,8 @@ TEST_F(QuicFramesTest, ConnectionCloseFrameToString) {
"frame_type: 0"
"}\n",
stream.str());
QuicFrame quic_frame(&frame);
EXPECT_FALSE(IsControlFrame(quic_frame.type));
}
TEST_F(QuicFramesTest, GoAwayFrameToString) {
......@@ -105,6 +159,7 @@ TEST_F(QuicFramesTest, GoAwayFrameToString) {
"reason_phrase: "
"'Reason' }\n",
stream.str());
EXPECT_TRUE(IsControlFrame(frame.type));
}
TEST_F(QuicFramesTest, WindowUpdateFrameToString) {
......@@ -118,6 +173,7 @@ TEST_F(QuicFramesTest, WindowUpdateFrameToString) {
stream << window_update;
EXPECT_EQ("{ control_frame_id: 3, stream_id: 1, byte_offset: 2 }\n",
stream.str());
EXPECT_TRUE(IsControlFrame(frame.type));
}
TEST_F(QuicFramesTest, BlockedFrameToString) {
......@@ -129,6 +185,7 @@ TEST_F(QuicFramesTest, BlockedFrameToString) {
std::ostringstream stream;
stream << blocked;
EXPECT_EQ("{ control_frame_id: 4, stream_id: 1 }\n", stream.str());
EXPECT_TRUE(IsControlFrame(frame.type));
}
TEST_F(QuicFramesTest, PingFrameToString) {
......@@ -139,6 +196,7 @@ TEST_F(QuicFramesTest, PingFrameToString) {
std::ostringstream stream;
stream << frame.ping_frame;
EXPECT_EQ("{ control_frame_id: 5 }\n", stream.str());
EXPECT_TRUE(IsControlFrame(frame.type));
}
TEST_F(QuicFramesTest, StreamFrameToString) {
......@@ -150,6 +208,7 @@ TEST_F(QuicFramesTest, StreamFrameToString) {
std::ostringstream stream;
stream << frame;
EXPECT_EQ("{ stream_id: 1, fin: 0, offset: 2, length: 3 }\n", stream.str());
EXPECT_FALSE(IsControlFrame(frame.type));
}
TEST_F(QuicFramesTest, StopWaitingFrameToString) {
......@@ -158,6 +217,8 @@ TEST_F(QuicFramesTest, StopWaitingFrameToString) {
std::ostringstream stream;
stream << frame;
EXPECT_EQ("{ least_unacked: 2 }\n", stream.str());
QuicFrame quic_frame(&frame);
EXPECT_FALSE(IsControlFrame(quic_frame.type));
}
TEST_F(QuicFramesTest, IsAwaitingPacket) {
......
......@@ -828,6 +828,11 @@ TEST_P(QuicSpdySessionTestServer, SendGoAway) {
}
TEST_P(QuicSpdySessionTestServer, DoNotSendGoAwayTwice) {
if (connection_->transport_version() == QUIC_VERSION_99) {
// TODO(b/118808809): Enable this test for version 99 when GOAWAY is
// supported.
return;
}
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
......@@ -836,6 +841,11 @@ TEST_P(QuicSpdySessionTestServer, DoNotSendGoAwayTwice) {
}
TEST_P(QuicSpdySessionTestServer, InvalidGoAway) {
if (connection_->transport_version() == QUIC_VERSION_99) {
// TODO(b/118808809): Enable this test for version 99 when GOAWAY is
// supported.
return;
}
QuicGoAwayFrame go_away(kInvalidControlFrameId, QUIC_PEER_GOING_AWAY,
session_.next_outgoing_stream_id(), "");
session_.OnGoAway(go_away);
......
......@@ -69,6 +69,13 @@ void QuicControlFrameManager::WriteOrBufferBlocked(QuicStreamId id) {
QuicFrame(new QuicBlockedFrame(++last_control_frame_id_, id)));
}
void QuicControlFrameManager::WriteOrBufferStopSending(uint16_t code,
QuicStreamId stream_id) {
QUIC_DVLOG(1) << "Writing STOP_SENDING_FRAME";
WriteOrBufferQuicFrame(QuicFrame(
new QuicStopSendingFrame(++last_control_frame_id_, stream_id, code)));
}
void QuicControlFrameManager::WritePing() {
QUIC_DVLOG(1) << "Writing PING_FRAME";
if (HasBufferedFrames()) {
......
......@@ -53,6 +53,10 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager {
// immediately.
void WriteOrBufferBlocked(QuicStreamId id);
// Tries to send an IETF-QUIC STOP_SENDING frame. The frame is buffered if it
// can not be sent immediately.
void WriteOrBufferStopSending(uint16_t code, QuicStreamId stream_id);
// Sends a PING_FRAME. Do not send PING if there is buffered frames.
void WritePing();
......
......@@ -27,6 +27,7 @@ class QuicControlFrameManagerPeer {
namespace {
const QuicStreamId kTestStreamId = 5;
const QuicStreamId kTestStopSendingCode = 321;
class QuicControlFrameManagerTest : public QuicTest {
public:
......@@ -40,6 +41,14 @@ class QuicControlFrameManagerTest : public QuicTest {
}
protected:
// Pre-fills the control frame queue with the following frames:
// ID Type
// 1 RST_STREAM
// 2 GO_AWAY
// 3 WINDOW_UPDATE
// 4 BLOCKED
// 5 STOP_SENDING
// This is verified. The tests then perform manipulations on these.
void Initialize() {
connection_ = new MockQuicConnection(&helper_, &alarm_factory_,
Perspective::IS_SERVER);
......@@ -55,14 +64,19 @@ class QuicControlFrameManagerTest : public QuicTest {
"Going away.");
manager_->WriteOrBufferWindowUpdate(kTestStreamId, 100);
manager_->WriteOrBufferBlocked(kTestStreamId);
EXPECT_EQ(4u, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
manager_->WriteOrBufferStopSending(kTestStopSendingCode, kTestStreamId);
number_of_frames_ = 5u;
ping_frame_id_ = 6u;
EXPECT_EQ(number_of_frames_,
QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&rst_stream_)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&goaway_)));
EXPECT_TRUE(
manager_->IsControlFrameOutstanding(QuicFrame(&window_update_)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&blocked_)));
EXPECT_FALSE(
manager_->IsControlFrameOutstanding(QuicFrame(QuicPingFrame(5))));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&stop_sending_)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(
QuicFrame(QuicPingFrame(ping_frame_id_))));
EXPECT_FALSE(manager_->HasPendingRetransmission());
EXPECT_TRUE(manager_->WillingToWrite());
......@@ -73,12 +87,15 @@ class QuicControlFrameManagerTest : public QuicTest {
"Going away."};
QuicWindowUpdateFrame window_update_ = {3, kTestStreamId, 100};
QuicBlockedFrame blocked_ = {4, kTestStreamId};
QuicStopSendingFrame stop_sending_ = {5, kTestStreamId, kTestStopSendingCode};
MockQuicConnectionHelper helper_;
MockAlarmFactory alarm_factory_;
MockQuicConnection* connection_;
std::unique_ptr<StrictMock<MockQuicSession>> session_;
std::unique_ptr<QuicControlFrameManager> manager_;
QuicFrame frame_;
size_t number_of_frames_;
int ping_frame_id_;
};
TEST_F(QuicControlFrameManagerTest, OnControlFrameAcked) {
......@@ -95,19 +112,25 @@ TEST_F(QuicControlFrameManagerTest, OnControlFrameAcked) {
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&goaway_)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&window_update_)));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&blocked_)));
EXPECT_FALSE(
manager_->IsControlFrameOutstanding(QuicFrame(QuicPingFrame(5))));
EXPECT_TRUE(manager_->IsControlFrameOutstanding(QuicFrame(&stop_sending_)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(
QuicFrame(QuicPingFrame(ping_frame_id_))));
EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(&window_update_)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(&window_update_)));
EXPECT_EQ(4u, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_EQ(number_of_frames_,
QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(&goaway_)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(&goaway_)));
EXPECT_EQ(4u, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_EQ(number_of_frames_,
QuicControlFrameManagerPeer::QueueSize(manager_.get()));
EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(&rst_stream_)));
EXPECT_FALSE(manager_->IsControlFrameOutstanding(QuicFrame(&rst_stream_)));
EXPECT_EQ(1u, QuicControlFrameManagerPeer::QueueSize(manager_.get()));
// Only after the first frame in the queue is acked do the frames get
// removed ... now see that the length has been reduced by 3.
EXPECT_EQ(number_of_frames_ - 3u,
QuicControlFrameManagerPeer::QueueSize(manager_.get()));
// Duplicate ack.
EXPECT_FALSE(manager_->OnControlFrameAcked(QuicFrame(&goaway_)));
......@@ -152,9 +175,9 @@ TEST_F(QuicControlFrameManagerTest, OnControlFrameLost) {
EXPECT_FALSE(manager_->HasPendingRetransmission());
EXPECT_TRUE(manager_->WillingToWrite());
// Send control frames 4, 5.
// Send control frames 4, 5, and 6.
EXPECT_CALL(*connection_, SendControlFrame(_))
.Times(2)
.Times(number_of_frames_ - 2u)
.WillRepeatedly(
Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
manager_->OnCanWrite();
......@@ -167,7 +190,7 @@ TEST_F(QuicControlFrameManagerTest, RetransmitControlFrame) {
InSequence s;
// Send control frames 1, 2, 3, 4.
EXPECT_CALL(*connection_, SendControlFrame(_))
.Times(4)
.Times(number_of_frames_)
.WillRepeatedly(
Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
manager_->OnCanWrite();
......@@ -194,16 +217,16 @@ TEST_F(QuicControlFrameManagerTest, DonotSendPingWithBufferedFrames) {
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillOnce(Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
EXPECT_CALL(*connection_, SendControlFrame(_)).WillOnce(Return(false));
// Send control frames 1.
// Send control frame 1.
manager_->OnCanWrite();
EXPECT_FALSE(manager_->HasPendingRetransmission());
EXPECT_TRUE(manager_->WillingToWrite());
// Send PING when there is buffered frames.
manager_->WritePing();
// Verify only the buffered 3 frames are sent.
// Verify only the buffered frames are sent.
EXPECT_CALL(*connection_, SendControlFrame(_))
.Times(3)
.Times(number_of_frames_ - 1)
.WillRepeatedly(
Invoke(this, &QuicControlFrameManagerTest::ClearControlFrame));
manager_->OnCanWrite();
......@@ -216,10 +239,12 @@ TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) {
Initialize();
// Send two more window updates of the same stream.
manager_->WriteOrBufferWindowUpdate(kTestStreamId, 200);
QuicWindowUpdateFrame window_update2(5, kTestStreamId, 200);
QuicWindowUpdateFrame window_update2(number_of_frames_ + 1, kTestStreamId,
200);
manager_->WriteOrBufferWindowUpdate(kTestStreamId, 300);
QuicWindowUpdateFrame window_update3(6, kTestStreamId, 300);
QuicWindowUpdateFrame window_update3(number_of_frames_ + 2, kTestStreamId,
300);
InSequence s;
// Flush all buffered control frames.
EXPECT_CALL(*connection_, SendControlFrame(_))
......@@ -238,7 +263,8 @@ TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) {
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillOnce(Invoke(this, &QuicControlFrameManagerTest::SaveControlFrame));
manager_->OnCanWrite();
EXPECT_EQ(6u, frame_.window_update_frame->control_frame_id);
EXPECT_EQ(number_of_frames_ + 2u,
frame_.window_update_frame->control_frame_id);
EXPECT_FALSE(manager_->HasPendingRetransmission());
EXPECT_FALSE(manager_->WillingToWrite());
DeleteFrame(&frame_);
......
......@@ -266,6 +266,8 @@ void QuicSentPacketManager::PostProcessAfterMarkingPacketHandled(
bool rtt_updated,
QuicByteCount prior_bytes_in_flight) {
if (aggregate_acked_stream_frames_ && session_decides_what_to_write()) {
QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_aggregate_acked_stream_frames_2,
1, 2);
unacked_packets_.NotifyAggregatedStreamFrameAcked(
last_ack_frame_.ack_delay_time);
}
......@@ -556,6 +558,8 @@ void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number,
unacked_packets_.MaybeAggregateAckedStreamFrame(*info, ack_delay_time);
} else {
if (aggregate_acked_stream_frames_ && session_decides_what_to_write()) {
QUIC_FLAG_COUNT_N(
quic_reloadable_flag_quic_aggregate_acked_stream_frames_2, 2, 2);
unacked_packets_.NotifyAggregatedStreamFrameAcked(ack_delay_time);
}
const bool new_data_acked =
......
......@@ -509,6 +509,8 @@ void QuicSession::SendRstStream(QuicStreamId id,
void QuicSession::SendGoAway(QuicErrorCode error_code,
const QuicString& reason) {
// GOAWAY frame is not supported in v99.
DCHECK_NE(QUIC_VERSION_99, connection_->transport_version());
if (goaway_sent_) {
return;
}
......@@ -573,7 +575,8 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
// If we haven't received a FIN or RST for this stream, we need to keep track
// of the how many bytes the stream's flow controller believes it has
// received, for accurate connection level flow control accounting.
if (!stream->HasFinalReceivedByteOffset()) {
const bool had_fin_or_rst = stream->HasFinalReceivedByteOffset();
if (!had_fin_or_rst) {
InsertLocallyClosedStreamsHighestOffset(
stream_id, stream->flow_controller()->highest_received_byte_offset());
}
......@@ -596,7 +599,7 @@ void QuicSession::CloseStreamInner(QuicStreamId stream_id, bool locally_reset) {
// Decrease the number of streams being emulated when a new one is opened.
connection_->SetNumOpenStreams(dynamic_stream_map_.size());
if (!stream_was_draining && !IsIncomingStream(stream_id)) {
if (!stream_was_draining && !IsIncomingStream(stream_id) && had_fin_or_rst) {
// Streams that first became draining already called OnCanCreate...
// This covers the case where the stream went directly to being closed.
OnCanCreateNewOutgoingStream();
......@@ -630,6 +633,8 @@ void QuicSession::OnFinalByteOffsetReceived(
locally_closed_streams_highest_offset_.erase(it);
if (IsIncomingStream(stream_id)) {
--num_locally_closed_incoming_streams_highest_offset_;
} else {
OnCanCreateNewOutgoingStream();
}
}
......@@ -1414,6 +1419,10 @@ bool QuicSession::deprecate_post_process_after_data() const {
return connection_->deprecate_post_process_after_data();
}
void QuicSession::SendStopSending(uint16_t code, QuicStreamId stream_id) {
control_frame_manager_.WriteOrBufferStopSending(code, stream_id);
}
void QuicSession::OnCanCreateNewOutgoingStream() {}
#undef ENDPOINT // undef for jumbo builds
......
......@@ -161,6 +161,12 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// a packet flusher is added, ensure the |message|'s buffer is not modified or
// deleted before exiting the flusher's scope. OnMessageAcked and
// OnMessageLost are called when a particular message gets acked or lost.
//
// Note that SendMessage will fail with status = MESSAGE_STATUS_BLOCKED
// if connection is congestion control blocked or underlying socket is write
// blocked. In this case the caller can retry sending message again when
// connection becomes available, for example after getting OnCanWrite()
// callback.
MessageResult SendMessage(QuicStringPiece message);
// Called when message with |message_id| gets acked.
......@@ -187,6 +193,9 @@ class QUIC_EXPORT_PRIVATE QuicSession : public QuicConnectionVisitorInterface,
// Sends a WINDOW_UPDATE frame.
virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset);
// Create and transmit a STOP_SENDING frame
virtual void SendStopSending(uint16_t code, QuicStreamId stream_id);
// Removes the stream associated with 'stream_id' from the active stream map.
virtual void CloseStream(QuicStreamId stream_id);
......
......@@ -202,6 +202,8 @@ class TestSession : public QuicSession {
return consumed;
}
MOCK_METHOD0(OnCanCreateNewOutgoingStream, void());
void set_writev_consumes_all_data(bool val) {
writev_consumes_all_data_ = val;
}
......@@ -800,6 +802,11 @@ TEST_P(QuicSessionTestServer, SendGoAway) {
}
TEST_P(QuicSessionTestServer, DoNotSendGoAwayTwice) {
if (transport_version() == QUIC_VERSION_99) {
// TODO(b/118808809): Enable this test for version 99 when GOAWAY is
// supported.
return;
}
EXPECT_CALL(*connection_, SendControlFrame(_))
.WillOnce(Invoke(&session_, &TestSession::ClearControlFrame));
session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away.");
......@@ -808,6 +815,11 @@ TEST_P(QuicSessionTestServer, DoNotSendGoAwayTwice) {
}
TEST_P(QuicSessionTestServer, InvalidGoAway) {
if (transport_version() == QUIC_VERSION_99) {
// TODO(b/118808809): Enable this test for version 99 when GOAWAY is
// supported.
return;
}
QuicGoAwayFrame go_away(kInvalidControlFrameId, QUIC_PEER_GOING_AWAY,
session_.next_outgoing_stream_id(), "");
session_.OnGoAway(go_away);
......@@ -1224,6 +1236,18 @@ TEST_P(QuicSessionTestServer, TooManyUnfinishedStreamsCauseServerRejectStream) {
}
}
TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpenedOutgoing) {
// Verify that a draining stream (which has received a FIN but not consumed
// it) does not count against the open quota (because it is closed from the
// protocol point of view).
TestStream* stream = session_.CreateOutgoingBidirectionalStream();
QuicStreamId stream_id = stream->id();
QuicStreamFrame data1(stream_id, true, 0, QuicStringPiece("HT"));
session_.OnStreamFrame(data1);
EXPECT_CALL(session_, OnCanCreateNewOutgoingStream()).Times(1);
session_.StreamDraining(stream_id);
}
TEST_P(QuicSessionTestServer, DrainingStreamsDoNotCountAsOpened) {
// Verify that a draining stream (which has received a FIN but not consumed
// it) does not count against the open quota (because it is closed from the
......@@ -1359,6 +1383,22 @@ TEST_P(QuicSessionTestServer, ZombieStreams) {
EXPECT_EQ(stream2->id(), session_.closed_streams()->front()->id());
}
TEST_P(QuicSessionTestServer, RstStreamReceivedAfterRstStreamSent) {
TestStream* stream2 = session_.CreateOutgoingBidirectionalStream();
QuicStreamPeer::SetStreamBytesWritten(3, stream2);
EXPECT_TRUE(stream2->IsWaitingForAcks());
EXPECT_CALL(*connection_, SendControlFrame(_));
EXPECT_CALL(*connection_, OnStreamReset(stream2->id(), _));
EXPECT_CALL(session_, OnCanCreateNewOutgoingStream()).Times(0);
stream2->Reset(quic::QUIC_STREAM_CANCELLED);
QuicRstStreamFrame rst1(kInvalidControlFrameId, stream2->id(),
QUIC_ERROR_PROCESSING_STREAM, 0);
EXPECT_CALL(session_, OnCanCreateNewOutgoingStream()).Times(1);
session_.OnRstStream(rst1);
}
// Regression test of b/71548958.
TEST_P(QuicSessionTestServer, TestZombieStreams) {
session_.set_writev_consumes_all_data(true);
......
......@@ -917,4 +917,14 @@ void QuicStream::OnDeadlinePassed() {
Reset(QUIC_STREAM_TTL_EXPIRED);
}
void QuicStream::SendStopSending(uint16_t code) {
if (transport_version() != QUIC_VERSION_99) {
// If the connection is not version 99, do nothing.
// Do not QUIC_BUG or anything; the application really does not need to know
// what version the connection is in.
return;
}
session_->SendStopSending(code, id_);
}
} // namespace quic
......@@ -276,6 +276,13 @@ class QUIC_EXPORT_PRIVATE QuicStream {
StreamType type() const { return type_; }
// Creates and sends a STOP_SENDING frame. This can be called regardless of
// the version that has been negotiated. If not IETF QUIC/Version 99 then the
// method is a noop, relieving the application of the necessity of
// understanding the connection's QUIC version and knowing whether it can call
// this method or not.
void SendStopSending(uint16_t code);
protected:
// Sends as many bytes in the first |count| buffers of |iov| to the connection
// as the connection will consume. If FIN is consumed, the write side is
......
......@@ -594,6 +594,7 @@ class MockQuicSession : public QuicSession {
MOCK_METHOD3(OnStreamHeadersComplete,
void(QuicStreamId stream_id, bool fin, size_t frame_len));
MOCK_CONST_METHOD0(IsCryptoHandshakeConfirmed, bool());
MOCK_METHOD2(SendStopSending, void(uint16_t code, QuicStreamId stream_id));
using QuicSession::ActivateStream;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment