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.
5 #include "net/tools/quic/quic_dispatcher.h"
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_utils.h"
15 #include "net/quic/test_tools/quic_test_utils.h"
16 #include "net/tools/epoll_server/epoll_server.h"
17 #include "net/tools/quic/quic_packet_writer_wrapper.h"
18 #include "net/tools/quic/quic_time_wait_list_manager.h"
19 #include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
20 #include "net/tools/quic/test_tools/quic_test_utils.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 using base::StringPiece
;
25 using net::EpollServer
;
26 using net::test::MockSession
;
27 using net::tools::test::MockConnection
;
31 using testing::Invoke
;
32 using testing::InSequence
;
33 using testing::Return
;
34 using testing::WithoutArgs
;
41 class TestDispatcher
: public QuicDispatcher
{
43 explicit TestDispatcher(const QuicConfig
& config
,
44 const QuicCryptoServerConfig
& crypto_config
,
46 : QuicDispatcher(config
, crypto_config
, QuicSupportedVersions(), eps
) {
49 MOCK_METHOD3(CreateQuicSession
, QuicSession
*(
51 const IPEndPoint
& server_address
,
52 const IPEndPoint
& client_address
));
53 using QuicDispatcher::write_blocked_list
;
56 // A Connection class which unregisters the session from the dispatcher
57 // when sending connection close.
58 // It'd be slightly more realistic to do this from the Session but it would
59 // involve a lot more mocking.
60 class MockServerConnection
: public MockConnection
{
62 MockServerConnection(QuicGuid guid
,
63 QuicDispatcher
* dispatcher
)
64 : MockConnection(guid
, true),
65 dispatcher_(dispatcher
) {}
67 void UnregisterOnConnectionClosed() {
68 LOG(ERROR
) << "Unregistering " << guid();
69 dispatcher_
->OnConnectionClosed(guid(), QUIC_NO_ERROR
);
72 QuicDispatcher
* dispatcher_
;
75 QuicSession
* CreateSession(QuicDispatcher
* dispatcher
,
77 const IPEndPoint
& addr
,
78 MockSession
** session
) {
79 MockServerConnection
* connection
= new MockServerConnection(guid
, dispatcher
);
80 *session
= new MockSession(connection
);
81 ON_CALL(*connection
, SendConnectionClose(_
)).WillByDefault(
83 connection
, &MockServerConnection::UnregisterOnConnectionClosed
)));
84 EXPECT_CALL(*reinterpret_cast<MockConnection
*>((*session
)->connection()),
85 ProcessUdpPacket(_
, addr
, _
));
90 class QuicDispatcherTest
: public ::testing::Test
{
93 : crypto_config_(QuicCryptoServerConfig::TESTING
,
94 QuicRandom::GetInstance()),
95 dispatcher_(config_
, crypto_config_
, &eps_
),
98 dispatcher_
.Initialize(1);
101 virtual ~QuicDispatcherTest() {}
103 MockConnection
* connection1() {
104 return reinterpret_cast<MockConnection
*>(session1_
->connection());
107 MockConnection
* connection2() {
108 return reinterpret_cast<MockConnection
*>(session2_
->connection());
111 QuicEncryptedPacket
* ConstructEncryptedPacket(
115 QuicPacketSequenceNumber sequence_number
,
116 const string
& data
) {
117 QuicPacketHeader header
;
118 header
.public_header
.guid
= guid
;
119 header
.public_header
.guid_length
= PACKET_8BYTE_GUID
;
120 header
.public_header
.version_flag
= version_flag
;
121 header
.public_header
.reset_flag
= reset_flag
;
122 header
.public_header
.sequence_number_length
= PACKET_6BYTE_SEQUENCE_NUMBER
;
123 header
.packet_sequence_number
= sequence_number
;
124 header
.entropy_flag
= false;
125 header
.entropy_hash
= 0;
126 header
.fec_flag
= false;
127 header
.is_in_fec_group
= NOT_IN_FEC_GROUP
;
128 header
.fec_group
= 0;
129 QuicStreamFrame
stream_frame(1, false, 0, MakeIOVector(data
));
130 QuicFrame
frame(&stream_frame
);
132 frames
.push_back(frame
);
133 QuicFramer
framer(QuicSupportedVersions(), QuicTime::Zero(), false);
134 scoped_ptr
<QuicPacket
> packet(
135 framer
.BuildUnsizedDataPacket(header
, frames
).packet
);
136 EXPECT_TRUE(packet
!= NULL
);
137 QuicEncryptedPacket
* encrypted
= framer
.EncryptPacket(ENCRYPTION_NONE
,
140 EXPECT_TRUE(encrypted
!= NULL
);
141 data_
= string(encrypted
->data(), encrypted
->length());
145 void ProcessPacket(IPEndPoint addr
,
147 bool has_version_flag
,
148 const string
& data
) {
149 scoped_ptr
<QuicEncryptedPacket
> packet(
150 ConstructEncryptedPacket(guid
, has_version_flag
, false, 1, data
));
151 dispatcher_
.ProcessPacket(IPEndPoint(), addr
, *packet
.get());
154 void ValidatePacket(const QuicEncryptedPacket
& packet
) {
155 EXPECT_EQ(data_
.length(), packet
.AsStringPiece().length());
156 EXPECT_EQ(data_
, packet
.AsStringPiece());
161 QuicCryptoServerConfig crypto_config_
;
162 TestDispatcher dispatcher_
;
163 MockSession
* session1_
;
164 MockSession
* session2_
;
168 TEST_F(QuicDispatcherTest
, ProcessPackets
) {
169 IPEndPoint
addr(net::test::Loopback4(), 1);
171 EXPECT_CALL(dispatcher_
, CreateQuicSession(1, _
, addr
))
172 .WillOnce(testing::Return(CreateSession(
173 &dispatcher_
, 1, addr
, &session1_
)));
174 ProcessPacket(addr
, 1, true, "foo");
176 EXPECT_CALL(dispatcher_
, CreateQuicSession(2, _
, addr
))
177 .WillOnce(testing::Return(CreateSession(
178 &dispatcher_
, 2, addr
, &session2_
)));
179 ProcessPacket(addr
, 2, true, "bar");
181 EXPECT_CALL(*reinterpret_cast<MockConnection
*>(session1_
->connection()),
182 ProcessUdpPacket(_
, _
, _
)).Times(1).
183 WillOnce(testing::WithArgs
<2>(Invoke(
184 this, &QuicDispatcherTest::ValidatePacket
)));
185 ProcessPacket(addr
, 1, false, "eep");
188 TEST_F(QuicDispatcherTest
, Shutdown
) {
189 IPEndPoint
addr(net::test::Loopback4(), 1);
191 EXPECT_CALL(dispatcher_
, CreateQuicSession(_
, _
, addr
))
192 .WillOnce(testing::Return(CreateSession(
193 &dispatcher_
, 1, addr
, &session1_
)));
195 ProcessPacket(addr
, 1, true, "foo");
197 EXPECT_CALL(*reinterpret_cast<MockConnection
*>(session1_
->connection()),
198 SendConnectionClose(QUIC_PEER_GOING_AWAY
));
200 dispatcher_
.Shutdown();
203 class MockTimeWaitListManager
: public QuicTimeWaitListManager
{
205 MockTimeWaitListManager(QuicPacketWriter
* writer
,
206 QuicServerSessionVisitor
* visitor
,
208 : QuicTimeWaitListManager(writer
, visitor
, eps
, QuicSupportedVersions()) {
211 MOCK_METHOD4(ProcessPacket
, void(const IPEndPoint
& server_address
,
212 const IPEndPoint
& client_address
,
214 QuicPacketSequenceNumber sequence_number
));
217 TEST_F(QuicDispatcherTest
, TimeWaitListManager
) {
218 MockTimeWaitListManager
* time_wait_list_manager
=
219 new MockTimeWaitListManager(
220 QuicDispatcherPeer::GetWriter(&dispatcher_
), &dispatcher_
, &eps_
);
221 // dispatcher takes the ownership of time_wait_list_manager.
222 QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_
,
223 time_wait_list_manager
);
224 // Create a new session.
225 IPEndPoint
addr(net::test::Loopback4(), 1);
227 EXPECT_CALL(dispatcher_
, CreateQuicSession(guid
, _
, addr
))
228 .WillOnce(testing::Return(CreateSession(
229 &dispatcher_
, guid
, addr
, &session1_
)));
230 ProcessPacket(addr
, guid
, true, "foo");
232 // Close the connection by sending public reset packet.
233 QuicPublicResetPacket packet
;
234 packet
.public_header
.guid
= guid
;
235 packet
.public_header
.reset_flag
= true;
236 packet
.public_header
.version_flag
= false;
237 packet
.rejected_sequence_number
= 19191;
238 packet
.nonce_proof
= 132232;
239 scoped_ptr
<QuicEncryptedPacket
> encrypted(
240 QuicFramer::BuildPublicResetPacket(packet
));
241 EXPECT_CALL(*session1_
, OnConnectionClosed(QUIC_PUBLIC_RESET
, true)).Times(1)
242 .WillOnce(WithoutArgs(Invoke(
243 reinterpret_cast<MockServerConnection
*>(session1_
->connection()),
244 &MockServerConnection::UnregisterOnConnectionClosed
)));
245 EXPECT_CALL(*reinterpret_cast<MockConnection
*>(session1_
->connection()),
246 ProcessUdpPacket(_
, _
, _
))
248 reinterpret_cast<MockConnection
*>(session1_
->connection()),
249 &MockConnection::ReallyProcessUdpPacket
));
250 dispatcher_
.ProcessPacket(IPEndPoint(), addr
, *encrypted
);
251 EXPECT_TRUE(time_wait_list_manager
->IsGuidInTimeWait(guid
));
253 // Dispatcher forwards subsequent packets for this guid to the time wait list
255 EXPECT_CALL(*time_wait_list_manager
, ProcessPacket(_
, _
, guid
, _
)).Times(1);
256 ProcessPacket(addr
, guid
, true, "foo");
259 TEST_F(QuicDispatcherTest
, StrayPacketToTimeWaitListManager
) {
260 MockTimeWaitListManager
* time_wait_list_manager
=
261 new MockTimeWaitListManager(
262 QuicDispatcherPeer::GetWriter(&dispatcher_
), &dispatcher_
, &eps_
);
263 // dispatcher takes the ownership of time_wait_list_manager.
264 QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_
,
265 time_wait_list_manager
);
267 IPEndPoint
addr(net::test::Loopback4(), 1);
269 // Dispatcher forwards all packets for this guid to the time wait list
271 EXPECT_CALL(dispatcher_
, CreateQuicSession(_
, _
, _
)).Times(0);
272 EXPECT_CALL(*time_wait_list_manager
, ProcessPacket(_
, _
, guid
, _
)).Times(1);
274 ProcessPacket(addr
, guid
, false, "foo");
277 class BlockingWriter
: public QuicPacketWriterWrapper
{
279 BlockingWriter() : write_blocked_(false) {}
281 virtual bool IsWriteBlocked() const OVERRIDE
{ return write_blocked_
; }
282 virtual void SetWritable() OVERRIDE
{ write_blocked_
= false; }
284 virtual WriteResult
WritePacket(
287 const IPAddressNumber
& self_address
,
288 const IPEndPoint
& peer_address
) OVERRIDE
{
289 if (write_blocked_
) {
290 return WriteResult(WRITE_STATUS_BLOCKED
, EAGAIN
);
292 return QuicPacketWriterWrapper::WritePacket(
293 buffer
, buf_len
, self_address
, peer_address
);
300 class QuicDispatcherWriteBlockedListTest
: public QuicDispatcherTest
{
302 virtual void SetUp() {
303 writer_
= new BlockingWriter
;
304 QuicDispatcherPeer::UseWriter(&dispatcher_
, writer_
);
306 IPEndPoint
addr(net::test::Loopback4(), 1);
308 EXPECT_CALL(dispatcher_
, CreateQuicSession(_
, _
, addr
))
309 .WillOnce(testing::Return(CreateSession(
310 &dispatcher_
, 1, addr
, &session1_
)));
311 ProcessPacket(addr
, 1, true, "foo");
313 EXPECT_CALL(dispatcher_
, CreateQuicSession(_
, _
, addr
))
314 .WillOnce(testing::Return(CreateSession(
315 &dispatcher_
, 2, addr
, &session2_
)));
316 ProcessPacket(addr
, 2, true, "bar");
318 blocked_list_
= dispatcher_
.write_blocked_list();
321 virtual void TearDown() {
322 EXPECT_CALL(*connection1(), SendConnectionClose(QUIC_PEER_GOING_AWAY
));
323 EXPECT_CALL(*connection2(), SendConnectionClose(QUIC_PEER_GOING_AWAY
));
324 dispatcher_
.Shutdown();
328 writer_
->write_blocked_
= true;
331 void BlockConnection2() {
332 writer_
->write_blocked_
= true;
333 dispatcher_
.OnWriteBlocked(connection2());
337 BlockingWriter
* writer_
;
338 QuicDispatcher::WriteBlockedList
* blocked_list_
;
341 TEST_F(QuicDispatcherWriteBlockedListTest
, BasicOnCanWrite
) {
342 // No OnCanWrite calls because no connections are blocked.
343 dispatcher_
.OnCanWrite();
345 // Register connection 1 for events, and make sure it's notified.
347 dispatcher_
.OnWriteBlocked(connection1());
348 EXPECT_CALL(*connection1(), OnCanWrite());
349 dispatcher_
.OnCanWrite();
351 // It should get only one notification.
352 EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
353 dispatcher_
.OnCanWrite();
354 EXPECT_FALSE(dispatcher_
.HasPendingWrites());
357 TEST_F(QuicDispatcherWriteBlockedListTest
, OnCanWriteOrder
) {
358 // Make sure we handle events in order.
361 dispatcher_
.OnWriteBlocked(connection1());
362 dispatcher_
.OnWriteBlocked(connection2());
363 EXPECT_CALL(*connection1(), OnCanWrite());
364 EXPECT_CALL(*connection2(), OnCanWrite());
365 dispatcher_
.OnCanWrite();
367 // Check the other ordering.
369 dispatcher_
.OnWriteBlocked(connection2());
370 dispatcher_
.OnWriteBlocked(connection1());
371 EXPECT_CALL(*connection2(), OnCanWrite());
372 EXPECT_CALL(*connection1(), OnCanWrite());
373 dispatcher_
.OnCanWrite();
376 TEST_F(QuicDispatcherWriteBlockedListTest
, OnCanWriteRemove
) {
377 // Add and remove one connction.
379 dispatcher_
.OnWriteBlocked(connection1());
380 blocked_list_
->erase(connection1());
381 EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
382 dispatcher_
.OnCanWrite();
384 // Add and remove one connction and make sure it doesn't affect others.
386 dispatcher_
.OnWriteBlocked(connection1());
387 dispatcher_
.OnWriteBlocked(connection2());
388 blocked_list_
->erase(connection1());
389 EXPECT_CALL(*connection2(), OnCanWrite());
390 dispatcher_
.OnCanWrite();
392 // Add it, remove it, and add it back and make sure things are OK.
394 dispatcher_
.OnWriteBlocked(connection1());
395 blocked_list_
->erase(connection1());
396 dispatcher_
.OnWriteBlocked(connection1());
397 EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
398 dispatcher_
.OnCanWrite();
401 TEST_F(QuicDispatcherWriteBlockedListTest
, DoubleAdd
) {
402 // Make sure a double add does not necessitate a double remove.
404 dispatcher_
.OnWriteBlocked(connection1());
405 dispatcher_
.OnWriteBlocked(connection1());
406 blocked_list_
->erase(connection1());
407 EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
408 dispatcher_
.OnCanWrite();
410 // Make sure a double add does not result in two OnCanWrite calls.
412 dispatcher_
.OnWriteBlocked(connection1());
413 dispatcher_
.OnWriteBlocked(connection1());
414 EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
415 dispatcher_
.OnCanWrite();
418 TEST_F(QuicDispatcherWriteBlockedListTest
, OnCanWriteHandleBlock
) {
419 // Finally make sure if we write block on a write call, we stop calling.
422 dispatcher_
.OnWriteBlocked(connection1());
423 dispatcher_
.OnWriteBlocked(connection2());
424 EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(
425 Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked
));
426 EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
427 dispatcher_
.OnCanWrite();
429 // And we'll resume where we left off when we get another call.
430 EXPECT_CALL(*connection2(), OnCanWrite());
431 dispatcher_
.OnCanWrite();
434 TEST_F(QuicDispatcherWriteBlockedListTest
, LimitedWrites
) {
435 // Make sure we call both writers. The first will register for more writing
436 // but should not be immediately called due to limits.
439 dispatcher_
.OnWriteBlocked(connection1());
440 dispatcher_
.OnWriteBlocked(connection2());
441 EXPECT_CALL(*connection1(), OnCanWrite());
442 EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce(
443 Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection2
));
444 dispatcher_
.OnCanWrite();
445 EXPECT_TRUE(dispatcher_
.HasPendingWrites());
447 // Now call OnCanWrite again, and connection1 should get its second chance
448 EXPECT_CALL(*connection2(), OnCanWrite());
449 dispatcher_
.OnCanWrite();
450 EXPECT_FALSE(dispatcher_
.HasPendingWrites());
453 TEST_F(QuicDispatcherWriteBlockedListTest
, TestWriteLimits
) {
454 // Finally make sure if we write block on a write call, we stop calling.
457 dispatcher_
.OnWriteBlocked(connection1());
458 dispatcher_
.OnWriteBlocked(connection2());
459 EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(
460 Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked
));
461 EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
462 dispatcher_
.OnCanWrite();
463 EXPECT_TRUE(dispatcher_
.HasPendingWrites());
465 // And we'll resume where we left off when we get another call.
466 EXPECT_CALL(*connection2(), OnCanWrite());
467 dispatcher_
.OnCanWrite();
468 EXPECT_FALSE(dispatcher_
.HasPendingWrites());