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/tools/quic/quic_server_session.h" | |
6 | |
7 #include "net/quic/crypto/cached_network_parameters.h" | |
8 #include "net/quic/crypto/quic_crypto_server_config.h" | |
9 #include "net/quic/crypto/quic_random.h" | |
10 #include "net/quic/quic_connection.h" | |
11 #include "net/quic/quic_crypto_server_stream.h" | |
12 #include "net/quic/quic_flags.h" | |
13 #include "net/quic/quic_utils.h" | |
14 #include "net/quic/test_tools/quic_config_peer.h" | |
15 #include "net/quic/test_tools/quic_connection_peer.h" | |
16 #include "net/quic/test_tools/quic_data_stream_peer.h" | |
17 #include "net/quic/test_tools/quic_sent_packet_manager_peer.h" | |
18 #include "net/quic/test_tools/quic_session_peer.h" | |
19 #include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h" | |
20 #include "net/quic/test_tools/quic_test_utils.h" | |
21 #include "net/tools/quic/quic_spdy_server_stream.h" | |
22 #include "net/tools/quic/test_tools/quic_test_utils.h" | |
23 #include "testing/gmock/include/gmock/gmock.h" | |
24 #include "testing/gtest/include/gtest/gtest.h" | |
25 | |
26 using __gnu_cxx::vector; | |
27 using net::test::MockConnection; | |
28 using net::test::QuicConfigPeer; | |
29 using net::test::QuicConnectionPeer; | |
30 using net::test::QuicDataStreamPeer; | |
31 using net::test::QuicSentPacketManagerPeer; | |
32 using net::test::QuicSessionPeer; | |
33 using net::test::QuicSustainedBandwidthRecorderPeer; | |
34 using net::test::SupportedVersions; | |
35 using net::test::ValueRestore; | |
36 using net::test::kClientDataStreamId1; | |
37 using net::test::kClientDataStreamId2; | |
38 using net::test::kClientDataStreamId3; | |
39 using net::test::kClientDataStreamId4; | |
40 using std::string; | |
41 using testing::StrictMock; | |
42 using testing::_; | |
43 | |
44 namespace net { | |
45 namespace tools { | |
46 namespace test { | |
47 | |
48 class QuicServerSessionPeer { | |
49 public: | |
50 static QuicDataStream* GetIncomingDataStream( | |
51 QuicServerSession* s, QuicStreamId id) { | |
52 return s->GetIncomingDataStream(id); | |
53 } | |
54 static QuicDataStream* GetDataStream(QuicServerSession* s, QuicStreamId id) { | |
55 return s->GetDataStream(id); | |
56 } | |
57 static void SetCryptoStream(QuicServerSession* s, | |
58 QuicCryptoServerStream* crypto_stream) { | |
59 s->crypto_stream_.reset(crypto_stream); | |
60 } | |
61 }; | |
62 | |
63 namespace { | |
64 | |
65 const size_t kMaxStreamsForTest = 10; | |
66 | |
67 class QuicServerSessionTest : public ::testing::TestWithParam<QuicVersion> { | |
68 protected: | |
69 QuicServerSessionTest() | |
70 : crypto_config_(QuicCryptoServerConfig::TESTING, | |
71 QuicRandom::GetInstance()) { | |
72 config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, | |
73 kMaxStreamsForTest); | |
74 config_.SetInitialStreamFlowControlWindowToSend( | |
75 kInitialStreamFlowControlWindowForTest); | |
76 config_.SetInitialSessionFlowControlWindowToSend( | |
77 kInitialSessionFlowControlWindowForTest); | |
78 | |
79 connection_ = | |
80 new StrictMock<MockConnection>(true, SupportedVersions(GetParam())); | |
81 session_.reset(new QuicServerSession(config_, connection_, &owner_)); | |
82 MockClock clock; | |
83 handshake_message_.reset(crypto_config_.AddDefaultConfig( | |
84 QuicRandom::GetInstance(), &clock, | |
85 QuicCryptoServerConfig::ConfigOptions())); | |
86 session_->InitializeSession(crypto_config_); | |
87 visitor_ = QuicConnectionPeer::GetVisitor(connection_); | |
88 } | |
89 | |
90 QuicVersion version() const { return connection_->version(); } | |
91 | |
92 StrictMock<MockQuicServerSessionVisitor> owner_; | |
93 StrictMock<MockConnection>* connection_; | |
94 QuicConfig config_; | |
95 QuicCryptoServerConfig crypto_config_; | |
96 scoped_ptr<QuicServerSession> session_; | |
97 scoped_ptr<CryptoHandshakeMessage> handshake_message_; | |
98 QuicConnectionVisitorInterface* visitor_; | |
99 }; | |
100 | |
101 // Compares CachedNetworkParameters. | |
102 MATCHER_P(EqualsProto, network_params, "") { | |
103 CachedNetworkParameters reference(network_params); | |
104 return (arg->bandwidth_estimate_bytes_per_second() == | |
105 reference.bandwidth_estimate_bytes_per_second() && | |
106 arg->bandwidth_estimate_bytes_per_second() == | |
107 reference.bandwidth_estimate_bytes_per_second() && | |
108 arg->max_bandwidth_estimate_bytes_per_second() == | |
109 reference.max_bandwidth_estimate_bytes_per_second() && | |
110 arg->max_bandwidth_timestamp_seconds() == | |
111 reference.max_bandwidth_timestamp_seconds() && | |
112 arg->min_rtt_ms() == reference.min_rtt_ms() && | |
113 arg->previous_connection_state() == | |
114 reference.previous_connection_state()); | |
115 } | |
116 | |
117 INSTANTIATE_TEST_CASE_P(Tests, QuicServerSessionTest, | |
118 ::testing::ValuesIn(QuicSupportedVersions())); | |
119 | |
120 TEST_P(QuicServerSessionTest, CloseStreamDueToReset) { | |
121 // Open a stream, then reset it. | |
122 // Send two bytes of payload to open it. | |
123 QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT")); | |
124 vector<QuicStreamFrame> frames; | |
125 frames.push_back(data1); | |
126 session_->OnStreamFrames(frames); | |
127 EXPECT_EQ(1u, session_->GetNumOpenStreams()); | |
128 | |
129 // Send a reset (and expect the peer to send a RST in response). | |
130 QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_STREAM_NO_ERROR, 0); | |
131 EXPECT_CALL(*connection_, | |
132 SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); | |
133 visitor_->OnRstStream(rst1); | |
134 EXPECT_EQ(0u, session_->GetNumOpenStreams()); | |
135 | |
136 // Send the same two bytes of payload in a new packet. | |
137 visitor_->OnStreamFrames(frames); | |
138 | |
139 // The stream should not be re-opened. | |
140 EXPECT_EQ(0u, session_->GetNumOpenStreams()); | |
141 EXPECT_TRUE(connection_->connected()); | |
142 } | |
143 | |
144 TEST_P(QuicServerSessionTest, NeverOpenStreamDueToReset) { | |
145 // Send a reset (and expect the peer to send a RST in response). | |
146 QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_STREAM_NO_ERROR, 0); | |
147 EXPECT_CALL(*connection_, | |
148 SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); | |
149 visitor_->OnRstStream(rst1); | |
150 EXPECT_EQ(0u, session_->GetNumOpenStreams()); | |
151 | |
152 // Send two bytes of payload. | |
153 QuicStreamFrame data1(kClientDataStreamId1, false, 0, MakeIOVector("HT")); | |
154 vector<QuicStreamFrame> frames; | |
155 frames.push_back(data1); | |
156 visitor_->OnStreamFrames(frames); | |
157 | |
158 // The stream should never be opened, now that the reset is received. | |
159 EXPECT_EQ(0u, session_->GetNumOpenStreams()); | |
160 EXPECT_TRUE(connection_->connected()); | |
161 } | |
162 | |
163 TEST_P(QuicServerSessionTest, AcceptClosedStream) { | |
164 vector<QuicStreamFrame> frames; | |
165 // Send (empty) compressed headers followed by two bytes of data. | |
166 frames.push_back(QuicStreamFrame(kClientDataStreamId1, false, 0, | |
167 MakeIOVector("\1\0\0\0\0\0\0\0HT"))); | |
168 frames.push_back(QuicStreamFrame(kClientDataStreamId2, false, 0, | |
169 MakeIOVector("\2\0\0\0\0\0\0\0HT"))); | |
170 visitor_->OnStreamFrames(frames); | |
171 EXPECT_EQ(2u, session_->GetNumOpenStreams()); | |
172 | |
173 // Send a reset (and expect the peer to send a RST in response). | |
174 QuicRstStreamFrame rst(kClientDataStreamId1, QUIC_STREAM_NO_ERROR, 0); | |
175 EXPECT_CALL(*connection_, | |
176 SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); | |
177 visitor_->OnRstStream(rst); | |
178 | |
179 // If we were tracking, we'd probably want to reject this because it's data | |
180 // past the reset point of stream 3. As it's a closed stream we just drop the | |
181 // data on the floor, but accept the packet because it has data for stream 5. | |
182 frames.clear(); | |
183 frames.push_back( | |
184 QuicStreamFrame(kClientDataStreamId1, false, 2, MakeIOVector("TP"))); | |
185 frames.push_back( | |
186 QuicStreamFrame(kClientDataStreamId2, false, 2, MakeIOVector("TP"))); | |
187 visitor_->OnStreamFrames(frames); | |
188 // The stream should never be opened, now that the reset is received. | |
189 EXPECT_EQ(1u, session_->GetNumOpenStreams()); | |
190 EXPECT_TRUE(connection_->connected()); | |
191 } | |
192 | |
193 TEST_P(QuicServerSessionTest, MaxOpenStreams) { | |
194 // Test that the server closes the connection if a client attempts to open too | |
195 // many data streams. The server accepts slightly more than the negotiated | |
196 // stream limit to deal with rare cases where a client FIN/RST is lost. | |
197 | |
198 // The slightly increased stream limit is set during config negotiation. It | |
199 // should be either an increase of 10 over negotiated limit, or a fixed | |
200 // percentage scaling, whichever is larger. Test both before continuing. | |
201 EXPECT_EQ(kMaxStreamsForTest, session_->get_max_open_streams()); | |
202 session_->OnConfigNegotiated(); | |
203 EXPECT_LT(kMaxStreamsMultiplier * kMaxStreamsForTest, | |
204 kMaxStreamsForTest + kMaxStreamsMinimumIncrement); | |
205 EXPECT_EQ(kMaxStreamsForTest + kMaxStreamsMinimumIncrement, | |
206 session_->get_max_open_streams()); | |
207 EXPECT_EQ(0u, session_->GetNumOpenStreams()); | |
208 QuicStreamId stream_id = kClientDataStreamId1; | |
209 // Open the max configured number of streams, should be no problem. | |
210 for (size_t i = 0; i < kMaxStreamsForTest; ++i) { | |
211 EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream(session_.get(), | |
212 stream_id)); | |
213 stream_id += 2; | |
214 } | |
215 | |
216 // Open more streams: server should accept slightly more than the limit. | |
217 for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) { | |
218 EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream(session_.get(), | |
219 stream_id)); | |
220 stream_id += 2; | |
221 } | |
222 | |
223 // Now violate the server's internal stream limit. | |
224 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS)); | |
225 stream_id += 2; | |
226 EXPECT_FALSE( | |
227 QuicServerSessionPeer::GetIncomingDataStream(session_.get(), stream_id)); | |
228 } | |
229 | |
230 TEST_P(QuicServerSessionTest, MaxOpenStreamsImplicit) { | |
231 // Test that the server closes the connection if a client attempts to open too | |
232 // many data streams implicitly. The server accepts slightly more than the | |
233 // negotiated stream limit to deal with rare cases where a client FIN/RST is | |
234 // lost. | |
235 | |
236 // The slightly increased stream limit is set during config negotiation. | |
237 EXPECT_EQ(kMaxStreamsForTest, session_->get_max_open_streams()); | |
238 session_->OnConfigNegotiated(); | |
239 EXPECT_LT(kMaxStreamsMultiplier * kMaxStreamsForTest, | |
240 kMaxStreamsForTest + kMaxStreamsMinimumIncrement); | |
241 EXPECT_EQ(kMaxStreamsForTest + kMaxStreamsMinimumIncrement, | |
242 session_->get_max_open_streams()); | |
243 | |
244 EXPECT_EQ(0u, session_->GetNumOpenStreams()); | |
245 EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream( | |
246 session_.get(), kClientDataStreamId1)); | |
247 // Implicitly open streams up to the server's limit. | |
248 const int kActualMaxStreams = | |
249 kMaxStreamsForTest + kMaxStreamsMinimumIncrement; | |
250 const int kMaxValidStreamId = | |
251 kClientDataStreamId1 + (kActualMaxStreams - 1) * 2; | |
252 EXPECT_TRUE(QuicServerSessionPeer::GetIncomingDataStream( | |
253 session_.get(), kMaxValidStreamId)); | |
254 | |
255 // Opening a further stream will result in connection close. | |
256 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS)); | |
257 EXPECT_FALSE(QuicServerSessionPeer::GetIncomingDataStream( | |
258 session_.get(), kMaxValidStreamId + 2)); | |
259 } | |
260 | |
261 TEST_P(QuicServerSessionTest, GetEvenIncomingError) { | |
262 // Incoming streams on the server session must be odd. | |
263 EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID)); | |
264 EXPECT_EQ(nullptr, | |
265 QuicServerSessionPeer::GetIncomingDataStream(session_.get(), 4)); | |
266 } | |
267 | |
268 TEST_P(QuicServerSessionTest, SetFecProtectionFromConfig) { | |
269 ValueRestore<bool> old_flag(&FLAGS_enable_quic_fec, true); | |
270 | |
271 // Set received config to have FEC connection option. | |
272 QuicTagVector copt; | |
273 copt.push_back(kFHDR); | |
274 QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); | |
275 session_->OnConfigNegotiated(); | |
276 | |
277 // Verify that headers stream is always protected and data streams are | |
278 // optionally protected. | |
279 EXPECT_EQ(FEC_PROTECT_ALWAYS, | |
280 QuicSessionPeer::GetHeadersStream(session_.get())->fec_policy()); | |
281 QuicDataStream* stream = QuicServerSessionPeer::GetIncomingDataStream( | |
282 session_.get(), kClientDataStreamId1); | |
283 ASSERT_TRUE(stream); | |
284 EXPECT_EQ(FEC_PROTECT_OPTIONAL, stream->fec_policy()); | |
285 } | |
286 | |
287 class MockQuicCryptoServerStream : public QuicCryptoServerStream { | |
288 public: | |
289 explicit MockQuicCryptoServerStream( | |
290 const QuicCryptoServerConfig& crypto_config, QuicSession* session) | |
291 : QuicCryptoServerStream(crypto_config, session) {} | |
292 ~MockQuicCryptoServerStream() override {} | |
293 | |
294 MOCK_METHOD1(SendServerConfigUpdate, | |
295 void(const CachedNetworkParameters* cached_network_parameters)); | |
296 | |
297 private: | |
298 DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStream); | |
299 }; | |
300 | |
301 TEST_P(QuicServerSessionTest, BandwidthEstimates) { | |
302 // Test that bandwidth estimate updates are sent to the client, only after the | |
303 // bandwidth estimate has changes sufficiently, and enough time has passed, | |
304 // and we don't have any other data to write. | |
305 | |
306 int32 bandwidth_estimate_kbytes_per_second = 123; | |
307 int32 max_bandwidth_estimate_kbytes_per_second = 134; | |
308 int32 max_bandwidth_estimate_timestamp = 1122334455; | |
309 const string serving_region = "not a real region"; | |
310 session_->set_serving_region(serving_region); | |
311 | |
312 MockQuicCryptoServerStream* crypto_stream = | |
313 new MockQuicCryptoServerStream(crypto_config_, session_.get()); | |
314 QuicServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream); | |
315 | |
316 // Set some initial bandwidth values. | |
317 QuicSentPacketManager* sent_packet_manager = | |
318 QuicConnectionPeer::GetSentPacketManager(session_->connection()); | |
319 QuicSustainedBandwidthRecorder& bandwidth_recorder = | |
320 QuicSentPacketManagerPeer::GetBandwidthRecorder(sent_packet_manager); | |
321 // Seed an rtt measurement equal to the initial default rtt. | |
322 RttStats* rtt_stats = | |
323 QuicSentPacketManagerPeer::GetRttStats(sent_packet_manager); | |
324 rtt_stats->UpdateRtt(QuicTime::Delta::FromMicroseconds( | |
325 rtt_stats->initial_rtt_us()), QuicTime::Delta::Zero(), QuicTime::Zero()); | |
326 QuicSustainedBandwidthRecorderPeer::SetBandwidthEstimate( | |
327 &bandwidth_recorder, bandwidth_estimate_kbytes_per_second); | |
328 QuicSustainedBandwidthRecorderPeer::SetMaxBandwidthEstimate( | |
329 &bandwidth_recorder, max_bandwidth_estimate_kbytes_per_second, | |
330 max_bandwidth_estimate_timestamp); | |
331 // Queue up some pending data. | |
332 session_->MarkWriteBlocked(kCryptoStreamId, | |
333 QuicWriteBlockedList::kHighestPriority); | |
334 EXPECT_TRUE(session_->HasDataToWrite()); | |
335 | |
336 // There will be no update sent yet - not enough time has passed. | |
337 QuicTime now = QuicTime::Zero(); | |
338 session_->OnCongestionWindowChange(now); | |
339 | |
340 // Bandwidth estimate has now changed sufficiently but not enough time has | |
341 // passed to send a Server Config Update. | |
342 bandwidth_estimate_kbytes_per_second = | |
343 bandwidth_estimate_kbytes_per_second * 1.6; | |
344 session_->OnCongestionWindowChange(now); | |
345 | |
346 // Bandwidth estimate has now changed sufficiently and enough time has passed, | |
347 // but not enough packets have been sent. | |
348 int64 srtt_ms = | |
349 sent_packet_manager->GetRttStats()->smoothed_rtt().ToMilliseconds(); | |
350 now = now.Add(QuicTime::Delta::FromMilliseconds( | |
351 kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms)); | |
352 session_->OnCongestionWindowChange(now); | |
353 | |
354 // The connection no longer has pending data to be written. | |
355 session_->OnCanWrite(); | |
356 EXPECT_FALSE(session_->HasDataToWrite()); | |
357 session_->OnCongestionWindowChange(now); | |
358 | |
359 // Bandwidth estimate has now changed sufficiently, enough time has passed, | |
360 // and enough packets have been sent. | |
361 QuicConnectionPeer::SetSequenceNumberOfLastSentPacket( | |
362 session_->connection(), kMinPacketsBetweenServerConfigUpdates); | |
363 | |
364 // Verify that the proto has exactly the values we expect. | |
365 CachedNetworkParameters expected_network_params; | |
366 expected_network_params.set_bandwidth_estimate_bytes_per_second( | |
367 bandwidth_recorder.BandwidthEstimate().ToBytesPerSecond()); | |
368 expected_network_params.set_max_bandwidth_estimate_bytes_per_second( | |
369 bandwidth_recorder.MaxBandwidthEstimate().ToBytesPerSecond()); | |
370 expected_network_params.set_max_bandwidth_timestamp_seconds( | |
371 bandwidth_recorder.MaxBandwidthTimestamp()); | |
372 expected_network_params.set_min_rtt_ms(session_->connection() | |
373 ->sent_packet_manager() | |
374 .GetRttStats() | |
375 ->min_rtt() | |
376 .ToMilliseconds()); | |
377 expected_network_params.set_previous_connection_state( | |
378 CachedNetworkParameters::CONGESTION_AVOIDANCE); | |
379 expected_network_params.set_timestamp( | |
380 session_->connection()->clock()->WallNow().ToUNIXSeconds()); | |
381 expected_network_params.set_serving_region(serving_region); | |
382 | |
383 EXPECT_CALL(*crypto_stream, | |
384 SendServerConfigUpdate(EqualsProto(expected_network_params))) | |
385 .Times(1); | |
386 session_->OnCongestionWindowChange(now); | |
387 } | |
388 | |
389 TEST_P(QuicServerSessionTest, BandwidthResumptionExperiment) { | |
390 ValueRestore<bool> old_flag( | |
391 &FLAGS_quic_enable_bandwidth_resumption_experiment, true); | |
392 | |
393 // Test that if a client provides a CachedNetworkParameters with the same | |
394 // serving region as the current server, that this data is passed down to the | |
395 // send algorithm. | |
396 | |
397 // Client has sent kBWRE connection option to trigger bandwidth resumption. | |
398 QuicTagVector copt; | |
399 copt.push_back(kBWRE); | |
400 QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); | |
401 | |
402 const string kTestServingRegion = "a serving region"; | |
403 session_->set_serving_region(kTestServingRegion); | |
404 | |
405 QuicCryptoServerStream* crypto_stream = | |
406 static_cast<QuicCryptoServerStream*>( | |
407 QuicSessionPeer::GetCryptoStream(session_.get())); | |
408 | |
409 // No effect if no CachedNetworkParameters provided. | |
410 EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(0); | |
411 session_->OnConfigNegotiated(); | |
412 | |
413 // No effect if CachedNetworkParameters provided, but different serving | |
414 // regions. | |
415 CachedNetworkParameters cached_network_params; | |
416 cached_network_params.set_bandwidth_estimate_bytes_per_second(1); | |
417 cached_network_params.set_serving_region("different serving region"); | |
418 crypto_stream->set_previous_cached_network_params(cached_network_params); | |
419 EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(0); | |
420 session_->OnConfigNegotiated(); | |
421 | |
422 // Same serving region results in CachedNetworkParameters being stored. | |
423 cached_network_params.set_serving_region(kTestServingRegion); | |
424 crypto_stream->set_previous_cached_network_params(cached_network_params); | |
425 EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(1); | |
426 session_->OnConfigNegotiated(); | |
427 } | |
428 | |
429 } // namespace | |
430 } // namespace test | |
431 } // namespace tools | |
432 } // namespace net | |
OLD | NEW |