Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1284)

Side by Side Diff: remoting/protocol/jingle_session_unittest.cc

Issue 8743023: Separate Authenticator and Session unittests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: - Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/bind.h" 5 #include "base/bind.h"
6 #include "base/file_path.h"
7 #include "base/file_util.h"
8 #include "base/message_loop_proxy.h" 6 #include "base/message_loop_proxy.h"
9 #include "base/path_service.h"
10 #include "base/time.h" 7 #include "base/time.h"
11 #include "base/test/test_timeouts.h" 8 #include "base/test/test_timeouts.h"
12 #include "crypto/nss_util.h"
13 #include "crypto/rsa_private_key.h"
14 #include "net/base/completion_callback.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/socket/socket.h" 9 #include "net/socket/socket.h"
18 #include "net/socket/stream_socket.h" 10 #include "net/socket/stream_socket.h"
19 #include "remoting/base/constants.h" 11 #include "remoting/base/constants.h"
20 #include "remoting/protocol/auth_util.h"
21 #include "remoting/protocol/authenticator.h" 12 #include "remoting/protocol/authenticator.h"
22 #include "remoting/protocol/channel_authenticator.h" 13 #include "remoting/protocol/channel_authenticator.h"
14 #include "remoting/protocol/connection_tester.h"
15 #include "remoting/protocol/fake_authenticator.h"
23 #include "remoting/protocol/jingle_session.h" 16 #include "remoting/protocol/jingle_session.h"
24 #include "remoting/protocol/jingle_session_manager.h" 17 #include "remoting/protocol/jingle_session_manager.h"
25 #include "remoting/protocol/v1_authenticator.h"
26 #include "remoting/jingle_glue/jingle_thread.h" 18 #include "remoting/jingle_glue/jingle_thread.h"
27 #include "remoting/jingle_glue/fake_signal_strategy.h" 19 #include "remoting/jingle_glue/fake_signal_strategy.h"
28 #include "testing/gmock/include/gmock/gmock.h" 20 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
30 #include "third_party/libjingle/source/talk/p2p/client/basicportallocator.h"
31 22
32 using testing::_; 23 using testing::_;
33 using testing::AtMost; 24 using testing::AtMost;
34 using testing::DeleteArg; 25 using testing::DeleteArg;
35 using testing::DoAll; 26 using testing::DoAll;
36 using testing::InSequence; 27 using testing::InSequence;
37 using testing::Invoke; 28 using testing::Invoke;
38 using testing::InvokeWithoutArgs; 29 using testing::InvokeWithoutArgs;
39 using testing::Return; 30 using testing::Return;
40 using testing::SaveArg; 31 using testing::SaveArg;
41 using testing::SetArgumentPointee; 32 using testing::SetArgumentPointee;
42 using testing::WithArg; 33 using testing::WithArg;
43 34
44 namespace remoting { 35 namespace remoting {
45 namespace protocol { 36 namespace protocol {
46 class JingleSessionTest;
47 } // namespace protocol
48 } // namespace remoting
49
50 DISABLE_RUNNABLE_METHOD_REFCOUNT(remoting::protocol::JingleSessionTest);
51
52 namespace remoting {
53 namespace protocol {
54 37
55 namespace { 38 namespace {
56 39
57 // Send 100 messages 1024 bytes each. UDP messages are sent with 10ms delay 40 // Send 100 messages 1024 bytes each. UDP messages are sent with 10ms delay
58 // between messages (about 1 second for 100 messages). 41 // between messages (about 1 second for 100 messages).
59 const int kMessageSize = 1024; 42 const int kMessageSize = 1024;
60 const int kMessages = 100; 43 const int kMessages = 100;
61 const int kTestDataSize = kMessages * kMessageSize;
62 const int kUdpWriteDelayMs = 10; 44 const int kUdpWriteDelayMs = 10;
63 const char kChannelName[] = "test_channel"; 45 const char kChannelName[] = "test_channel";
64 46
65 const char kHostJid[] = "host1@gmail.com/123"; 47 const char kHostJid[] = "host1@gmail.com/123";
66 const char kClientJid[] = "host2@gmail.com/321"; 48 const char kClientJid[] = "host2@gmail.com/321";
67 49
68 const char kTestHostPublicKey[] =
69 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3nk/8ILc0JBqHgOS0UCOIl4m"
70 "0GUd2FIiZ/6Fc9D/iiyUgli+FIY5dwsrSoNJ87sYGifVDh8a5fdZNV5y58CcrapI5fJI"
71 "FpXviSW4g8d/t1gcZkoz1ppmjzbgXm6ckw9Td0yRD0cHu732Ijs+eo8wT0pt4KiHkbyR"
72 "iAvjrvkNDlfiEk7tiY7YzD9zTi3146GX6KLz5GQAd/3I8I5QW3ftF1s/m93AHuc383GZ"
73 "A78Oi+IbcJf/jJUZO119VNnRKGiPsf5GZIoHyXX8O5OUQk5soKdQPeK1FwWkeZu6fuXl"
74 "QoU12I6podD6xMFa/PA/xefMwcpmuWTRhcso9bp10zVFGQIDAQAB";
75
76 const char kTestSharedSecret[] = "1234-1234-5678";
77 const char kTestSharedSecretBad[] = "0000-0000-0001";
78
79 void QuitCurrentThread() { 50 void QuitCurrentThread() {
80 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); 51 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
81 } 52 }
82 53
83 void OnTimeoutTerminateThread(bool* timeout) { 54 void OnTimeoutTerminateThread(bool* timeout) {
84 *timeout = true; 55 *timeout = true;
85 QuitCurrentThread(); 56 QuitCurrentThread();
86 } 57 }
87 58
88 bool RunMessageLoopWithTimeout(int timeout_ms) { 59 bool RunMessageLoopWithTimeout(int timeout_ms) {
89 bool timeout = false; 60 bool timeout = false;
90 MessageLoop::current()->PostDelayedTask( 61 MessageLoop::current()->PostDelayedTask(
91 FROM_HERE, base::Bind(&OnTimeoutTerminateThread, &timeout), timeout_ms); 62 FROM_HERE, base::Bind(&OnTimeoutTerminateThread, &timeout), timeout_ms);
92 MessageLoop::current()->Run(); 63 MessageLoop::current()->Run();
93 return !timeout; 64 return !timeout;
94 } 65 }
95 66
67 ACTION(QuitThread) {
68 QuitCurrentThread();
69 }
70
96 ACTION_P(QuitThreadOnCounter, counter) { 71 ACTION_P(QuitThreadOnCounter, counter) {
97 (*counter)--; 72 (*counter)--;
98 EXPECT_GE(*counter, 0); 73 EXPECT_GE(*counter, 0);
99 if (*counter == 0) 74 if (*counter == 0)
100 QuitCurrentThread(); 75 QuitCurrentThread();
101 } 76 }
102 77
103 class MockSessionManagerListener : public SessionManager::Listener { 78 class MockSessionManagerListener : public SessionManager::Listener {
104 public: 79 public:
105 MOCK_METHOD0(OnSessionManagerInitialized, void()); 80 MOCK_METHOD0(OnSessionManagerInitialized, void());
106 MOCK_METHOD2(OnIncomingSession, 81 MOCK_METHOD2(OnIncomingSession,
107 void(Session*, 82 void(Session*,
108 SessionManager::IncomingSessionResponse*)); 83 SessionManager::IncomingSessionResponse*));
109 }; 84 };
110 85
111 class MockSessionCallback { 86 class MockSessionCallback {
112 public: 87 public:
113 MOCK_METHOD1(OnStateChange, void(Session::State)); 88 MOCK_METHOD1(OnStateChange, void(Session::State));
114 }; 89 };
115 90
116 class FakeChannelAuthenticator : public ChannelAuthenticator { 91 class MockStreamChannelCallback {
117 public: 92 public:
118 FakeChannelAuthenticator(bool accept) 93 MOCK_METHOD1(OnDone, void(net::StreamSocket* socket));
119 : accept_(accept) {
120 }
121 virtual ~FakeChannelAuthenticator() {}
122
123 virtual void SecureAndAuthenticate(
124 net::StreamSocket* socket, const DoneCallback& done_callback) OVERRIDE {
125 if (accept_) {
126 done_callback.Run(net::OK, socket);
127 } else {
128 delete socket;
129 done_callback.Run(net::ERR_FAILED, NULL);
130 }
131 }
132
133 private:
134 bool accept_;
135
136 DISALLOW_COPY_AND_ASSIGN(FakeChannelAuthenticator);
137 }; 94 };
138 95
139 class FakeClientAuthenticator : public Authenticator { 96 class MockDatagramChannelCallback {
140 public: 97 public:
141 FakeClientAuthenticator(bool accept, bool accept_channel) 98 MOCK_METHOD1(OnDone, void(net::Socket* socket));
142 : accept_(accept),
143 accept_channel_(accept_channel),
144 state_(MESSAGE_READY) {
145 }
146 virtual ~FakeClientAuthenticator() {}
147
148 virtual State state() const OVERRIDE {
149 return state_;
150 }
151
152 virtual void ProcessMessage(const buzz::XmlElement* message) OVERRIDE {
153 EXPECT_EQ(WAITING_MESSAGE, state_);
154 state_ = accept_ ? ACCEPTED : REJECTED;
155 }
156
157 virtual buzz::XmlElement* GetNextMessage() OVERRIDE {
158 EXPECT_EQ(MESSAGE_READY, state_);
159 state_ = WAITING_MESSAGE;
160 return new buzz::XmlElement(
161 buzz::QName(kChromotingXmlNamespace, "authentication"));
162 }
163
164 virtual ChannelAuthenticator* CreateChannelAuthenticator() const OVERRIDE {
165 return new FakeChannelAuthenticator(accept_channel_);
166 }
167
168 protected:
169 bool accept_;
170 bool accept_channel_;
171 State state_;
172
173 DISALLOW_COPY_AND_ASSIGN(FakeClientAuthenticator);
174 };
175
176 class FakeHostAuthenticator : public Authenticator {
177 public:
178 FakeHostAuthenticator(bool accept, bool accept_channel)
179 : accept_(accept),
180 accept_channel_(accept_channel),
181 state_(WAITING_MESSAGE) {
182 }
183 virtual ~FakeHostAuthenticator() {}
184
185 virtual State state() const OVERRIDE {
186 return state_;
187 }
188
189 virtual void ProcessMessage(const buzz::XmlElement* message) OVERRIDE {
190 EXPECT_EQ(WAITING_MESSAGE, state_);
191 state_ = MESSAGE_READY;
192 }
193
194 virtual buzz::XmlElement* GetNextMessage() OVERRIDE {
195 EXPECT_EQ(MESSAGE_READY, state_);
196 state_ = accept_ ? ACCEPTED : REJECTED;
197 return new buzz::XmlElement(
198 buzz::QName(kChromotingXmlNamespace, "authentication"));
199 }
200
201 virtual ChannelAuthenticator* CreateChannelAuthenticator() const OVERRIDE {
202 return new FakeChannelAuthenticator(accept_channel_);
203 }
204
205 protected:
206 bool accept_;
207 bool accept_channel_;
208 State state_;
209
210 DISALLOW_COPY_AND_ASSIGN(FakeHostAuthenticator);
211 };
212
213 class FakeHostAuthenticatorFactory : public AuthenticatorFactory {
214 public:
215 FakeHostAuthenticatorFactory(bool accept, bool accept_channel)
216 : accept_(accept),
217 accept_channel_(accept_channel) {
218 }
219 virtual ~FakeHostAuthenticatorFactory() {}
220
221 virtual Authenticator* CreateAuthenticator(
222 const std::string& remote_jid,
223 const buzz::XmlElement* first_message) OVERRIDE {
224 return new FakeHostAuthenticator(accept_, accept_channel_);
225 }
226
227 private:
228 bool accept_;
229 bool accept_channel_;
230
231 DISALLOW_COPY_AND_ASSIGN(FakeHostAuthenticatorFactory);
232 }; 99 };
233 100
234 } // namespace 101 } // namespace
235 102
236 class JingleSessionTest : public testing::Test { 103 class JingleSessionTest : public testing::Test {
237 public: 104 public:
238 JingleSessionTest() 105 JingleSessionTest()
239 : message_loop_(talk_base::Thread::Current()) { 106 : message_loop_(talk_base::Thread::Current()) {
240 } 107 }
241 108
(...skipping 11 matching lines...) Expand all
253 protected: 120 protected:
254 virtual void SetUp() { 121 virtual void SetUp() {
255 } 122 }
256 123
257 virtual void TearDown() { 124 virtual void TearDown() {
258 CloseSessions(); 125 CloseSessions();
259 CloseSessionManager(); 126 CloseSessionManager();
260 } 127 }
261 128
262 void CloseSessions() { 129 void CloseSessions() {
263 if (host_session_.get()) { 130 host_socket_.reset();
264 host_session_->Close(); 131 client_socket_.reset();
265 host_session_.reset(); 132 host_session_.reset();
266 } 133 client_session_.reset();
267 if (client_session_.get()) {
268 client_session_->Close();
269 client_session_.reset();
270 }
271 } 134 }
272 135
273 void CreateServerPair(bool use_fake_auth) { 136 void CreateServerPair(FakeAuthenticator::Action auth_action,
274 FilePath certs_dir; 137 int auth_round_trips) {
275 PathService::Get(base::DIR_SOURCE_ROOT, &certs_dir);
276 certs_dir = certs_dir.AppendASCII("net");
277 certs_dir = certs_dir.AppendASCII("data");
278 certs_dir = certs_dir.AppendASCII("ssl");
279 certs_dir = certs_dir.AppendASCII("certificates");
280
281 FilePath cert_path = certs_dir.AppendASCII("unittest.selfsigned.der");
282 std::string cert_der;
283 ASSERT_TRUE(file_util::ReadFileToString(cert_path, &cert_der));
284
285 FilePath key_path = certs_dir.AppendASCII("unittest.key.bin");
286 std::string key_string;
287 ASSERT_TRUE(file_util::ReadFileToString(key_path, &key_string));
288 std::vector<uint8> key_vector(
289 reinterpret_cast<const uint8*>(key_string.data()),
290 reinterpret_cast<const uint8*>(key_string.data() +
291 key_string.length()));
292 scoped_ptr<crypto::RSAPrivateKey> private_key(
293 crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_vector));
294
295 host_signal_strategy_.reset(new FakeSignalStrategy(kHostJid)); 138 host_signal_strategy_.reset(new FakeSignalStrategy(kHostJid));
296 client_signal_strategy_.reset(new FakeSignalStrategy(kClientJid)); 139 client_signal_strategy_.reset(new FakeSignalStrategy(kClientJid));
297 FakeSignalStrategy::Connect(host_signal_strategy_.get(), 140 FakeSignalStrategy::Connect(host_signal_strategy_.get(),
298 client_signal_strategy_.get()); 141 client_signal_strategy_.get());
299 142
300 EXPECT_CALL(host_server_listener_, OnSessionManagerInitialized()) 143 EXPECT_CALL(host_server_listener_, OnSessionManagerInitialized())
301 .Times(1); 144 .Times(1);
302 host_server_.reset(new JingleSessionManager( 145 host_server_.reset(new JingleSessionManager(
303 base::MessageLoopProxy::current())); 146 base::MessageLoopProxy::current()));
304 host_server_->Init( 147 host_server_->Init(
305 kHostJid, host_signal_strategy_.get(), &host_server_listener_, false); 148 kHostJid, host_signal_strategy_.get(), &host_server_listener_, false);
306 149
307 if (use_fake_auth) { 150 host_server_->set_authenticator_factory(
308 host_server_->set_authenticator_factory( 151 new FakeHostAuthenticatorFactory(auth_action, auth_round_trips));
309 new FakeHostAuthenticatorFactory(true, false));
310 } else {
311 host_server_->set_authenticator_factory(
312 new V1HostAuthenticatorFactory(
313 cert_der, private_key.get(), kTestSharedSecret));
314 }
315 152
316 EXPECT_CALL(client_server_listener_, OnSessionManagerInitialized()) 153 EXPECT_CALL(client_server_listener_, OnSessionManagerInitialized())
317 .Times(1); 154 .Times(1);
318 client_server_.reset(new JingleSessionManager( 155 client_server_.reset(new JingleSessionManager(
319 base::MessageLoopProxy::current())); 156 base::MessageLoopProxy::current()));
320 client_server_->Init( 157 client_server_->Init(
321 kClientJid, client_signal_strategy_.get(), 158 kClientJid, client_signal_strategy_.get(),
322 &client_server_listener_, false); 159 &client_server_listener_, false);
323 } 160 }
324 161
325 void CloseSessionManager() { 162 void CloseSessionManager() {
326 if (host_server_.get()) { 163 if (host_server_.get()) {
327 host_server_->Close(); 164 host_server_->Close();
328 host_server_.reset(); 165 host_server_.reset();
329 } 166 }
330 if (client_server_.get()) { 167 if (client_server_.get()) {
331 client_server_->Close(); 168 client_server_->Close();
332 client_server_.reset(); 169 client_server_.reset();
333 } 170 }
334 host_signal_strategy_.reset(); 171 host_signal_strategy_.reset();
335 client_signal_strategy_.reset(); 172 client_signal_strategy_.reset();
336 } 173 }
337 174
338 bool InitiateConnection(bool use_fake_auth) { 175 bool InitiateConnection(FakeAuthenticator::Action auth_action,
339 int not_connected_peers = 2; 176 int auth_round_trips, bool expect_fail) {
177 int not_connected_peers = expect_fail ? 1 : 2;
Wez 2011/12/09 23:42:33 Not clear on what this means; surely neither peer
Sergey Ulanov 2011/12/12 22:52:00 It is a counter for QuitThreadOnCounter(). I agree
340 178
341 EXPECT_CALL(host_server_listener_, OnIncomingSession(_, _)) 179 EXPECT_CALL(host_server_listener_, OnIncomingSession(_, _))
342 .WillOnce(DoAll( 180 .WillOnce(DoAll(
343 WithArg<0>(Invoke( 181 WithArg<0>(Invoke(
344 this, &JingleSessionTest::SetHostSession)), 182 this, &JingleSessionTest::SetHostSession)),
345 SetArgumentPointee<1>(protocol::SessionManager::ACCEPT))); 183 SetArgumentPointee<1>(protocol::SessionManager::ACCEPT)));
346 184
347 { 185 {
348 InSequence dummy; 186 InSequence dummy;
349 187
350 EXPECT_CALL(host_connection_callback_, 188 if (expect_fail) {
351 OnStateChange(Session::CONNECTED)) 189 EXPECT_CALL(host_connection_callback_,
352 .Times(1) 190 OnStateChange(Session::FAILED))
353 .WillOnce(QuitThreadOnCounter(&not_connected_peers)); 191 .Times(1)
354 // Expect that the connection will be closed eventually. 192 .WillOnce(QuitThreadOnCounter(&not_connected_peers));
355 EXPECT_CALL(host_connection_callback_, 193 } else {
356 OnStateChange(Session::CLOSED)) 194 EXPECT_CALL(host_connection_callback_,
357 .Times(AtMost(1)); 195 OnStateChange(Session::CONNECTED))
196 .Times(1)
197 .WillOnce(QuitThreadOnCounter(&not_connected_peers));
198 // Expect that the connection will be closed eventually.
199 EXPECT_CALL(host_connection_callback_,
200 OnStateChange(Session::CLOSED))
201 .Times(AtMost(1));
202 }
358 } 203 }
359 204
360 { 205 {
361 InSequence dummy; 206 InSequence dummy;
362 207
363 EXPECT_CALL(client_connection_callback_, 208 EXPECT_CALL(client_connection_callback_,
364 OnStateChange(Session::CONNECTING)) 209 OnStateChange(Session::CONNECTING))
365 .Times(1); 210 .Times(1);
366 EXPECT_CALL(client_connection_callback_, 211 if (!expect_fail) {
367 OnStateChange(Session::CONNECTED)) 212 EXPECT_CALL(client_connection_callback_,
368 .Times(1) 213 OnStateChange(Session::CONNECTED))
369 .WillOnce(QuitThreadOnCounter(&not_connected_peers)); 214 .Times(1)
215 .WillOnce(QuitThreadOnCounter(&not_connected_peers));
216 }
370 // Expect that the connection will be closed eventually. 217 // Expect that the connection will be closed eventually.
371 EXPECT_CALL(client_connection_callback_, 218 EXPECT_CALL(client_connection_callback_,
372 OnStateChange(Session::CLOSED)) 219 OnStateChange(Session::CLOSED))
373 .Times(AtMost(1)); 220 .Times(AtMost(1));
374 } 221 }
375 222
376 Authenticator* authenticator; 223 Authenticator* authenticator = new FakeAuthenticator(
377 if (use_fake_auth) { 224 FakeAuthenticator::CLIENT, auth_action, auth_round_trips);
378 authenticator = new FakeClientAuthenticator(true, true); 225
379 } else {
380 authenticator = new V1ClientAuthenticator(kClientJid, kTestSharedSecret);
381 }
382 client_session_.reset(client_server_->Connect( 226 client_session_.reset(client_server_->Connect(
383 kHostJid, authenticator, 227 kHostJid, authenticator,
384 CandidateSessionConfig::CreateDefault(), 228 CandidateSessionConfig::CreateDefault(),
385 base::Bind(&MockSessionCallback::OnStateChange, 229 base::Bind(&MockSessionCallback::OnStateChange,
386 base::Unretained(&client_connection_callback_)))); 230 base::Unretained(&client_connection_callback_))));
387 231
388 return RunMessageLoopWithTimeout(TestTimeouts::action_max_timeout_ms()); 232 return RunMessageLoopWithTimeout(TestTimeouts::action_max_timeout_ms());
389 } 233 }
390 234
235 bool CreateChannel() {
236 MockStreamChannelCallback client_callback;
237 MockStreamChannelCallback host_callback;
238
239 client_session_->CreateStreamChannel(kChannelName, base::Bind(
240 &MockStreamChannelCallback::OnDone,
241 base::Unretained(&host_callback)));
242 host_session_->CreateStreamChannel(kChannelName, base::Bind(
243 &MockStreamChannelCallback::OnDone,
244 base::Unretained(&client_callback)));
245
246 int counter = 2;
247 net::StreamSocket* client_socket = NULL;
248 net::StreamSocket* host_socket = NULL;
249 EXPECT_CALL(client_callback, OnDone(_))
250 .WillOnce(DoAll(SaveArg<0>(&client_socket),
251 QuitThreadOnCounter(&counter)));
252 EXPECT_CALL(host_callback, OnDone(_))
253 .WillOnce(DoAll(SaveArg<0>(&host_socket),
254 QuitThreadOnCounter(&counter)));
255 message_loop_.Run();
256
257 EXPECT_TRUE(client_socket != NULL);
258 EXPECT_TRUE(host_socket != NULL);
259
260 client_socket_.reset(client_socket);
261 host_socket_.reset(host_socket);
262
263 return client_socket_.get() && host_socket_.get();
264 }
265
266 void RunSpeedTest(int size) {
267 ASSERT_TRUE(InitiateConnection(FakeAuthenticator::ACCEPT, 1, false));
268 ASSERT_TRUE(CreateChannel());
269
270 base::Time start = base::Time::Now();
271 StreamConnectionTester tester(
272 host_socket_.get(), client_socket_.get(), size, 1);
273 tester.Start();
274 message_loop_.Run();
275 tester.CheckResults();
276 LOG(INFO) << "Time for " << size << " bytes "
277 << (base::Time::Now() - start).InMilliseconds() << " ms.";
278
279 CloseSessions();
280 }
281
391 static void DoNothing() { } 282 static void DoNothing() { }
392 283
393 JingleThreadMessageLoop message_loop_; 284 JingleThreadMessageLoop message_loop_;
394 285
395 scoped_ptr<FakeSignalStrategy> host_signal_strategy_; 286 scoped_ptr<FakeSignalStrategy> host_signal_strategy_;
396 scoped_ptr<FakeSignalStrategy> client_signal_strategy_; 287 scoped_ptr<FakeSignalStrategy> client_signal_strategy_;
397 288
398 scoped_ptr<JingleSessionManager> host_server_; 289 scoped_ptr<JingleSessionManager> host_server_;
399 MockSessionManagerListener host_server_listener_; 290 MockSessionManagerListener host_server_listener_;
400 scoped_ptr<JingleSessionManager> client_server_; 291 scoped_ptr<JingleSessionManager> client_server_;
401 MockSessionManagerListener client_server_listener_; 292 MockSessionManagerListener client_server_listener_;
402 293
403 scoped_ptr<Session> host_session_; 294 scoped_ptr<Session> host_session_;
404 MockSessionCallback host_connection_callback_; 295 MockSessionCallback host_connection_callback_;
405 scoped_ptr<Session> client_session_; 296 scoped_ptr<Session> client_session_;
406 MockSessionCallback client_connection_callback_; 297 MockSessionCallback client_connection_callback_;
298
299 scoped_ptr<net::StreamSocket> client_socket_;
300 scoped_ptr<net::StreamSocket> host_socket_;
407 }; 301 };
408 302
409 class ChannelTesterBase : public base::RefCountedThreadSafe<ChannelTesterBase> {
410 public:
411 ChannelTesterBase(Session* host_session,
412 Session* client_session)
413 : host_session_(host_session),
414 client_session_(client_session),
415 done_(false) {
416 }
417
418 virtual ~ChannelTesterBase() { }
419
420 void Start() {
421 MessageLoop::current()->PostTask(
422 FROM_HERE, base::Bind(&ChannelTesterBase::DoStart, this));
423 }
424
425 bool WaitFinished() {
426 return RunMessageLoopWithTimeout(TestTimeouts::action_max_timeout_ms());
427 }
428
429 virtual void CheckResults() = 0;
430
431 protected:
432 void DoStart() {
433 InitChannels();
434 }
435
436 virtual void InitChannels() = 0;
437
438 void Done() {
439 done_ = true;
440 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitCurrentThread));
441 }
442
443 virtual void InitBuffers() = 0;
444 virtual void DoWrite() = 0;
445 virtual void DoRead() = 0;
446
447 Session* host_session_;
448 Session* client_session_;
449 scoped_ptr<net::Socket> sockets_[2];
450 bool done_;
451 };
452
453 class TCPChannelTester : public ChannelTesterBase {
454 public:
455 TCPChannelTester(Session* host_session,
456 Session* client_session,
457 int message_size,
458 int message_count)
459 : ChannelTesterBase(host_session, client_session),
460 ALLOW_THIS_IN_INITIALIZER_LIST(
461 write_cb_(this, &TCPChannelTester::OnWritten)),
462 ALLOW_THIS_IN_INITIALIZER_LIST(
463 read_cb_(this, &TCPChannelTester::OnRead)),
464 write_errors_(0),
465 read_errors_(0),
466 message_size_(message_size),
467 message_count_(message_count),
468 test_data_size_(message_size * message_count) {
469 }
470
471 virtual ~TCPChannelTester() { }
472
473 virtual bool did_initialization_fail() {
474 return !sockets_[0].get() || !sockets_[1].get();
475 }
476
477 virtual void CheckResults() {
478 ASSERT_FALSE(did_initialization_fail());
479
480 EXPECT_EQ(0, write_errors_);
481 EXPECT_EQ(0, read_errors_);
482
483 ASSERT_EQ(test_data_size_, input_buffer_->offset());
484
485 output_buffer_->SetOffset(0);
486 ASSERT_EQ(test_data_size_, output_buffer_->size());
487
488 EXPECT_EQ(0, memcmp(output_buffer_->data(),
489 input_buffer_->StartOfBuffer(), test_data_size_));
490 }
491
492 protected:
493 virtual void InitChannels() OVERRIDE {
494 host_session_->CreateStreamChannel(
495 kChannelName,
496 base::Bind(&TCPChannelTester::OnChannelReady,
497 base::Unretained(this), 0));
498 client_session_->CreateStreamChannel(
499 kChannelName,
500 base::Bind(&TCPChannelTester::OnChannelReady,
501 base::Unretained(this), 1));
502 }
503
504 void OnChannelReady(int id, net::StreamSocket* socket) {
505 if (!socket) {
506 host_session_->CancelChannelCreation(kChannelName);
507 client_session_->CancelChannelCreation(kChannelName);
508 Done();
509 return;
510 }
511
512 DCHECK(id >= 0 && id < 2);
513 sockets_[id].reset(socket);
514
515 if (sockets_[0].get() && sockets_[1].get()) {
516 InitBuffers();
517 DoRead();
518 DoWrite();
519 }
520 }
521
522 virtual void InitBuffers() {
523 output_buffer_ = new net::DrainableIOBuffer(
524 new net::IOBuffer(test_data_size_), test_data_size_);
525 memset(output_buffer_->data(), 123, test_data_size_);
526
527 input_buffer_ = new net::GrowableIOBuffer();
528 }
529
530 virtual void DoWrite() {
531 int result = 1;
532 while (result > 0) {
533 if (output_buffer_->BytesRemaining() == 0)
534 break;
535 int bytes_to_write = std::min(output_buffer_->BytesRemaining(),
536 message_size_);
537 result = sockets_[0]->Write(output_buffer_, bytes_to_write, &write_cb_);
538 HandleWriteResult(result);
539 };
540 }
541
542 void OnWritten(int result) {
543 HandleWriteResult(result);
544 DoWrite();
545 }
546
547 void HandleWriteResult(int result) {
548 if (result <= 0 && result != net::ERR_IO_PENDING) {
549 LOG(ERROR) << "Received error " << result << " when trying to write";
550 write_errors_++;
551 Done();
552 } else if (result > 0) {
553 output_buffer_->DidConsume(result);
554 }
555 }
556
557 virtual void DoRead() {
558 int result = 1;
559 while (result > 0) {
560 input_buffer_->SetCapacity(input_buffer_->offset() + message_size_);
561 result = sockets_[1]->Read(input_buffer_, message_size_, &read_cb_);
562 HandleReadResult(result);
563 };
564 }
565
566 void OnRead(int result) {
567 HandleReadResult(result);
568 if (!done_)
569 DoRead(); // Don't try to read again when we are done reading.
570 }
571
572 void HandleReadResult(int result) {
573 if (result <= 0 && result != net::ERR_IO_PENDING) {
574 if (!done_) {
575 LOG(ERROR) << "Received error " << result << " when trying to read";
576 read_errors_++;
577 Done();
578 }
579 } else if (result > 0) {
580 // Allocate memory for the next read.
581 input_buffer_->set_offset(input_buffer_->offset() + result);
582 if (input_buffer_->offset() == test_data_size_)
583 Done();
584 }
585 }
586
587 scoped_refptr<net::DrainableIOBuffer> output_buffer_;
588 scoped_refptr<net::GrowableIOBuffer> input_buffer_;
589
590 net::OldCompletionCallbackImpl<TCPChannelTester> write_cb_;
591 net::OldCompletionCallbackImpl<TCPChannelTester> read_cb_;
592 int write_errors_;
593 int read_errors_;
594 int message_size_;
595 int message_count_;
596 int test_data_size_;
597 };
598
599 class ChannelSpeedTester : public TCPChannelTester {
600 public:
601 ChannelSpeedTester(Session* host_session,
602 Session* client_session,
603 int message_size)
604 : TCPChannelTester(host_session, client_session, message_size, 1) {
605 CHECK(message_size >= 8);
606 }
607
608 virtual ~ChannelSpeedTester() { }
609
610 virtual void CheckResults() {
611 }
612
613 base::TimeDelta GetElapsedTime() {
614 return base::Time::Now() - start_time_;
615 }
616
617 protected:
618 virtual void InitBuffers() {
619 TCPChannelTester::InitBuffers();
620
621 start_time_ = base::Time::Now();
622 }
623
624 base::Time start_time_;
625 };
626
627 class UDPChannelTester : public ChannelTesterBase {
628 public:
629 UDPChannelTester(Session* host_session,
630 Session* client_session)
631 : ChannelTesterBase(host_session, client_session),
632 ALLOW_THIS_IN_INITIALIZER_LIST(
633 write_cb_(this, &UDPChannelTester::OnWritten)),
634 ALLOW_THIS_IN_INITIALIZER_LIST(
635 read_cb_(this, &UDPChannelTester::OnRead)),
636 write_errors_(0),
637 read_errors_(0),
638 packets_sent_(0),
639 packets_received_(0),
640 broken_packets_(0) {
641 }
642
643 virtual ~UDPChannelTester() { }
644
645 virtual void CheckResults() {
646 EXPECT_EQ(0, write_errors_);
647 EXPECT_EQ(0, read_errors_);
648
649 EXPECT_EQ(0, broken_packets_);
650
651 // Verify that we've received at least one packet.
652 EXPECT_GT(packets_received_, 0);
653 LOG(INFO) << "Received " << packets_received_ << " packets out of "
654 << kMessages;
655 }
656
657 protected:
658 virtual void InitChannels() OVERRIDE {
659 host_session_->CreateDatagramChannel(
660 kChannelName,
661 base::Bind(&UDPChannelTester::OnChannelReady,
662 base::Unretained(this), 0));
663 client_session_->CreateDatagramChannel(
664 kChannelName,
665 base::Bind(&UDPChannelTester::OnChannelReady,
666 base::Unretained(this), 1));
667 }
668
669 void OnChannelReady(int id, net::Socket* socket) {
670 ASSERT_TRUE(socket);
671 if (!socket) {
672 Done();
673 return;
674 }
675
676 DCHECK(id >= 0 && id < 2);
677 sockets_[id].reset(socket);
678
679 if (sockets_[0].get() && sockets_[1].get()) {
680 InitBuffers();
681 DoRead();
682 DoWrite();
683 }
684 }
685
686
687 virtual void InitBuffers() {
688 }
689
690 virtual void DoWrite() {
691 if (packets_sent_ >= kMessages) {
692 Done();
693 return;
694 }
695
696 scoped_refptr<net::IOBuffer> packet(new net::IOBuffer(kMessageSize));
697 memset(packet->data(), 123, kMessageSize);
698 sent_packets_[packets_sent_] = packet;
699 // Put index of this packet in the beginning of the packet body.
700 memcpy(packet->data(), &packets_sent_, sizeof(packets_sent_));
701
702 int result = sockets_[0]->Write(packet, kMessageSize, &write_cb_);
703 HandleWriteResult(result);
704 }
705
706 void OnWritten(int result) {
707 HandleWriteResult(result);
708 }
709
710 void HandleWriteResult(int result) {
711 if (result <= 0 && result != net::ERR_IO_PENDING) {
712 LOG(ERROR) << "Received error " << result << " when trying to write";
713 write_errors_++;
714 Done();
715 } else if (result > 0) {
716 EXPECT_EQ(kMessageSize, result);
717 packets_sent_++;
718 MessageLoop::current()->PostDelayedTask(
719 FROM_HERE, base::Bind(&UDPChannelTester::DoWrite, this),
720 kUdpWriteDelayMs);
721 }
722 }
723
724 virtual void DoRead() {
725 int result = 1;
726 while (result > 0) {
727 int kReadSize = kMessageSize * 2;
728 read_buffer_ = new net::IOBuffer(kReadSize);
729
730 result = sockets_[1]->Read(read_buffer_, kReadSize, &read_cb_);
731 HandleReadResult(result);
732 };
733 }
734
735 void OnRead(int result) {
736 HandleReadResult(result);
737 DoRead();
738 }
739
740 void HandleReadResult(int result) {
741 if (result <= 0 && result != net::ERR_IO_PENDING) {
742 // Error will be received after the socket is closed.
743 if (!done_) {
744 LOG(ERROR) << "Received error " << result << " when trying to read";
745 read_errors_++;
746 Done();
747 }
748 } else if (result > 0) {
749 packets_received_++;
750 if (kMessageSize != result) {
751 // Invalid packet size;
752 broken_packets_++;
753 } else {
754 // Validate packet body.
755 int packet_id;
756 memcpy(&packet_id, read_buffer_->data(), sizeof(packet_id));
757 if (packet_id < 0 || packet_id >= kMessages) {
758 broken_packets_++;
759 } else {
760 if (memcmp(read_buffer_->data(), sent_packets_[packet_id]->data(),
761 kMessageSize) != 0)
762 broken_packets_++;
763 }
764 }
765 }
766 }
767
768 private:
769 scoped_refptr<net::IOBuffer> sent_packets_[kMessages];
770 scoped_refptr<net::IOBuffer> read_buffer_;
771
772 net::OldCompletionCallbackImpl<UDPChannelTester> write_cb_;
773 net::OldCompletionCallbackImpl<UDPChannelTester> read_cb_;
774 int write_errors_;
775 int read_errors_;
776 int packets_sent_;
777 int packets_received_;
778 int broken_packets_;
779 };
780 303
781 // Verify that we can create and destory server objects without a connection. 304 // Verify that we can create and destory server objects without a connection.
782 TEST_F(JingleSessionTest, CreateAndDestoy) { 305 TEST_F(JingleSessionTest, CreateAndDestoy) {
783 CreateServerPair(false); 306 CreateServerPair(FakeAuthenticator::ACCEPT, 1);
784 } 307 }
785 308
786 // Verify that incoming session can be rejected, and that the status 309 // Verify that incoming session can be rejected, and that the status
787 // of the connection is set to CLOSED in this case. 310 // of the connection is set to CLOSED in this case.
788 TEST_F(JingleSessionTest, RejectConnection) { 311 TEST_F(JingleSessionTest, RejectConnection) {
789 CreateServerPair(false); 312 CreateServerPair(FakeAuthenticator::ACCEPT, 1);
790 313
791 // Reject incoming session. 314 // Reject incoming session.
792 EXPECT_CALL(host_server_listener_, OnIncomingSession(_, _)) 315 EXPECT_CALL(host_server_listener_, OnIncomingSession(_, _))
793 .WillOnce(SetArgumentPointee<1>(protocol::SessionManager::DECLINE)); 316 .WillOnce(SetArgumentPointee<1>(protocol::SessionManager::DECLINE));
794 317
795 { 318 {
796 InSequence dummy; 319 InSequence dummy;
797 320
798 EXPECT_CALL(client_connection_callback_, 321 EXPECT_CALL(client_connection_callback_,
799 OnStateChange(Session::CONNECTING)) 322 OnStateChange(Session::CONNECTING))
800 .Times(1); 323 .Times(1);
801 EXPECT_CALL(client_connection_callback_, 324 EXPECT_CALL(client_connection_callback_,
802 OnStateChange(Session::CLOSED)) 325 OnStateChange(Session::CLOSED))
803 .Times(1) 326 .Times(1)
804 .WillOnce(InvokeWithoutArgs(&QuitCurrentThread)); 327 .WillOnce(InvokeWithoutArgs(&QuitCurrentThread));
805 } 328 }
806 329
807 Authenticator* authenticator = 330 Authenticator* authenticator = new FakeAuthenticator(
808 new V1ClientAuthenticator(kClientJid, kTestSharedSecretBad); 331 FakeAuthenticator::CLIENT, FakeAuthenticator::ACCEPT, 1);
809 client_session_.reset(client_server_->Connect( 332 client_session_.reset(client_server_->Connect(
810 kHostJid, authenticator, 333 kHostJid, authenticator,
811 CandidateSessionConfig::CreateDefault(), 334 CandidateSessionConfig::CreateDefault(),
812 base::Bind(&MockSessionCallback::OnStateChange, 335 base::Bind(&MockSessionCallback::OnStateChange,
813 base::Unretained(&client_connection_callback_)))); 336 base::Unretained(&client_connection_callback_))));
814 337
815 ASSERT_TRUE(RunMessageLoopWithTimeout(TestTimeouts::action_max_timeout_ms())); 338 ASSERT_TRUE(RunMessageLoopWithTimeout(TestTimeouts::action_max_timeout_ms()));
816 } 339 }
817 340
818 // Verify that we can connect two endpoints. 341 // Verify that we can connect two endpoints.
819 TEST_F(JingleSessionTest, Connect) { 342 TEST_F(JingleSessionTest, Connect) {
820 CreateServerPair(false); 343 CreateServerPair(FakeAuthenticator::ACCEPT, 1);
821 ASSERT_TRUE(InitiateConnection(false)); 344 ASSERT_TRUE(InitiateConnection(FakeAuthenticator::ACCEPT, 1, false));
822 } 345 }
823 346
824 // Verify that we can't connect two endpoints with mismatched secrets. 347 // Verify that we can't connect two endpoints with mismatched secrets.
348 TEST_F(JingleSessionTest, ConnectBadAuth) {
349 CreateServerPair(FakeAuthenticator::REJECT, 1);
350 ASSERT_TRUE(InitiateConnection(FakeAuthenticator::ACCEPT, 1, true));
351 }
352
825 TEST_F(JingleSessionTest, ConnectBadChannelAuth) { 353 TEST_F(JingleSessionTest, ConnectBadChannelAuth) {
826 CreateServerPair(true); 354 CreateServerPair(FakeAuthenticator::REJECT_CHANNEL, 1);
827 ASSERT_TRUE(InitiateConnection(true)); 355 ASSERT_TRUE(InitiateConnection(FakeAuthenticator::ACCEPT, 1, false));
828 scoped_refptr<TCPChannelTester> tester(
829 new TCPChannelTester(host_session_.get(), client_session_.get(),
830 kMessageSize, kMessages));
831 tester->Start();
832 ASSERT_TRUE(tester->WaitFinished());
833 EXPECT_TRUE(tester->did_initialization_fail());
834 356
835 CloseSessions(); 357 MockStreamChannelCallback client_callback;
358 MockStreamChannelCallback host_callback;
359
360 client_session_->CreateStreamChannel(kChannelName, base::Bind(
361 &MockStreamChannelCallback::OnDone,
362 base::Unretained(&client_callback)));
363 host_session_->CreateStreamChannel(kChannelName, base::Bind(
364 &MockStreamChannelCallback::OnDone,
365 base::Unretained(&host_callback)));
366
367 EXPECT_CALL(client_callback, OnDone(_))
368 .Times(AtMost(1))
369 .WillOnce(DeleteArg<0>());
370 EXPECT_CALL(host_callback, OnDone(NULL))
371 .WillOnce(QuitThread());
372
373 message_loop_.Run();
374
375 client_session_->CancelChannelCreation(kChannelName);
376 host_session_->CancelChannelCreation(kChannelName);
836 } 377 }
837 378
838 // Verify that data can be transmitted over the event channel. 379 // Verify that data can be transmitted over the event channel.
839 TEST_F(JingleSessionTest, TestTcpChannel) { 380 TEST_F(JingleSessionTest, TestTcpChannel) {
840 CreateServerPair(false); 381 CreateServerPair(FakeAuthenticator::ACCEPT, 1);
841 ASSERT_TRUE(InitiateConnection(false)); 382 ASSERT_TRUE(InitiateConnection(FakeAuthenticator::ACCEPT, 1, false));
842 scoped_refptr<TCPChannelTester> tester(
843 new TCPChannelTester(host_session_.get(), client_session_.get(),
844 kMessageSize, kMessages));
845 tester->Start();
846 ASSERT_TRUE(tester->WaitFinished());
847 tester->CheckResults();
848 383
849 // Connections must be closed while |tester| still exists. 384 ASSERT_TRUE(CreateChannel());
850 CloseSessions(); 385
386 StreamConnectionTester tester(host_socket_.get(), client_socket_.get(),
387 kMessageSize, kMessages);
388 tester.Start();
389 message_loop_.Run();
390 tester.CheckResults();
851 } 391 }
852 392
853 // Verify that data can be transmitted over the video RTP channel. 393 // Verify that data can be transmitted over the video RTP channel.
854 TEST_F(JingleSessionTest, TestUdpChannel) { 394 TEST_F(JingleSessionTest, TestUdpChannel) {
855 CreateServerPair(false); 395 CreateServerPair(FakeAuthenticator::ACCEPT, 1);
856 ASSERT_TRUE(InitiateConnection(false)); 396 ASSERT_TRUE(InitiateConnection(FakeAuthenticator::ACCEPT, 1, false));
857 scoped_refptr<UDPChannelTester> tester(
858 new UDPChannelTester(host_session_.get(), client_session_.get()));
859 tester->Start();
860 ASSERT_TRUE(tester->WaitFinished());
861 tester->CheckResults();
862 397
863 // Connections must be closed while |tester| still exists. 398 MockDatagramChannelCallback client_callback;
864 CloseSessions(); 399 MockDatagramChannelCallback host_callback;
400
401 int counter = 2;
402 net::Socket* client_socket = NULL;
403 net::Socket* host_socket = NULL;
404 EXPECT_CALL(client_callback, OnDone(_))
405 .WillOnce(DoAll(SaveArg<0>(&client_socket),
406 QuitThreadOnCounter(&counter)));
407 EXPECT_CALL(host_callback, OnDone(_))
408 .WillOnce(DoAll(SaveArg<0>(&host_socket),
409 QuitThreadOnCounter(&counter)));
410
411 client_session_->CreateDatagramChannel(kChannelName, base::Bind(
412 &MockDatagramChannelCallback::OnDone,
413 base::Unretained(&host_callback)));
414 host_session_->CreateDatagramChannel(kChannelName, base::Bind(
415 &MockDatagramChannelCallback::OnDone,
416 base::Unretained(&client_callback)));
417
418 message_loop_.Run();
419
420 scoped_ptr<net::Socket> client_socket_ptr(client_socket);
421 scoped_ptr<net::Socket> host_socket_ptr(host_socket);
422
423 ASSERT_TRUE(client_socket != NULL);
424 ASSERT_TRUE(host_socket != NULL);
425
426 DatagramConnectionTester tester(
427 client_socket, host_socket, kMessageSize, kMessages, kUdpWriteDelayMs);
428 tester.Start();
429 message_loop_.Run();
430 tester.CheckResults();
865 } 431 }
866 432
867 // Send packets of different size to get the latency for sending data 433 // Send packets of different size to get the latency for sending data
868 // using sockets from JingleSession. 434 // using sockets from JingleSession.
869 TEST_F(JingleSessionTest, FLAKY_TestSpeed) { 435 TEST_F(JingleSessionTest, FLAKY_TestSpeed) {
Wez 2011/12/09 23:42:33 I don't think this test belongs in a unit-test; it
Sergey Ulanov 2011/12/12 22:52:00 Removed it from here.
870 CreateServerPair(false); 436 CreateServerPair(FakeAuthenticator::ACCEPT, 1);
871 ASSERT_TRUE(InitiateConnection(false));
872 scoped_refptr<ChannelSpeedTester> tester;
873 437
874 tester = new ChannelSpeedTester(host_session_.get(), 438 RunSpeedTest(512);
875 client_session_.get(), 512); 439 RunSpeedTest(1024);
876 tester->Start(); 440 RunSpeedTest(51200);
877 ASSERT_TRUE(tester->WaitFinished()); 441 RunSpeedTest(512000);
878 LOG(INFO) << "Time for 512 bytes "
879 << tester->GetElapsedTime().InMilliseconds() << " ms.";
880
881 CloseSessions();
882 ASSERT_TRUE(InitiateConnection(false));
883
884 tester = new ChannelSpeedTester(host_session_.get(),
885 client_session_.get(), 1024);
886 tester->Start();
887 ASSERT_TRUE(tester->WaitFinished());
888 LOG(INFO) << "Time for 1024 bytes "
889 << tester->GetElapsedTime().InMilliseconds() << " ms.";
890
891 CloseSessions();
892 ASSERT_TRUE(InitiateConnection(false));
893
894 tester = new ChannelSpeedTester(host_session_.get(),
895 client_session_.get(), 51200);
896 tester->Start();
897 ASSERT_TRUE(tester->WaitFinished());
898 LOG(INFO) << "Time for 50k bytes "
899 << tester->GetElapsedTime().InMilliseconds() << " ms.";
900
901 CloseSessions();
902 ASSERT_TRUE(InitiateConnection(false));
903
904 tester = new ChannelSpeedTester(host_session_.get(),
905 client_session_.get(), 512000);
906 tester->Start();
907 ASSERT_TRUE(tester->WaitFinished());
908 LOG(INFO) << "Time for 500k bytes "
909 << tester->GetElapsedTime().InMilliseconds() << " ms.";
910
911 // Connections must be closed while |tester| still exists.
912 CloseSessions();
913 } 442 }
914 443
915 } // namespace protocol 444 } // namespace protocol
916 } // namespace remoting 445 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698