| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/quic/quic_server_session_base.h" | |
| 6 | |
| 7 #include <cstdint> | |
| 8 #include <memory> | |
| 9 | |
| 10 #include "base/macros.h" | |
| 11 #include "net/quic/crypto/quic_crypto_server_config.h" | |
| 12 #include "net/quic/crypto/quic_random.h" | |
| 13 #include "net/quic/proto/cached_network_parameters.pb.h" | |
| 14 #include "net/quic/quic_connection.h" | |
| 15 #include "net/quic/quic_crypto_server_stream.h" | |
| 16 #include "net/quic/quic_utils.h" | |
| 17 #include "net/quic/test_tools/crypto_test_utils.h" | |
| 18 #include "net/quic/test_tools/quic_config_peer.h" | |
| 19 #include "net/quic/test_tools/quic_connection_peer.h" | |
| 20 #include "net/quic/test_tools/quic_sent_packet_manager_peer.h" | |
| 21 #include "net/quic/test_tools/quic_session_peer.h" | |
| 22 #include "net/quic/test_tools/quic_spdy_session_peer.h" | |
| 23 #include "net/quic/test_tools/quic_spdy_stream_peer.h" | |
| 24 #include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h" | |
| 25 #include "net/quic/test_tools/quic_test_utils.h" | |
| 26 #include "net/test/gtest_util.h" | |
| 27 #include "net/tools/quic/quic_simple_server_stream.h" | |
| 28 #include "net/tools/quic/test_tools/mock_quic_server_session_visitor.h" | |
| 29 #include "testing/gmock/include/gmock/gmock.h" | |
| 30 #include "testing/gtest/include/gtest/gtest.h" | |
| 31 | |
| 32 using net::test::CryptoTestUtils; | |
| 33 using net::test::MockQuicConnection; | |
| 34 using net::test::MockQuicConnectionHelper; | |
| 35 using net::test::QuicConfigPeer; | |
| 36 using net::test::QuicConnectionPeer; | |
| 37 using net::test::QuicSpdyStreamPeer; | |
| 38 using net::test::QuicSentPacketManagerPeer; | |
| 39 using net::test::QuicSessionPeer; | |
| 40 using net::test::QuicSpdySessionPeer; | |
| 41 using net::test::QuicSustainedBandwidthRecorderPeer; | |
| 42 using net::test::SupportedVersions; | |
| 43 using net::test::ValueRestore; | |
| 44 using net::test::kClientDataStreamId1; | |
| 45 using net::test::kClientDataStreamId2; | |
| 46 using net::test::kClientDataStreamId3; | |
| 47 using net::test::kInitialSessionFlowControlWindowForTest; | |
| 48 using net::test::kInitialStreamFlowControlWindowForTest; | |
| 49 using std::string; | |
| 50 using testing::StrictMock; | |
| 51 using testing::_; | |
| 52 | |
| 53 namespace net { | |
| 54 namespace test { | |
| 55 | |
| 56 class QuicServerSessionBasePeer { | |
| 57 public: | |
| 58 static ReliableQuicStream* GetOrCreateDynamicStream(QuicServerSessionBase* s, | |
| 59 QuicStreamId id) { | |
| 60 return s->GetOrCreateDynamicStream(id); | |
| 61 } | |
| 62 static void SetCryptoStream(QuicServerSessionBase* s, | |
| 63 QuicCryptoServerStream* crypto_stream) { | |
| 64 s->crypto_stream_.reset(crypto_stream); | |
| 65 s->static_streams()[kCryptoStreamId] = crypto_stream; | |
| 66 } | |
| 67 static bool IsBandwidthResumptionEnabled(QuicServerSessionBase* s) { | |
| 68 return s->bandwidth_resumption_enabled_; | |
| 69 } | |
| 70 }; | |
| 71 | |
| 72 namespace { | |
| 73 | |
| 74 class TestServerSession : public QuicServerSessionBase { | |
| 75 public: | |
| 76 TestServerSession(const QuicConfig& config, | |
| 77 QuicConnection* connection, | |
| 78 QuicServerSessionBase::Visitor* visitor, | |
| 79 QuicServerSessionBase::Helper* helper, | |
| 80 const QuicCryptoServerConfig* crypto_config, | |
| 81 QuicCompressedCertsCache* compressed_certs_cache) | |
| 82 : QuicServerSessionBase(config, | |
| 83 connection, | |
| 84 visitor, | |
| 85 helper, | |
| 86 crypto_config, | |
| 87 compressed_certs_cache) {} | |
| 88 | |
| 89 ~TestServerSession() override{}; | |
| 90 | |
| 91 protected: | |
| 92 QuicSpdyStream* CreateIncomingDynamicStream(QuicStreamId id) override { | |
| 93 if (!ShouldCreateIncomingDynamicStream(id)) { | |
| 94 return nullptr; | |
| 95 } | |
| 96 QuicSpdyStream* stream = new QuicSimpleServerStream(id, this); | |
| 97 ActivateStream(stream); | |
| 98 return stream; | |
| 99 } | |
| 100 | |
| 101 QuicSpdyStream* CreateOutgoingDynamicStream(SpdyPriority priority) override { | |
| 102 if (!ShouldCreateOutgoingDynamicStream()) { | |
| 103 return nullptr; | |
| 104 } | |
| 105 | |
| 106 QuicSpdyStream* stream = | |
| 107 new QuicSimpleServerStream(GetNextOutgoingStreamId(), this); | |
| 108 stream->SetPriority(priority); | |
| 109 ActivateStream(stream); | |
| 110 return stream; | |
| 111 } | |
| 112 | |
| 113 QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( | |
| 114 const QuicCryptoServerConfig* crypto_config, | |
| 115 QuicCompressedCertsCache* compressed_certs_cache) override { | |
| 116 return new QuicCryptoServerStream( | |
| 117 crypto_config, compressed_certs_cache, | |
| 118 FLAGS_enable_quic_stateless_reject_support, this); | |
| 119 } | |
| 120 }; | |
| 121 | |
| 122 const size_t kMaxStreamsForTest = 10; | |
| 123 | |
| 124 class QuicServerSessionBaseTest : public ::testing::TestWithParam<QuicVersion> { | |
| 125 protected: | |
| 126 QuicServerSessionBaseTest() | |
| 127 : crypto_config_(QuicCryptoServerConfig::TESTING, | |
| 128 QuicRandom::GetInstance(), | |
| 129 CryptoTestUtils::ProofSourceForTesting()), | |
| 130 compressed_certs_cache_( | |
| 131 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { | |
| 132 FLAGS_quic_always_log_bugs_for_tests = true; | |
| 133 config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest); | |
| 134 config_.SetMaxIncomingDynamicStreamsToSend(kMaxStreamsForTest); | |
| 135 QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(&config_, | |
| 136 kMaxStreamsForTest); | |
| 137 config_.SetInitialStreamFlowControlWindowToSend( | |
| 138 kInitialStreamFlowControlWindowForTest); | |
| 139 config_.SetInitialSessionFlowControlWindowToSend( | |
| 140 kInitialSessionFlowControlWindowForTest); | |
| 141 | |
| 142 connection_ = new StrictMock<MockQuicConnection>( | |
| 143 &helper_, &alarm_factory_, Perspective::IS_SERVER, | |
| 144 SupportedVersions(GetParam())); | |
| 145 session_.reset(new TestServerSession(config_, connection_, &owner_, | |
| 146 &session_helper_, &crypto_config_, | |
| 147 &compressed_certs_cache_)); | |
| 148 MockClock clock; | |
| 149 handshake_message_.reset(crypto_config_.AddDefaultConfig( | |
| 150 QuicRandom::GetInstance(), &clock, | |
| 151 QuicCryptoServerConfig::ConfigOptions())); | |
| 152 session_->Initialize(); | |
| 153 visitor_ = QuicConnectionPeer::GetVisitor(connection_); | |
| 154 } | |
| 155 | |
| 156 StrictMock<MockQuicServerSessionVisitor> owner_; | |
| 157 StrictMock<MockQuicServerSessionHelper> session_helper_; | |
| 158 MockQuicConnectionHelper helper_; | |
| 159 MockAlarmFactory alarm_factory_; | |
| 160 StrictMock<MockQuicConnection>* connection_; | |
| 161 QuicConfig config_; | |
| 162 QuicCryptoServerConfig crypto_config_; | |
| 163 QuicCompressedCertsCache compressed_certs_cache_; | |
| 164 std::unique_ptr<TestServerSession> session_; | |
| 165 std::unique_ptr<CryptoHandshakeMessage> handshake_message_; | |
| 166 QuicConnectionVisitorInterface* visitor_; | |
| 167 }; | |
| 168 | |
| 169 // Compares CachedNetworkParameters. | |
| 170 MATCHER_P(EqualsProto, network_params, "") { | |
| 171 CachedNetworkParameters reference(network_params); | |
| 172 return (arg->bandwidth_estimate_bytes_per_second() == | |
| 173 reference.bandwidth_estimate_bytes_per_second() && | |
| 174 arg->bandwidth_estimate_bytes_per_second() == | |
| 175 reference.bandwidth_estimate_bytes_per_second() && | |
| 176 arg->max_bandwidth_estimate_bytes_per_second() == | |
| 177 reference.max_bandwidth_estimate_bytes_per_second() && | |
| 178 arg->max_bandwidth_timestamp_seconds() == | |
| 179 reference.max_bandwidth_timestamp_seconds() && | |
| 180 arg->min_rtt_ms() == reference.min_rtt_ms() && | |
| 181 arg->previous_connection_state() == | |
| 182 reference.previous_connection_state()); | |
| 183 } | |
| 184 | |
| 185 INSTANTIATE_TEST_CASE_P(Tests, | |
| 186 QuicServerSessionBaseTest, | |
| 187 ::testing::ValuesIn(QuicSupportedVersions())); | |
| 188 | |
| 189 TEST_P(QuicServerSessionBaseTest, ServerPushDisabledByDefault) { | |
| 190 // Without the client explicitly sending kSPSH, server push will be disabled | |
| 191 // at the server. | |
| 192 EXPECT_FALSE( | |
| 193 session_->config()->HasReceivedConnectionOptions() && | |
| 194 ContainsQuicTag(session_->config()->ReceivedConnectionOptions(), kSPSH)); | |
| 195 session_->OnConfigNegotiated(); | |
| 196 EXPECT_FALSE(session_->server_push_enabled()); | |
| 197 } | |
| 198 | |
| 199 TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { | |
| 200 // Open a stream, then reset it. | |
| 201 // Send two bytes of payload to open it. | |
| 202 QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT")); | |
| 203 session_->OnStreamFrame(data1); | |
| 204 EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); | |
| 205 | |
| 206 // Send a reset (and expect the peer to send a RST in response). | |
| 207 QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, | |
| 208 0); | |
| 209 EXPECT_CALL(*connection_, | |
| 210 SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); | |
| 211 visitor_->OnRstStream(rst1); | |
| 212 EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); | |
| 213 | |
| 214 // Send the same two bytes of payload in a new packet. | |
| 215 visitor_->OnStreamFrame(data1); | |
| 216 | |
| 217 // The stream should not be re-opened. | |
| 218 EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); | |
| 219 EXPECT_TRUE(connection_->connected()); | |
| 220 } | |
| 221 | |
| 222 TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) { | |
| 223 // Send a reset (and expect the peer to send a RST in response). | |
| 224 QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, | |
| 225 0); | |
| 226 EXPECT_CALL(*connection_, | |
| 227 SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); | |
| 228 visitor_->OnRstStream(rst1); | |
| 229 EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); | |
| 230 | |
| 231 // Send two bytes of payload. | |
| 232 QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT")); | |
| 233 visitor_->OnStreamFrame(data1); | |
| 234 | |
| 235 // The stream should never be opened, now that the reset is received. | |
| 236 EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); | |
| 237 EXPECT_TRUE(connection_->connected()); | |
| 238 } | |
| 239 | |
| 240 TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { | |
| 241 // Send (empty) compressed headers followed by two bytes of data. | |
| 242 QuicStreamFrame frame1(kClientDataStreamId1, false, 0, | |
| 243 StringPiece("\1\0\0\0\0\0\0\0HT")); | |
| 244 QuicStreamFrame frame2(kClientDataStreamId2, false, 0, | |
| 245 StringPiece("\2\0\0\0\0\0\0\0HT")); | |
| 246 visitor_->OnStreamFrame(frame1); | |
| 247 visitor_->OnStreamFrame(frame2); | |
| 248 EXPECT_EQ(2u, session_->GetNumOpenIncomingStreams()); | |
| 249 | |
| 250 // Send a reset (and expect the peer to send a RST in response). | |
| 251 QuicRstStreamFrame rst(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, 0); | |
| 252 EXPECT_CALL(*connection_, | |
| 253 SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); | |
| 254 visitor_->OnRstStream(rst); | |
| 255 | |
| 256 // If we were tracking, we'd probably want to reject this because it's data | |
| 257 // past the reset point of stream 3. As it's a closed stream we just drop the | |
| 258 // data on the floor, but accept the packet because it has data for stream 5. | |
| 259 QuicStreamFrame frame3(kClientDataStreamId1, false, 2, StringPiece("TP")); | |
| 260 QuicStreamFrame frame4(kClientDataStreamId2, false, 2, StringPiece("TP")); | |
| 261 visitor_->OnStreamFrame(frame3); | |
| 262 visitor_->OnStreamFrame(frame4); | |
| 263 // The stream should never be opened, now that the reset is received. | |
| 264 EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); | |
| 265 EXPECT_TRUE(connection_->connected()); | |
| 266 } | |
| 267 | |
| 268 TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) { | |
| 269 // Test that the server refuses if a client attempts to open too many data | |
| 270 // streams. The server accepts slightly more than the negotiated stream limit | |
| 271 // to deal with rare cases where a client FIN/RST is lost. | |
| 272 | |
| 273 if (GetParam() <= QUIC_VERSION_34) { | |
| 274 EXPECT_EQ(kMaxStreamsForTest, session_->max_open_incoming_streams()); | |
| 275 } | |
| 276 | |
| 277 // The slightly increased stream limit is set during config negotiation. It | |
| 278 // is either an increase of 10 over negotiated limit, or a fixed percentage | |
| 279 // scaling, whichever is larger. Test both before continuing. | |
| 280 session_->OnConfigNegotiated(); | |
| 281 EXPECT_LT(kMaxStreamsMultiplier * kMaxStreamsForTest, | |
| 282 kMaxStreamsForTest + kMaxStreamsMinimumIncrement); | |
| 283 EXPECT_EQ(kMaxStreamsForTest + kMaxStreamsMinimumIncrement, | |
| 284 session_->max_open_incoming_streams()); | |
| 285 EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); | |
| 286 QuicStreamId stream_id = kClientDataStreamId1; | |
| 287 // Open the max configured number of streams, should be no problem. | |
| 288 for (size_t i = 0; i < kMaxStreamsForTest; ++i) { | |
| 289 EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( | |
| 290 session_.get(), stream_id)); | |
| 291 stream_id += 2; | |
| 292 } | |
| 293 | |
| 294 // Open more streams: server should accept slightly more than the limit. | |
| 295 for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) { | |
| 296 EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( | |
| 297 session_.get(), stream_id)); | |
| 298 stream_id += 2; | |
| 299 } | |
| 300 | |
| 301 // Now violate the server's internal stream limit. | |
| 302 stream_id += 2; | |
| 303 EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); | |
| 304 EXPECT_CALL(*connection_, SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0)); | |
| 305 // Even if the connection remains open, the stream creation should fail. | |
| 306 EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( | |
| 307 session_.get(), stream_id)); | |
| 308 } | |
| 309 | |
| 310 TEST_P(QuicServerSessionBaseTest, MaxAvailableStreams) { | |
| 311 // Test that the server closes the connection if a client makes too many data | |
| 312 // streams available. The server accepts slightly more than the negotiated | |
| 313 // stream limit to deal with rare cases where a client FIN/RST is lost. | |
| 314 | |
| 315 if (GetParam() <= QUIC_VERSION_34) { | |
| 316 // The slightly increased stream limit is set during config negotiation. | |
| 317 EXPECT_EQ(kMaxStreamsForTest, session_->max_open_incoming_streams()); | |
| 318 } | |
| 319 session_->OnConfigNegotiated(); | |
| 320 const size_t kAvailableStreamLimit = session_->MaxAvailableStreams(); | |
| 321 EXPECT_EQ( | |
| 322 session_->max_open_incoming_streams() * kMaxAvailableStreamsMultiplier, | |
| 323 session_->MaxAvailableStreams()); | |
| 324 // The protocol specification requires that there can be at least 10 times | |
| 325 // as many available streams as the connection's maximum open streams. | |
| 326 EXPECT_LE(10 * kMaxStreamsForTest, kAvailableStreamLimit); | |
| 327 | |
| 328 EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); | |
| 329 EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( | |
| 330 session_.get(), kClientDataStreamId1)); | |
| 331 | |
| 332 // Establish available streams up to the server's limit. | |
| 333 const int kLimitingStreamId = | |
| 334 kClientDataStreamId1 + (kAvailableStreamLimit)*2 + 2; | |
| 335 EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( | |
| 336 session_.get(), kLimitingStreamId)); | |
| 337 | |
| 338 // A further available stream will result in connection close. | |
| 339 EXPECT_CALL(*connection_, | |
| 340 CloseConnection(QUIC_TOO_MANY_AVAILABLE_STREAMS, _, _)); | |
| 341 // This forces stream kLimitingStreamId + 2 to become available, which | |
| 342 // violates the quota. | |
| 343 EXPECT_FALSE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( | |
| 344 session_.get(), kLimitingStreamId + 4)); | |
| 345 } | |
| 346 | |
| 347 TEST_P(QuicServerSessionBaseTest, EnableServerPushThroughConnectionOption) { | |
| 348 // Assume server received server push connection option. | |
| 349 QuicTagVector copt; | |
| 350 copt.push_back(kSPSH); | |
| 351 QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); | |
| 352 session_->OnConfigNegotiated(); | |
| 353 EXPECT_TRUE(session_->server_push_enabled()); | |
| 354 } | |
| 355 | |
| 356 TEST_P(QuicServerSessionBaseTest, GetEvenIncomingError) { | |
| 357 // Incoming streams on the server session must be odd. | |
| 358 EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _)); | |
| 359 EXPECT_EQ(nullptr, QuicServerSessionBasePeer::GetOrCreateDynamicStream( | |
| 360 session_.get(), 4)); | |
| 361 } | |
| 362 | |
| 363 TEST_P(QuicServerSessionBaseTest, GetStreamDisconnected) { | |
| 364 // Don't create new streams if the connection is disconnected. | |
| 365 QuicConnectionPeer::TearDownLocalConnectionState(connection_); | |
| 366 EXPECT_DFATAL( | |
| 367 QuicServerSessionBasePeer::GetOrCreateDynamicStream(session_.get(), 5), | |
| 368 "ShouldCreateIncomingDynamicStream called when disconnected"); | |
| 369 } | |
| 370 | |
| 371 class MockQuicCryptoServerStream : public QuicCryptoServerStream { | |
| 372 public: | |
| 373 explicit MockQuicCryptoServerStream( | |
| 374 const QuicCryptoServerConfig* crypto_config, | |
| 375 QuicCompressedCertsCache* compressed_certs_cache, | |
| 376 QuicServerSessionBase* session) | |
| 377 : QuicCryptoServerStream(crypto_config, | |
| 378 compressed_certs_cache, | |
| 379 FLAGS_enable_quic_stateless_reject_support, | |
| 380 session) {} | |
| 381 ~MockQuicCryptoServerStream() override {} | |
| 382 | |
| 383 MOCK_METHOD1(SendServerConfigUpdate, | |
| 384 void(const CachedNetworkParameters* cached_network_parameters)); | |
| 385 | |
| 386 void set_encryption_established(bool has_established) { | |
| 387 encryption_established_ = has_established; | |
| 388 } | |
| 389 | |
| 390 private: | |
| 391 DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStream); | |
| 392 }; | |
| 393 | |
| 394 TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { | |
| 395 // Test that bandwidth estimate updates are sent to the client, only when | |
| 396 // bandwidth resumption is enabled, the bandwidth estimate has changed | |
| 397 // sufficiently, enough time has passed, | |
| 398 // and we don't have any other data to write. | |
| 399 | |
| 400 // Client has sent kBWRE connection option to trigger bandwidth resumption. | |
| 401 // Disable this flag because if connection uses multipath sent packet manager, | |
| 402 // static_cast here does not work. | |
| 403 QuicTagVector copt; | |
| 404 copt.push_back(kBWRE); | |
| 405 QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); | |
| 406 session_->OnConfigNegotiated(); | |
| 407 EXPECT_TRUE( | |
| 408 QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); | |
| 409 | |
| 410 int32_t bandwidth_estimate_kbytes_per_second = 123; | |
| 411 int32_t max_bandwidth_estimate_kbytes_per_second = 134; | |
| 412 int32_t max_bandwidth_estimate_timestamp = 1122334455; | |
| 413 const string serving_region = "not a real region"; | |
| 414 session_->set_serving_region(serving_region); | |
| 415 | |
| 416 MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream( | |
| 417 &crypto_config_, &compressed_certs_cache_, session_.get()); | |
| 418 QuicServerSessionBasePeer::SetCryptoStream(session_.get(), crypto_stream); | |
| 419 | |
| 420 // Set some initial bandwidth values. | |
| 421 QuicSentPacketManager* sent_packet_manager = | |
| 422 QuicConnectionPeer::GetSentPacketManager(session_->connection(), | |
| 423 kDefaultPathId); | |
| 424 QuicSustainedBandwidthRecorder& bandwidth_recorder = | |
| 425 QuicSentPacketManagerPeer::GetBandwidthRecorder(sent_packet_manager); | |
| 426 // Seed an rtt measurement equal to the initial default rtt. | |
| 427 RttStats* rtt_stats = | |
| 428 const_cast<RttStats*>(sent_packet_manager->GetRttStats()); | |
| 429 rtt_stats->UpdateRtt( | |
| 430 QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us()), | |
| 431 QuicTime::Delta::Zero(), QuicTime::Zero()); | |
| 432 QuicSustainedBandwidthRecorderPeer::SetBandwidthEstimate( | |
| 433 &bandwidth_recorder, bandwidth_estimate_kbytes_per_second); | |
| 434 QuicSustainedBandwidthRecorderPeer::SetMaxBandwidthEstimate( | |
| 435 &bandwidth_recorder, max_bandwidth_estimate_kbytes_per_second, | |
| 436 max_bandwidth_estimate_timestamp); | |
| 437 // Queue up some pending data. | |
| 438 session_->MarkConnectionLevelWriteBlocked(kCryptoStreamId); | |
| 439 EXPECT_TRUE(session_->HasDataToWrite()); | |
| 440 | |
| 441 // There will be no update sent yet - not enough time has passed. | |
| 442 QuicTime now = QuicTime::Zero(); | |
| 443 session_->OnCongestionWindowChange(now); | |
| 444 | |
| 445 // Bandwidth estimate has now changed sufficiently but not enough time has | |
| 446 // passed to send a Server Config Update. | |
| 447 bandwidth_estimate_kbytes_per_second = | |
| 448 bandwidth_estimate_kbytes_per_second * 1.6; | |
| 449 session_->OnCongestionWindowChange(now); | |
| 450 | |
| 451 // Bandwidth estimate has now changed sufficiently and enough time has passed, | |
| 452 // but not enough packets have been sent. | |
| 453 int64_t srtt_ms = | |
| 454 sent_packet_manager->GetRttStats()->smoothed_rtt().ToMilliseconds(); | |
| 455 now = now + QuicTime::Delta::FromMilliseconds( | |
| 456 kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms); | |
| 457 session_->OnCongestionWindowChange(now); | |
| 458 | |
| 459 // The connection no longer has pending data to be written. | |
| 460 session_->OnCanWrite(); | |
| 461 EXPECT_FALSE(session_->HasDataToWrite()); | |
| 462 session_->OnCongestionWindowChange(now); | |
| 463 | |
| 464 // Bandwidth estimate has now changed sufficiently, enough time has passed, | |
| 465 // and enough packets have been sent. | |
| 466 QuicConnectionPeer::SetPacketNumberOfLastSentPacket( | |
| 467 session_->connection(), kMinPacketsBetweenServerConfigUpdates); | |
| 468 | |
| 469 // Verify that the proto has exactly the values we expect. | |
| 470 CachedNetworkParameters expected_network_params; | |
| 471 expected_network_params.set_bandwidth_estimate_bytes_per_second( | |
| 472 bandwidth_recorder.BandwidthEstimate().ToBytesPerSecond()); | |
| 473 expected_network_params.set_max_bandwidth_estimate_bytes_per_second( | |
| 474 bandwidth_recorder.MaxBandwidthEstimate().ToBytesPerSecond()); | |
| 475 expected_network_params.set_max_bandwidth_timestamp_seconds( | |
| 476 bandwidth_recorder.MaxBandwidthTimestamp()); | |
| 477 expected_network_params.set_min_rtt_ms(session_->connection() | |
| 478 ->sent_packet_manager() | |
| 479 .GetRttStats() | |
| 480 ->min_rtt() | |
| 481 .ToMilliseconds()); | |
| 482 expected_network_params.set_previous_connection_state( | |
| 483 CachedNetworkParameters::CONGESTION_AVOIDANCE); | |
| 484 expected_network_params.set_timestamp( | |
| 485 session_->connection()->clock()->WallNow().ToUNIXSeconds()); | |
| 486 expected_network_params.set_serving_region(serving_region); | |
| 487 | |
| 488 EXPECT_CALL(*crypto_stream, | |
| 489 SendServerConfigUpdate(EqualsProto(expected_network_params))) | |
| 490 .Times(1); | |
| 491 EXPECT_CALL(*connection_, OnSendConnectionState(_)).Times(1); | |
| 492 session_->OnCongestionWindowChange(now); | |
| 493 } | |
| 494 | |
| 495 TEST_P(QuicServerSessionBaseTest, BandwidthResumptionExperiment) { | |
| 496 // Test that if a client provides a CachedNetworkParameters with the same | |
| 497 // serving region as the current server, and which was made within an hour of | |
| 498 // now, that this data is passed down to the send algorithm. | |
| 499 | |
| 500 // Client has sent kBWRE connection option to trigger bandwidth resumption. | |
| 501 QuicTagVector copt; | |
| 502 copt.push_back(kBWRE); | |
| 503 QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); | |
| 504 | |
| 505 const string kTestServingRegion = "a serving region"; | |
| 506 session_->set_serving_region(kTestServingRegion); | |
| 507 | |
| 508 // Set the time to be one hour + one second from the 0 baseline. | |
| 509 connection_->AdvanceTime( | |
| 510 QuicTime::Delta::FromSeconds(kNumSecondsPerHour + 1)); | |
| 511 | |
| 512 QuicCryptoServerStream* crypto_stream = static_cast<QuicCryptoServerStream*>( | |
| 513 QuicSessionPeer::GetCryptoStream(session_.get())); | |
| 514 | |
| 515 // No effect if no CachedNetworkParameters provided. | |
| 516 EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0); | |
| 517 session_->OnConfigNegotiated(); | |
| 518 | |
| 519 // No effect if CachedNetworkParameters provided, but different serving | |
| 520 // regions. | |
| 521 CachedNetworkParameters cached_network_params; | |
| 522 cached_network_params.set_bandwidth_estimate_bytes_per_second(1); | |
| 523 cached_network_params.set_serving_region("different serving region"); | |
| 524 crypto_stream->SetPreviousCachedNetworkParams(cached_network_params); | |
| 525 EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0); | |
| 526 session_->OnConfigNegotiated(); | |
| 527 | |
| 528 // Same serving region, but timestamp is too old, should have no effect. | |
| 529 cached_network_params.set_serving_region(kTestServingRegion); | |
| 530 cached_network_params.set_timestamp(0); | |
| 531 crypto_stream->SetPreviousCachedNetworkParams(cached_network_params); | |
| 532 EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0); | |
| 533 session_->OnConfigNegotiated(); | |
| 534 | |
| 535 // Same serving region, and timestamp is recent: estimate is stored. | |
| 536 cached_network_params.set_timestamp( | |
| 537 connection_->clock()->WallNow().ToUNIXSeconds()); | |
| 538 crypto_stream->SetPreviousCachedNetworkParams(cached_network_params); | |
| 539 EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(1); | |
| 540 session_->OnConfigNegotiated(); | |
| 541 } | |
| 542 | |
| 543 TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) { | |
| 544 EXPECT_FALSE( | |
| 545 QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); | |
| 546 | |
| 547 // Client has sent kBWMX connection option to trigger bandwidth resumption. | |
| 548 QuicTagVector copt; | |
| 549 copt.push_back(kBWMX); | |
| 550 QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); | |
| 551 session_->OnConfigNegotiated(); | |
| 552 EXPECT_TRUE( | |
| 553 QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); | |
| 554 } | |
| 555 | |
| 556 TEST_P(QuicServerSessionBaseTest, NoBandwidthResumptionByDefault) { | |
| 557 EXPECT_FALSE( | |
| 558 QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); | |
| 559 session_->OnConfigNegotiated(); | |
| 560 EXPECT_FALSE( | |
| 561 QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); | |
| 562 } | |
| 563 | |
| 564 } // namespace | |
| 565 } // namespace test | |
| 566 } // namespace net | |
| OLD | NEW |