• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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