OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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_dispatcher.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/strings/string_piece.h" | |
10 #include "net/quic/crypto/crypto_handshake.h" | |
11 #include "net/quic/crypto/quic_crypto_server_config.h" | |
12 #include "net/quic/crypto/quic_random.h" | |
13 #include "net/quic/quic_crypto_stream.h" | |
14 #include "net/quic/quic_flags.h" | |
15 #include "net/quic/quic_utils.h" | |
16 #include "net/quic/test_tools/quic_test_utils.h" | |
17 #include "net/tools/epoll_server/epoll_server.h" | |
18 #include "net/tools/quic/quic_packet_writer_wrapper.h" | |
19 #include "net/tools/quic/quic_time_wait_list_manager.h" | |
20 #include "net/tools/quic/test_tools/quic_dispatcher_peer.h" | |
21 #include "net/tools/quic/test_tools/quic_test_utils.h" | |
22 #include "testing/gmock/include/gmock/gmock.h" | |
23 #include "testing/gtest/include/gtest/gtest.h" | |
24 | |
25 using base::StringPiece; | |
26 using net::EpollServer; | |
27 using net::test::ConstructEncryptedPacket; | |
28 using net::test::MockSession; | |
29 using net::test::ValueRestore; | |
30 using net::tools::test::MockConnection; | |
31 using std::make_pair; | |
32 using std::string; | |
33 using testing::DoAll; | |
34 using testing::InSequence; | |
35 using testing::Invoke; | |
36 using testing::WithoutArgs; | |
37 using testing::_; | |
38 | |
39 namespace net { | |
40 namespace tools { | |
41 namespace test { | |
42 namespace { | |
43 | |
44 class TestDispatcher : public QuicDispatcher { | |
45 public: | |
46 explicit TestDispatcher(const QuicConfig& config, | |
47 const QuicCryptoServerConfig& crypto_config, | |
48 EpollServer* eps) | |
49 : QuicDispatcher(config, | |
50 crypto_config, | |
51 QuicSupportedVersions(), | |
52 new QuicDispatcher::DefaultPacketWriterFactory(), | |
53 eps) { | |
54 } | |
55 | |
56 MOCK_METHOD3(CreateQuicSession, QuicSession*( | |
57 QuicConnectionId connection_id, | |
58 const IPEndPoint& server_address, | |
59 const IPEndPoint& client_address)); | |
60 | |
61 using QuicDispatcher::current_server_address; | |
62 using QuicDispatcher::current_client_address; | |
63 }; | |
64 | |
65 // A Connection class which unregisters the session from the dispatcher | |
66 // when sending connection close. | |
67 // It'd be slightly more realistic to do this from the Session but it would | |
68 // involve a lot more mocking. | |
69 class MockServerConnection : public MockConnection { | |
70 public: | |
71 MockServerConnection(QuicConnectionId connection_id, | |
72 QuicDispatcher* dispatcher) | |
73 : MockConnection(connection_id, true), | |
74 dispatcher_(dispatcher) {} | |
75 | |
76 void UnregisterOnConnectionClosed() { | |
77 LOG(ERROR) << "Unregistering " << connection_id(); | |
78 dispatcher_->OnConnectionClosed(connection_id(), QUIC_NO_ERROR); | |
79 } | |
80 private: | |
81 QuicDispatcher* dispatcher_; | |
82 }; | |
83 | |
84 QuicSession* CreateSession(QuicDispatcher* dispatcher, | |
85 QuicConnectionId connection_id, | |
86 const IPEndPoint& client_address, | |
87 MockSession** session) { | |
88 MockServerConnection* connection = | |
89 new MockServerConnection(connection_id, dispatcher); | |
90 *session = new MockSession(connection); | |
91 ON_CALL(*connection, SendConnectionClose(_)).WillByDefault( | |
92 WithoutArgs(Invoke( | |
93 connection, &MockServerConnection::UnregisterOnConnectionClosed))); | |
94 EXPECT_CALL(*reinterpret_cast<MockConnection*>((*session)->connection()), | |
95 ProcessUdpPacket(_, client_address, _)); | |
96 | |
97 return *session; | |
98 } | |
99 | |
100 class MockTimeWaitListManager : public QuicTimeWaitListManager { | |
101 public: | |
102 MockTimeWaitListManager(QuicPacketWriter* writer, | |
103 QuicServerSessionVisitor* visitor, | |
104 EpollServer* eps) | |
105 : QuicTimeWaitListManager(writer, visitor, eps, QuicSupportedVersions()) { | |
106 } | |
107 | |
108 MOCK_METHOD5(ProcessPacket, | |
109 void(const IPEndPoint& server_address, | |
110 const IPEndPoint& client_address, | |
111 QuicConnectionId connection_id, | |
112 QuicPacketSequenceNumber sequence_number, | |
113 const QuicEncryptedPacket& packet)); | |
114 }; | |
115 | |
116 class QuicDispatcherTest : public ::testing::Test { | |
117 public: | |
118 QuicDispatcherTest() | |
119 : crypto_config_(QuicCryptoServerConfig::TESTING, | |
120 QuicRandom::GetInstance()), | |
121 dispatcher_(config_, crypto_config_, &eps_), | |
122 time_wait_list_manager_(nullptr), | |
123 session1_(nullptr), | |
124 session2_(nullptr) { | |
125 dispatcher_.Initialize(1); | |
126 } | |
127 | |
128 ~QuicDispatcherTest() override {} | |
129 | |
130 MockConnection* connection1() { | |
131 return reinterpret_cast<MockConnection*>(session1_->connection()); | |
132 } | |
133 | |
134 MockConnection* connection2() { | |
135 return reinterpret_cast<MockConnection*>(session2_->connection()); | |
136 } | |
137 | |
138 void ProcessPacket(IPEndPoint client_address, | |
139 QuicConnectionId connection_id, | |
140 bool has_version_flag, | |
141 const string& data) { | |
142 scoped_ptr<QuicEncryptedPacket> packet(ConstructEncryptedPacket( | |
143 connection_id, has_version_flag, false, 1, data)); | |
144 data_ = string(packet->data(), packet->length()); | |
145 dispatcher_.ProcessPacket(server_address_, client_address, *packet); | |
146 } | |
147 | |
148 void ValidatePacket(const QuicEncryptedPacket& packet) { | |
149 EXPECT_EQ(data_.length(), packet.AsStringPiece().length()); | |
150 EXPECT_EQ(data_, packet.AsStringPiece()); | |
151 } | |
152 | |
153 void CreateTimeWaitListManager() { | |
154 time_wait_list_manager_ = new MockTimeWaitListManager( | |
155 QuicDispatcherPeer::GetWriter(&dispatcher_), &dispatcher_, &eps_); | |
156 // dispatcher takes the ownership of time_wait_list_manager. | |
157 QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_, | |
158 time_wait_list_manager_); | |
159 } | |
160 | |
161 EpollServer eps_; | |
162 QuicConfig config_; | |
163 QuicCryptoServerConfig crypto_config_; | |
164 IPEndPoint server_address_; | |
165 TestDispatcher dispatcher_; | |
166 MockTimeWaitListManager* time_wait_list_manager_; | |
167 MockSession* session1_; | |
168 MockSession* session2_; | |
169 string data_; | |
170 }; | |
171 | |
172 TEST_F(QuicDispatcherTest, ProcessPackets) { | |
173 IPEndPoint client_address(net::test::Loopback4(), 1); | |
174 IPAddressNumber any4; | |
175 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4)); | |
176 server_address_ = IPEndPoint(any4, 5); | |
177 | |
178 EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, client_address)) | |
179 .WillOnce(testing::Return(CreateSession( | |
180 &dispatcher_, 1, client_address, &session1_))); | |
181 ProcessPacket(client_address, 1, true, "foo"); | |
182 EXPECT_EQ(client_address, dispatcher_.current_client_address()); | |
183 EXPECT_EQ(server_address_, dispatcher_.current_server_address()); | |
184 | |
185 | |
186 EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, client_address)) | |
187 .WillOnce(testing::Return(CreateSession( | |
188 &dispatcher_, 2, client_address, &session2_))); | |
189 ProcessPacket(client_address, 2, true, "bar"); | |
190 | |
191 EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()), | |
192 ProcessUdpPacket(_, _, _)).Times(1). | |
193 WillOnce(testing::WithArgs<2>(Invoke( | |
194 this, &QuicDispatcherTest::ValidatePacket))); | |
195 ProcessPacket(client_address, 1, false, "eep"); | |
196 } | |
197 | |
198 TEST_F(QuicDispatcherTest, Shutdown) { | |
199 IPEndPoint client_address(net::test::Loopback4(), 1); | |
200 | |
201 EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address)) | |
202 .WillOnce(testing::Return(CreateSession( | |
203 &dispatcher_, 1, client_address, &session1_))); | |
204 | |
205 ProcessPacket(client_address, 1, true, "foo"); | |
206 | |
207 EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()), | |
208 SendConnectionClose(QUIC_PEER_GOING_AWAY)); | |
209 | |
210 dispatcher_.Shutdown(); | |
211 } | |
212 | |
213 TEST_F(QuicDispatcherTest, TimeWaitListManager) { | |
214 CreateTimeWaitListManager(); | |
215 | |
216 // Create a new session. | |
217 IPEndPoint client_address(net::test::Loopback4(), 1); | |
218 QuicConnectionId connection_id = 1; | |
219 EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, _, client_address)) | |
220 .WillOnce(testing::Return(CreateSession( | |
221 &dispatcher_, connection_id, client_address, &session1_))); | |
222 ProcessPacket(client_address, connection_id, true, "foo"); | |
223 | |
224 // Close the connection by sending public reset packet. | |
225 QuicPublicResetPacket packet; | |
226 packet.public_header.connection_id = connection_id; | |
227 packet.public_header.reset_flag = true; | |
228 packet.public_header.version_flag = false; | |
229 packet.rejected_sequence_number = 19191; | |
230 packet.nonce_proof = 132232; | |
231 scoped_ptr<QuicEncryptedPacket> encrypted( | |
232 QuicFramer::BuildPublicResetPacket(packet)); | |
233 EXPECT_CALL(*session1_, OnConnectionClosed(QUIC_PUBLIC_RESET, true)).Times(1) | |
234 .WillOnce(WithoutArgs(Invoke( | |
235 reinterpret_cast<MockServerConnection*>(session1_->connection()), | |
236 &MockServerConnection::UnregisterOnConnectionClosed))); | |
237 EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()), | |
238 ProcessUdpPacket(_, _, _)) | |
239 .WillOnce(Invoke( | |
240 reinterpret_cast<MockConnection*>(session1_->connection()), | |
241 &MockConnection::ReallyProcessUdpPacket)); | |
242 dispatcher_.ProcessPacket(IPEndPoint(), client_address, *encrypted); | |
243 EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); | |
244 | |
245 // Dispatcher forwards subsequent packets for this connection_id to the time | |
246 // wait list manager. | |
247 EXPECT_CALL(*time_wait_list_manager_, | |
248 ProcessPacket(_, _, connection_id, _, _)).Times(1); | |
249 ProcessPacket(client_address, connection_id, true, "foo"); | |
250 } | |
251 | |
252 TEST_F(QuicDispatcherTest, StrayPacketToTimeWaitListManager) { | |
253 CreateTimeWaitListManager(); | |
254 | |
255 IPEndPoint client_address(net::test::Loopback4(), 1); | |
256 QuicConnectionId connection_id = 1; | |
257 // Dispatcher forwards all packets for this connection_id to the time wait | |
258 // list manager. | |
259 EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0); | |
260 EXPECT_CALL(*time_wait_list_manager_, | |
261 ProcessPacket(_, _, connection_id, _, _)).Times(1); | |
262 string data = "foo"; | |
263 ProcessPacket(client_address, connection_id, false, "foo"); | |
264 } | |
265 | |
266 TEST_F(QuicDispatcherTest, ProcessPacketWithBogusPort) { | |
267 CreateTimeWaitListManager(); | |
268 | |
269 IPEndPoint client_address(net::test::Loopback4(), 0); | |
270 IPAddressNumber any4; | |
271 CHECK(net::ParseIPLiteralToNumber("0.0.0.0", &any4)); | |
272 server_address_ = IPEndPoint(any4, 5); | |
273 | |
274 EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, client_address)).Times(0); | |
275 EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _, _, _)).Times(0); | |
276 ProcessPacket(client_address, 1, true, "foo"); | |
277 EXPECT_EQ(client_address, dispatcher_.current_client_address()); | |
278 EXPECT_EQ(server_address_, dispatcher_.current_server_address()); | |
279 } | |
280 | |
281 class BlockingWriter : public QuicPacketWriterWrapper { | |
282 public: | |
283 BlockingWriter() : write_blocked_(false) {} | |
284 | |
285 bool IsWriteBlocked() const override { return write_blocked_; } | |
286 void SetWritable() override { write_blocked_ = false; } | |
287 | |
288 WriteResult WritePacket(const char* buffer, | |
289 size_t buf_len, | |
290 const IPAddressNumber& self_client_address, | |
291 const IPEndPoint& peer_client_address) override { | |
292 // It would be quite possible to actually implement this method here with | |
293 // the fake blocked status, but it would be significantly more work in | |
294 // Chromium, and since it's not called anyway, don't bother. | |
295 LOG(DFATAL) << "Not supported"; | |
296 return WriteResult(); | |
297 } | |
298 | |
299 bool write_blocked_; | |
300 }; | |
301 | |
302 class QuicDispatcherWriteBlockedListTest : public QuicDispatcherTest { | |
303 public: | |
304 void SetUp() override { | |
305 writer_ = new BlockingWriter; | |
306 QuicDispatcherPeer::SetPacketWriterFactory(&dispatcher_, | |
307 new TestWriterFactory()); | |
308 QuicDispatcherPeer::UseWriter(&dispatcher_, writer_); | |
309 | |
310 IPEndPoint client_address(net::test::Loopback4(), 1); | |
311 | |
312 EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address)) | |
313 .WillOnce(testing::Return(CreateSession( | |
314 &dispatcher_, 1, client_address, &session1_))); | |
315 ProcessPacket(client_address, 1, true, "foo"); | |
316 | |
317 EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, client_address)) | |
318 .WillOnce(testing::Return(CreateSession( | |
319 &dispatcher_, 2, client_address, &session2_))); | |
320 ProcessPacket(client_address, 2, true, "bar"); | |
321 | |
322 blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(&dispatcher_); | |
323 } | |
324 | |
325 void TearDown() override { | |
326 EXPECT_CALL(*connection1(), SendConnectionClose(QUIC_PEER_GOING_AWAY)); | |
327 EXPECT_CALL(*connection2(), SendConnectionClose(QUIC_PEER_GOING_AWAY)); | |
328 dispatcher_.Shutdown(); | |
329 } | |
330 | |
331 void SetBlocked() { | |
332 writer_->write_blocked_ = true; | |
333 } | |
334 | |
335 void BlockConnection2() { | |
336 writer_->write_blocked_ = true; | |
337 dispatcher_.OnWriteBlocked(connection2()); | |
338 } | |
339 | |
340 protected: | |
341 BlockingWriter* writer_; | |
342 QuicDispatcher::WriteBlockedList* blocked_list_; | |
343 }; | |
344 | |
345 TEST_F(QuicDispatcherWriteBlockedListTest, BasicOnCanWrite) { | |
346 // No OnCanWrite calls because no connections are blocked. | |
347 dispatcher_.OnCanWrite(); | |
348 | |
349 // Register connection 1 for events, and make sure it's notified. | |
350 SetBlocked(); | |
351 dispatcher_.OnWriteBlocked(connection1()); | |
352 EXPECT_CALL(*connection1(), OnCanWrite()); | |
353 dispatcher_.OnCanWrite(); | |
354 | |
355 // It should get only one notification. | |
356 EXPECT_CALL(*connection1(), OnCanWrite()).Times(0); | |
357 dispatcher_.OnCanWrite(); | |
358 EXPECT_FALSE(dispatcher_.HasPendingWrites()); | |
359 } | |
360 | |
361 TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteOrder) { | |
362 // Make sure we handle events in order. | |
363 InSequence s; | |
364 SetBlocked(); | |
365 dispatcher_.OnWriteBlocked(connection1()); | |
366 dispatcher_.OnWriteBlocked(connection2()); | |
367 EXPECT_CALL(*connection1(), OnCanWrite()); | |
368 EXPECT_CALL(*connection2(), OnCanWrite()); | |
369 dispatcher_.OnCanWrite(); | |
370 | |
371 // Check the other ordering. | |
372 SetBlocked(); | |
373 dispatcher_.OnWriteBlocked(connection2()); | |
374 dispatcher_.OnWriteBlocked(connection1()); | |
375 EXPECT_CALL(*connection2(), OnCanWrite()); | |
376 EXPECT_CALL(*connection1(), OnCanWrite()); | |
377 dispatcher_.OnCanWrite(); | |
378 } | |
379 | |
380 TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteRemove) { | |
381 // Add and remove one connction. | |
382 SetBlocked(); | |
383 dispatcher_.OnWriteBlocked(connection1()); | |
384 blocked_list_->erase(connection1()); | |
385 EXPECT_CALL(*connection1(), OnCanWrite()).Times(0); | |
386 dispatcher_.OnCanWrite(); | |
387 | |
388 // Add and remove one connction and make sure it doesn't affect others. | |
389 SetBlocked(); | |
390 dispatcher_.OnWriteBlocked(connection1()); | |
391 dispatcher_.OnWriteBlocked(connection2()); | |
392 blocked_list_->erase(connection1()); | |
393 EXPECT_CALL(*connection2(), OnCanWrite()); | |
394 dispatcher_.OnCanWrite(); | |
395 | |
396 // Add it, remove it, and add it back and make sure things are OK. | |
397 SetBlocked(); | |
398 dispatcher_.OnWriteBlocked(connection1()); | |
399 blocked_list_->erase(connection1()); | |
400 dispatcher_.OnWriteBlocked(connection1()); | |
401 EXPECT_CALL(*connection1(), OnCanWrite()).Times(1); | |
402 dispatcher_.OnCanWrite(); | |
403 } | |
404 | |
405 TEST_F(QuicDispatcherWriteBlockedListTest, DoubleAdd) { | |
406 // Make sure a double add does not necessitate a double remove. | |
407 SetBlocked(); | |
408 dispatcher_.OnWriteBlocked(connection1()); | |
409 dispatcher_.OnWriteBlocked(connection1()); | |
410 blocked_list_->erase(connection1()); | |
411 EXPECT_CALL(*connection1(), OnCanWrite()).Times(0); | |
412 dispatcher_.OnCanWrite(); | |
413 | |
414 // Make sure a double add does not result in two OnCanWrite calls. | |
415 SetBlocked(); | |
416 dispatcher_.OnWriteBlocked(connection1()); | |
417 dispatcher_.OnWriteBlocked(connection1()); | |
418 EXPECT_CALL(*connection1(), OnCanWrite()).Times(1); | |
419 dispatcher_.OnCanWrite(); | |
420 } | |
421 | |
422 TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteHandleBlock) { | |
423 // Finally make sure if we write block on a write call, we stop calling. | |
424 InSequence s; | |
425 SetBlocked(); | |
426 dispatcher_.OnWriteBlocked(connection1()); | |
427 dispatcher_.OnWriteBlocked(connection2()); | |
428 EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce( | |
429 Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked)); | |
430 EXPECT_CALL(*connection2(), OnCanWrite()).Times(0); | |
431 dispatcher_.OnCanWrite(); | |
432 | |
433 // And we'll resume where we left off when we get another call. | |
434 EXPECT_CALL(*connection2(), OnCanWrite()); | |
435 dispatcher_.OnCanWrite(); | |
436 } | |
437 | |
438 TEST_F(QuicDispatcherWriteBlockedListTest, LimitedWrites) { | |
439 // Make sure we call both writers. The first will register for more writing | |
440 // but should not be immediately called due to limits. | |
441 InSequence s; | |
442 SetBlocked(); | |
443 dispatcher_.OnWriteBlocked(connection1()); | |
444 dispatcher_.OnWriteBlocked(connection2()); | |
445 EXPECT_CALL(*connection1(), OnCanWrite()); | |
446 EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce( | |
447 Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection2)); | |
448 dispatcher_.OnCanWrite(); | |
449 EXPECT_TRUE(dispatcher_.HasPendingWrites()); | |
450 | |
451 // Now call OnCanWrite again, and connection1 should get its second chance | |
452 EXPECT_CALL(*connection2(), OnCanWrite()); | |
453 dispatcher_.OnCanWrite(); | |
454 EXPECT_FALSE(dispatcher_.HasPendingWrites()); | |
455 } | |
456 | |
457 TEST_F(QuicDispatcherWriteBlockedListTest, TestWriteLimits) { | |
458 // Finally make sure if we write block on a write call, we stop calling. | |
459 InSequence s; | |
460 SetBlocked(); | |
461 dispatcher_.OnWriteBlocked(connection1()); | |
462 dispatcher_.OnWriteBlocked(connection2()); | |
463 EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce( | |
464 Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked)); | |
465 EXPECT_CALL(*connection2(), OnCanWrite()).Times(0); | |
466 dispatcher_.OnCanWrite(); | |
467 EXPECT_TRUE(dispatcher_.HasPendingWrites()); | |
468 | |
469 // And we'll resume where we left off when we get another call. | |
470 EXPECT_CALL(*connection2(), OnCanWrite()); | |
471 dispatcher_.OnCanWrite(); | |
472 EXPECT_FALSE(dispatcher_.HasPendingWrites()); | |
473 } | |
474 | |
475 } // namespace | |
476 } // namespace test | |
477 } // namespace tools | |
478 } // namespace net | |
OLD | NEW |