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/test_tools/quic_test_utils.h"
15 #include "net/tools/epoll_server/epoll_server.h"
16 #include "net/tools/quic/quic_time_wait_list_manager.h"
17 #include "net/tools/quic/test_tools/quic_dispatcher_peer.h"
18 #include "net/tools/quic/test_tools/quic_test_utils.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 using base::StringPiece;
23 using net::EpollServer;
24 using net::test::MockSession;
25 using net::tools::test::MockConnection;
26 using std::make_pair;
27 using testing::_;
28 using testing::DoAll;
29 using testing::Invoke;
30 using testing::InSequence;
31 using testing::Return;
32 using testing::WithoutArgs;
33
34 namespace net {
35 namespace tools {
36 namespace test {
37 namespace {
38
39 class TestDispatcher : public QuicDispatcher {
40 public:
TestDispatcher(const QuicConfig & config,const QuicCryptoServerConfig & crypto_config,EpollServer * eps)41 explicit TestDispatcher(const QuicConfig& config,
42 const QuicCryptoServerConfig& crypto_config,
43 EpollServer* eps)
44 : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), 1, eps) {
45 }
46
47 MOCK_METHOD3(CreateQuicSession, QuicSession*(
48 QuicGuid guid,
49 const IPEndPoint& server_address,
50 const IPEndPoint& client_address));
51 using QuicDispatcher::write_blocked_list;
52 };
53
54 // A Connection class which unregisters the session from the dispatcher
55 // when sending connection close.
56 // It'd be slightly more realistic to do this from the Session but it would
57 // involve a lot more mocking.
58 class MockServerConnection : public MockConnection {
59 public:
MockServerConnection(QuicGuid guid,QuicDispatcher * dispatcher)60 MockServerConnection(QuicGuid guid,
61 QuicDispatcher* dispatcher)
62 : MockConnection(guid, true),
63 dispatcher_(dispatcher) {
64 }
UnregisterOnConnectionClosed()65 void UnregisterOnConnectionClosed() {
66 LOG(ERROR) << "Unregistering " << guid();
67 dispatcher_->OnConnectionClosed(guid(), QUIC_NO_ERROR);
68 }
69 private:
70 QuicDispatcher* dispatcher_;
71 };
72
CreateSession(QuicDispatcher * dispatcher,QuicGuid guid,const IPEndPoint & addr,MockSession ** session)73 QuicSession* CreateSession(QuicDispatcher* dispatcher,
74 QuicGuid guid,
75 const IPEndPoint& addr,
76 MockSession** session) {
77 MockServerConnection* connection = new MockServerConnection(guid, dispatcher);
78 *session = new MockSession(connection);
79 ON_CALL(*connection, SendConnectionClose(_)).WillByDefault(
80 WithoutArgs(Invoke(
81 connection, &MockServerConnection::UnregisterOnConnectionClosed)));
82 EXPECT_CALL(*reinterpret_cast<MockConnection*>((*session)->connection()),
83 ProcessUdpPacket(_, addr, _));
84
85 return *session;
86 }
87
88 class QuicDispatcherTest : public ::testing::Test {
89 public:
QuicDispatcherTest()90 QuicDispatcherTest()
91 : crypto_config_(QuicCryptoServerConfig::TESTING,
92 QuicRandom::GetInstance()),
93 dispatcher_(config_, crypto_config_, &eps_),
94 session1_(NULL),
95 session2_(NULL) {
96 }
97
~QuicDispatcherTest()98 virtual ~QuicDispatcherTest() {}
99
connection1()100 MockConnection* connection1() {
101 return reinterpret_cast<MockConnection*>(session1_->connection());
102 }
103
connection2()104 MockConnection* connection2() {
105 return reinterpret_cast<MockConnection*>(session2_->connection());
106 }
107
ProcessPacket(IPEndPoint addr,QuicGuid guid,bool has_version_flag,const string & data)108 void ProcessPacket(IPEndPoint addr,
109 QuicGuid guid,
110 bool has_version_flag,
111 const string& data) {
112 dispatcher_.ProcessPacket(
113 IPEndPoint(), addr, guid, has_version_flag,
114 QuicEncryptedPacket(data.data(), data.length()));
115 }
116
ValidatePacket(const QuicEncryptedPacket & packet)117 void ValidatePacket(const QuicEncryptedPacket& packet) {
118 EXPECT_TRUE(packet.AsStringPiece().find(data_) != StringPiece::npos);
119 }
120
121 EpollServer eps_;
122 QuicConfig config_;
123 QuicCryptoServerConfig crypto_config_;
124 TestDispatcher dispatcher_;
125 MockSession* session1_;
126 MockSession* session2_;
127 string data_;
128 };
129
TEST_F(QuicDispatcherTest,ProcessPackets)130 TEST_F(QuicDispatcherTest, ProcessPackets) {
131 IPEndPoint addr(net::test::Loopback4(), 1);
132
133 EXPECT_CALL(dispatcher_, CreateQuicSession(1, _, addr))
134 .WillOnce(testing::Return(CreateSession(
135 &dispatcher_, 1, addr, &session1_)));
136 ProcessPacket(addr, 1, true, "foo");
137
138 EXPECT_CALL(dispatcher_, CreateQuicSession(2, _, addr))
139 .WillOnce(testing::Return(CreateSession(
140 &dispatcher_, 2, addr, &session2_)));
141 ProcessPacket(addr, 2, true, "bar");
142
143 data_ = "eep";
144 EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
145 ProcessUdpPacket(_, _, _)).Times(1).
146 WillOnce(testing::WithArgs<2>(Invoke(
147 this, &QuicDispatcherTest::ValidatePacket)));
148 ProcessPacket(addr, 1, false, "eep");
149 }
150
TEST_F(QuicDispatcherTest,Shutdown)151 TEST_F(QuicDispatcherTest, Shutdown) {
152 IPEndPoint addr(net::test::Loopback4(), 1);
153
154 EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
155 .WillOnce(testing::Return(CreateSession(
156 &dispatcher_, 1, addr, &session1_)));
157
158 ProcessPacket(addr, 1, true, "foo");
159
160 EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
161 SendConnectionClose(QUIC_PEER_GOING_AWAY));
162
163 dispatcher_.Shutdown();
164 }
165
166 class MockTimeWaitListManager : public QuicTimeWaitListManager {
167 public:
MockTimeWaitListManager(QuicPacketWriter * writer,EpollServer * eps)168 MockTimeWaitListManager(QuicPacketWriter* writer,
169 EpollServer* eps)
170 : QuicTimeWaitListManager(writer, eps, QuicSupportedVersions()) {
171 }
172
173 MOCK_METHOD4(ProcessPacket, void(const IPEndPoint& server_address,
174 const IPEndPoint& client_address,
175 QuicGuid guid,
176 const QuicEncryptedPacket& packet));
177 };
178
TEST_F(QuicDispatcherTest,TimeWaitListManager)179 TEST_F(QuicDispatcherTest, TimeWaitListManager) {
180 MockTimeWaitListManager* time_wait_list_manager =
181 new MockTimeWaitListManager(
182 QuicDispatcherPeer::GetWriter(&dispatcher_), &eps_);
183 // dispatcher takes the ownership of time_wait_list_manager.
184 QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
185 time_wait_list_manager);
186 // Create a new session.
187 IPEndPoint addr(net::test::Loopback4(), 1);
188 QuicGuid guid = 1;
189 EXPECT_CALL(dispatcher_, CreateQuicSession(guid, _, addr))
190 .WillOnce(testing::Return(CreateSession(
191 &dispatcher_, guid, addr, &session1_)));
192 ProcessPacket(addr, guid, true, "foo");
193
194 // Close the connection by sending public reset packet.
195 QuicPublicResetPacket packet;
196 packet.public_header.guid = guid;
197 packet.public_header.reset_flag = true;
198 packet.public_header.version_flag = false;
199 packet.rejected_sequence_number = 19191;
200 packet.nonce_proof = 132232;
201 scoped_ptr<QuicEncryptedPacket> encrypted(
202 QuicFramer::BuildPublicResetPacket(packet));
203 EXPECT_CALL(*session1_, OnConnectionClosed(QUIC_PUBLIC_RESET, true)).Times(1)
204 .WillOnce(WithoutArgs(Invoke(
205 reinterpret_cast<MockServerConnection*>(session1_->connection()),
206 &MockServerConnection::UnregisterOnConnectionClosed)));
207 EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()),
208 ProcessUdpPacket(_, _, _))
209 .WillOnce(Invoke(
210 reinterpret_cast<MockConnection*>(session1_->connection()),
211 &MockConnection::ReallyProcessUdpPacket));
212 dispatcher_.ProcessPacket(IPEndPoint(), addr, guid, true, *encrypted);
213 EXPECT_TRUE(time_wait_list_manager->IsGuidInTimeWait(guid));
214
215 // Dispatcher forwards subsequent packets for this guid to the time wait list
216 // manager.
217 EXPECT_CALL(*time_wait_list_manager, ProcessPacket(_, _, guid, _)).Times(1);
218 ProcessPacket(addr, guid, true, "foo");
219 }
220
TEST_F(QuicDispatcherTest,StrayPacketToTimeWaitListManager)221 TEST_F(QuicDispatcherTest, StrayPacketToTimeWaitListManager) {
222 MockTimeWaitListManager* time_wait_list_manager =
223 new MockTimeWaitListManager(
224 QuicDispatcherPeer::GetWriter(&dispatcher_), &eps_);
225 // dispatcher takes the ownership of time_wait_list_manager.
226 QuicDispatcherPeer::SetTimeWaitListManager(&dispatcher_,
227 time_wait_list_manager);
228
229 IPEndPoint addr(net::test::Loopback4(), 1);
230 QuicGuid guid = 1;
231 // Dispatcher forwards all packets for this guid to the time wait list
232 // manager.
233 EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, _)).Times(0);
234 EXPECT_CALL(*time_wait_list_manager, ProcessPacket(_, _, guid, _)).Times(1);
235 string data = "foo";
236 ProcessPacket(addr, guid, false, "foo");
237 }
238
239 class QuicWriteBlockedListTest : public QuicDispatcherTest {
240 public:
SetUp()241 virtual void SetUp() {
242 IPEndPoint addr(net::test::Loopback4(), 1);
243
244 EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
245 .WillOnce(testing::Return(CreateSession(
246 &dispatcher_, 1, addr, &session1_)));
247 ProcessPacket(addr, 1, true, "foo");
248
249 EXPECT_CALL(dispatcher_, CreateQuicSession(_, _, addr))
250 .WillOnce(testing::Return(CreateSession(
251 &dispatcher_, 2, addr, &session2_)));
252 ProcessPacket(addr, 2, true, "bar");
253
254 blocked_list_ = dispatcher_.write_blocked_list();
255 }
256
TearDown()257 virtual void TearDown() {
258 EXPECT_CALL(*connection1(), SendConnectionClose(QUIC_PEER_GOING_AWAY));
259 EXPECT_CALL(*connection2(), SendConnectionClose(QUIC_PEER_GOING_AWAY));
260 dispatcher_.Shutdown();
261 }
262
SetBlocked()263 bool SetBlocked() {
264 QuicDispatcherPeer::SetWriteBlocked(&dispatcher_);
265 return true;
266 }
267
268 protected:
269 QuicDispatcher::WriteBlockedList* blocked_list_;
270 };
271
TEST_F(QuicWriteBlockedListTest,BasicOnCanWrite)272 TEST_F(QuicWriteBlockedListTest, BasicOnCanWrite) {
273 // No OnCanWrite calls because no connections are blocked.
274 dispatcher_.OnCanWrite();
275
276 // Register connection 1 for events, and make sure it's nofitied.
277 blocked_list_->insert(make_pair(connection1(), true));
278 EXPECT_CALL(*connection1(), OnCanWrite());
279 dispatcher_.OnCanWrite();
280
281 // It should get only one notification.
282 EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
283 EXPECT_FALSE(dispatcher_.OnCanWrite());
284 }
285
TEST_F(QuicWriteBlockedListTest,OnCanWriteOrder)286 TEST_F(QuicWriteBlockedListTest, OnCanWriteOrder) {
287 // Make sure we handle events in order.
288 InSequence s;
289 blocked_list_->insert(make_pair(connection1(), true));
290 blocked_list_->insert(make_pair(connection2(), true));
291 EXPECT_CALL(*connection1(), OnCanWrite());
292 EXPECT_CALL(*connection2(), OnCanWrite());
293 dispatcher_.OnCanWrite();
294
295 // Check the other ordering.
296 blocked_list_->insert(make_pair(connection2(), true));
297 blocked_list_->insert(make_pair(connection1(), true));
298 EXPECT_CALL(*connection2(), OnCanWrite());
299 EXPECT_CALL(*connection1(), OnCanWrite());
300 dispatcher_.OnCanWrite();
301 }
302
TEST_F(QuicWriteBlockedListTest,OnCanWriteRemove)303 TEST_F(QuicWriteBlockedListTest, OnCanWriteRemove) {
304 // Add and remove one connction.
305 blocked_list_->insert(make_pair(connection1(), true));
306 blocked_list_->erase(connection1());
307 EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
308 dispatcher_.OnCanWrite();
309
310 // Add and remove one connction and make sure it doesn't affect others.
311 blocked_list_->insert(make_pair(connection1(), true));
312 blocked_list_->insert(make_pair(connection2(), true));
313 blocked_list_->erase(connection1());
314 EXPECT_CALL(*connection2(), OnCanWrite());
315 dispatcher_.OnCanWrite();
316
317 // Add it, remove it, and add it back and make sure things are OK.
318 blocked_list_->insert(make_pair(connection1(), true));
319 blocked_list_->erase(connection1());
320 blocked_list_->insert(make_pair(connection1(), true));
321 EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
322 dispatcher_.OnCanWrite();
323 }
324
TEST_F(QuicWriteBlockedListTest,DoubleAdd)325 TEST_F(QuicWriteBlockedListTest, DoubleAdd) {
326 // Make sure a double add does not necessitate a double remove.
327 blocked_list_->insert(make_pair(connection1(), true));
328 blocked_list_->insert(make_pair(connection1(), true));
329 blocked_list_->erase(connection1());
330 EXPECT_CALL(*connection1(), OnCanWrite()).Times(0);
331 dispatcher_.OnCanWrite();
332
333 // Make sure a double add does not result in two OnCanWrite calls.
334 blocked_list_->insert(make_pair(connection1(), true));
335 blocked_list_->insert(make_pair(connection1(), true));
336 EXPECT_CALL(*connection1(), OnCanWrite()).Times(1);
337 dispatcher_.OnCanWrite();
338 }
339
TEST_F(QuicWriteBlockedListTest,OnCanWriteHandleBlock)340 TEST_F(QuicWriteBlockedListTest, OnCanWriteHandleBlock) {
341 // Finally make sure if we write block on a write call, we stop calling.
342 InSequence s;
343 blocked_list_->insert(make_pair(connection1(), true));
344 blocked_list_->insert(make_pair(connection2(), true));
345 EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(
346 Invoke(this, &QuicWriteBlockedListTest::SetBlocked));
347 EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
348 dispatcher_.OnCanWrite();
349
350 // And we'll resume where we left off when we get another call.
351 EXPECT_CALL(*connection2(), OnCanWrite());
352 dispatcher_.OnCanWrite();
353 }
354
TEST_F(QuicWriteBlockedListTest,LimitedWrites)355 TEST_F(QuicWriteBlockedListTest, LimitedWrites) {
356 // Make sure we call both writers. The first will register for more writing
357 // but should not be immediately called due to limits.
358 InSequence s;
359 blocked_list_->insert(make_pair(connection1(), true));
360 blocked_list_->insert(make_pair(connection2(), true));
361 EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(Return(true));
362 EXPECT_CALL(*connection2(), OnCanWrite()).WillOnce(Return(false));
363 dispatcher_.OnCanWrite();
364
365 // Now call OnCanWrite again, and connection1 should get its second chance
366 EXPECT_CALL(*connection1(), OnCanWrite());
367 dispatcher_.OnCanWrite();
368 }
369
TEST_F(QuicWriteBlockedListTest,TestWriteLimits)370 TEST_F(QuicWriteBlockedListTest, TestWriteLimits) {
371 // Finally make sure if we write block on a write call, we stop calling.
372 InSequence s;
373 blocked_list_->insert(make_pair(connection1(), true));
374 blocked_list_->insert(make_pair(connection2(), true));
375 EXPECT_CALL(*connection1(), OnCanWrite()).WillOnce(
376 Invoke(this, &QuicWriteBlockedListTest::SetBlocked));
377 EXPECT_CALL(*connection2(), OnCanWrite()).Times(0);
378 dispatcher_.OnCanWrite();
379
380 // And we'll resume where we left off when we get another call.
381 EXPECT_CALL(*connection2(), OnCanWrite());
382 dispatcher_.OnCanWrite();
383 }
384
385 } // namespace
386 } // namespace test
387 } // namespace tools
388 } // namespace net
389