1 // Copyright (c) 2010 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 "chrome/browser/debugger/devtools_remote_listen_socket_unittest.h" 6 7 #include <fcntl.h> 8 #if defined(OS_POSIX) 9 #include <netinet/in.h> 10 #endif 11 12 #include "base/eintr_wrapper.h" 13 #include "base/test/test_timeouts.h" 14 #include "base/threading/platform_thread.h" 15 #include "net/base/net_util.h" 16 #include "testing/platform_test.h" 17 18 const int DevToolsRemoteListenSocketTester::kTestPort = 9999; 19 20 static const int kReadBufSize = 1024; 21 static const char* kChromeDevToolsHandshake = "ChromeDevToolsHandshake\r\n"; 22 static const char* kSimpleMessagePart1 = 23 "Tool:V8Debugger\r\n" 24 "Destination:2\r"; 25 static const char* kSimpleMessagePart2 = 26 "\n" 27 "Content-Length:0\r\n" 28 "\r\n"; 29 static const char* kTwoMessages = 30 "Tool:DevToolsService\r\n" 31 "Content-Length:300\r\n" 32 "\r\n" 33 "00000000000000000000000000000000000000000000000000" 34 "00000000000000000000000000000000000000000000000000" 35 "00000000000000000000000000000000000000000000000000" 36 "00000000000000000000000000000000000000000000000000" 37 "00000000000000000000000000000000000000000000000000" 38 "00000000000000000000000000000000000000000000000000" 39 "Tool:V8Debugger\r\n" 40 "Destination:1\r\n" 41 "Content-Length:0\r\n" 42 "\r\n"; 43 44 static const int kMaxQueueSize = 20; 45 static const char* kLoopback = "127.0.0.1"; 46 #if defined(OS_POSIX) 47 static const char* kSemaphoreName = "chromium.listen_socket"; 48 #endif 49 50 51 ListenSocketTestAction::ListenSocketTestAction() : action_(ACTION_NONE) {} 52 53 ListenSocketTestAction::ListenSocketTestAction(ActionType action) 54 : action_(action) {} 55 56 ListenSocketTestAction::ListenSocketTestAction(ActionType action, 57 std::string data) 58 : action_(action), 59 data_(data) {} 60 61 ListenSocketTestAction::ListenSocketTestAction( 62 ActionType action, 63 const DevToolsRemoteMessage& message) 64 : action_(action), 65 message_(message) {} 66 67 ListenSocketTestAction::~ListenSocketTestAction() {} 68 69 ListenSocket* DevToolsRemoteListenSocketTester::DoListen() { 70 return DevToolsRemoteListenSocket::Listen(kLoopback, kTestPort, this); 71 } 72 73 DevToolsRemoteListenSocketTester::DevToolsRemoteListenSocketTester() 74 : semaphore_(NULL), 75 thread_(NULL), 76 loop_(NULL), 77 server_(NULL), 78 connection_(NULL), 79 test_socket_(INVALID_SOCKET) { 80 memset(&lock_, 0, sizeof(lock_)); 81 } 82 83 void DevToolsRemoteListenSocketTester::SetUp() { 84 #if defined(OS_WIN) 85 InitializeCriticalSection(&lock_); 86 semaphore_ = CreateSemaphore(NULL, 0, kMaxQueueSize, NULL); 87 server_ = NULL; 88 net::EnsureWinsockInit(); 89 #elif defined(OS_POSIX) 90 ASSERT_EQ(0, pthread_mutex_init(&lock_, NULL)); 91 sem_unlink(kSemaphoreName); 92 semaphore_ = sem_open(kSemaphoreName, O_CREAT, 0, 0); 93 ASSERT_NE(SEM_FAILED, semaphore_); 94 #endif 95 base::Thread::Options options; 96 options.message_loop_type = MessageLoop::TYPE_IO; 97 thread_.reset(new base::Thread("socketio_test")); 98 thread_->StartWithOptions(options); 99 loop_ = static_cast<MessageLoopForIO*>(thread_->message_loop()); 100 101 loop_->PostTask(FROM_HERE, NewRunnableMethod( 102 this, &DevToolsRemoteListenSocketTester::Listen)); 103 104 // verify Listen succeeded 105 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 106 ASSERT_FALSE(server_ == NULL); 107 ASSERT_EQ(ACTION_LISTEN, last_action_.type()); 108 109 // verify the connect/accept and setup test_socket_ 110 test_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 111 ASSERT_NE(INVALID_SOCKET, test_socket_); 112 struct sockaddr_in client; 113 client.sin_family = AF_INET; 114 client.sin_addr.s_addr = inet_addr(kLoopback); 115 client.sin_port = htons(kTestPort); 116 int ret = HANDLE_EINTR(connect(test_socket_, 117 reinterpret_cast<sockaddr*>(&client), 118 sizeof(client))); 119 ASSERT_NE(ret, SOCKET_ERROR); 120 121 net::SetNonBlocking(test_socket_); 122 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 123 ASSERT_EQ(ACTION_ACCEPT, last_action_.type()); 124 } 125 126 void DevToolsRemoteListenSocketTester::TearDown() { 127 // verify close 128 #if defined(OS_WIN) 129 closesocket(test_socket_); 130 #elif defined(OS_POSIX) 131 int ret = HANDLE_EINTR(close(test_socket_)); 132 ASSERT_EQ(ret, 0); 133 #endif 134 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 135 ASSERT_EQ(ACTION_CLOSE, last_action_.type()); 136 137 loop_->PostTask(FROM_HERE, NewRunnableMethod( 138 this, &DevToolsRemoteListenSocketTester::Shutdown)); 139 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 140 ASSERT_EQ(ACTION_SHUTDOWN, last_action_.type()); 141 142 #if defined(OS_WIN) 143 CloseHandle(semaphore_); 144 semaphore_ = 0; 145 DeleteCriticalSection(&lock_); 146 #elif defined(OS_POSIX) 147 ASSERT_EQ(0, pthread_mutex_lock(&lock_)); 148 semaphore_ = NULL; 149 ASSERT_EQ(0, pthread_mutex_unlock(&lock_)); 150 ASSERT_EQ(0, sem_unlink(kSemaphoreName)); 151 ASSERT_EQ(0, pthread_mutex_destroy(&lock_)); 152 #endif 153 154 thread_.reset(); 155 loop_ = NULL; 156 } 157 158 void DevToolsRemoteListenSocketTester::ReportAction( 159 const ListenSocketTestAction& action) { 160 #if defined(OS_WIN) 161 EnterCriticalSection(&lock_); 162 queue_.push_back(action); 163 LeaveCriticalSection(&lock_); 164 ReleaseSemaphore(semaphore_, 1, NULL); 165 #elif defined(OS_POSIX) 166 ASSERT_EQ(0, pthread_mutex_lock(&lock_)); 167 queue_.push_back(action); 168 ASSERT_EQ(0, pthread_mutex_unlock(&lock_)); 169 ASSERT_EQ(0, sem_post(semaphore_)); 170 #endif 171 } 172 173 bool DevToolsRemoteListenSocketTester::NextAction(int timeout) { 174 #if defined(OS_WIN) 175 DWORD ret = ::WaitForSingleObject(semaphore_, timeout); 176 if (ret != WAIT_OBJECT_0) 177 return false; 178 EnterCriticalSection(&lock_); 179 if (queue_.empty()) { 180 LeaveCriticalSection(&lock_); 181 return false; 182 } 183 last_action_ = queue_.front(); 184 queue_.pop_front(); 185 LeaveCriticalSection(&lock_); 186 return true; 187 #elif defined(OS_POSIX) 188 if (semaphore_ == SEM_FAILED) 189 return false; 190 while (true) { 191 int result = sem_trywait(semaphore_); 192 base::PlatformThread::Sleep(1); // 1MS sleep 193 timeout--; 194 if (timeout <= 0) 195 return false; 196 if (result == 0) 197 break; 198 } 199 pthread_mutex_lock(&lock_); 200 if (queue_.empty()) { 201 pthread_mutex_unlock(&lock_); 202 return false; 203 } 204 last_action_ = queue_.front(); 205 queue_.pop_front(); 206 pthread_mutex_unlock(&lock_); 207 return true; 208 #endif 209 } 210 211 int DevToolsRemoteListenSocketTester::ClearTestSocket() { 212 char buf[kReadBufSize]; 213 int len_ret = 0; 214 int time_out = 0; 215 do { 216 int len = HANDLE_EINTR(recv(test_socket_, buf, kReadBufSize, 0)); 217 #if defined(OS_WIN) 218 if (len == SOCKET_ERROR) { 219 int err = WSAGetLastError(); 220 if (err == WSAEWOULDBLOCK) { 221 #elif defined(OS_POSIX) 222 if (len == SOCKET_ERROR) { 223 if (errno == EWOULDBLOCK || errno == EAGAIN) { 224 #endif 225 base::PlatformThread::Sleep(1); 226 time_out++; 227 if (time_out > 10) 228 break; 229 continue; // still trying 230 } 231 } else if (len == 0) { 232 // socket closed 233 break; 234 } else { 235 time_out = 0; 236 len_ret += len; 237 } 238 } while (true); 239 return len_ret; 240 } 241 242 void DevToolsRemoteListenSocketTester::Shutdown() { 243 server_->Release(); 244 server_ = NULL; 245 ReportAction(ListenSocketTestAction(ACTION_SHUTDOWN)); 246 } 247 248 void DevToolsRemoteListenSocketTester::Listen() { 249 server_ = DoListen(); 250 server_->AddRef(); 251 ReportAction(ListenSocketTestAction(ACTION_LISTEN)); 252 } 253 254 void DevToolsRemoteListenSocketTester::SendFromTester() { 255 connection_->Send(kChromeDevToolsHandshake); 256 ReportAction(ListenSocketTestAction(ACTION_SEND)); 257 } 258 259 void DevToolsRemoteListenSocketTester::OnAcceptConnection( 260 ListenSocket* connection) { 261 connection_ = connection; 262 ReportAction(ListenSocketTestAction(ACTION_ACCEPT)); 263 } 264 265 void DevToolsRemoteListenSocketTester::OnConnectionLost() { 266 connection_ = NULL; 267 ReportAction(ListenSocketTestAction(ACTION_CLOSE)); 268 } 269 270 void DevToolsRemoteListenSocketTester::HandleMessage( 271 const DevToolsRemoteMessage& message) { 272 ReportAction(ListenSocketTestAction(ACTION_READ_MESSAGE, message)); 273 } 274 275 bool DevToolsRemoteListenSocketTester::Send(SOCKET sock, 276 const std::string& str) { 277 int len = static_cast<int>(str.length()); 278 int send_len = HANDLE_EINTR(send(sock, str.data(), len, 0)); 279 if (send_len == SOCKET_ERROR) { 280 LOG(ERROR) << "send failed: " << errno; 281 return false; 282 } else if (send_len != len) { 283 return false; 284 } 285 return true; 286 } 287 288 void DevToolsRemoteListenSocketTester::TestClientSend() { 289 ASSERT_TRUE(Send(test_socket_, kChromeDevToolsHandshake)); 290 { 291 ASSERT_TRUE(Send(test_socket_, kSimpleMessagePart1)); 292 // sleep for 10ms to test message split between \r and \n 293 base::PlatformThread::Sleep(10); 294 ASSERT_TRUE(Send(test_socket_, kSimpleMessagePart2)); 295 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 296 ASSERT_EQ(ACTION_READ_MESSAGE, last_action_.type()); 297 const DevToolsRemoteMessage& message = last_action_.message(); 298 ASSERT_STREQ("V8Debugger", message.GetHeaderWithEmptyDefault( 299 DevToolsRemoteMessageHeaders::kTool).c_str()); 300 ASSERT_STREQ("2", message.GetHeaderWithEmptyDefault( 301 DevToolsRemoteMessageHeaders::kDestination).c_str()); 302 ASSERT_STREQ("0", message.GetHeaderWithEmptyDefault( 303 DevToolsRemoteMessageHeaders::kContentLength).c_str()); 304 ASSERT_EQ(0, static_cast<int>(message.content().size())); 305 } 306 ASSERT_TRUE(Send(test_socket_, kTwoMessages)); 307 { 308 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 309 ASSERT_EQ(ACTION_READ_MESSAGE, last_action_.type()); 310 const DevToolsRemoteMessage& message = last_action_.message(); 311 ASSERT_STREQ("DevToolsService", message.tool().c_str()); 312 ASSERT_STREQ("", message.destination().c_str()); 313 ASSERT_EQ(300, message.content_length()); 314 const std::string& content = message.content(); 315 ASSERT_EQ(300, static_cast<int>(content.size())); 316 for (int i = 0; i < 300; ++i) { 317 ASSERT_EQ('0', content[i]); 318 } 319 } 320 { 321 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 322 ASSERT_EQ(ACTION_READ_MESSAGE, last_action_.type()); 323 const DevToolsRemoteMessage& message = last_action_.message(); 324 ASSERT_STREQ("V8Debugger", message.GetHeaderWithEmptyDefault( 325 DevToolsRemoteMessageHeaders::kTool).c_str()); 326 ASSERT_STREQ("1", message.GetHeaderWithEmptyDefault( 327 DevToolsRemoteMessageHeaders::kDestination).c_str()); 328 ASSERT_STREQ("0", message.GetHeaderWithEmptyDefault( 329 DevToolsRemoteMessageHeaders::kContentLength).c_str()); 330 const std::string& content = message.content(); 331 ASSERT_EQ(0, static_cast<int>(content.size())); 332 } 333 } 334 335 void DevToolsRemoteListenSocketTester::TestServerSend() { 336 loop_->PostTask(FROM_HERE, NewRunnableMethod( 337 this, &DevToolsRemoteListenSocketTester::SendFromTester)); 338 ASSERT_TRUE(NextAction(TestTimeouts::action_timeout_ms())); 339 ASSERT_EQ(ACTION_SEND, last_action_.type()); 340 // TODO(erikkay): Without this sleep, the recv seems to fail a small amount 341 // of the time. I could fix this by making the socket blocking, but then 342 // this test might hang in the case of errors. It would be nice to do 343 // something that felt more reliable here. 344 base::PlatformThread::Sleep(10); // sleep for 10ms 345 const int buf_len = 200; 346 char buf[buf_len+1]; 347 int recv_len = HANDLE_EINTR(recv(test_socket_, buf, buf_len, 0)); 348 ASSERT_NE(recv_len, SOCKET_ERROR); 349 buf[recv_len] = 0; 350 ASSERT_STREQ(buf, kChromeDevToolsHandshake); 351 } 352 353 DevToolsRemoteListenSocketTester::~DevToolsRemoteListenSocketTester() {} 354 355 class DevToolsRemoteListenSocketTest: public PlatformTest { 356 public: 357 DevToolsRemoteListenSocketTest() { 358 tester_ = NULL; 359 } 360 361 virtual void SetUp() { 362 PlatformTest::SetUp(); 363 tester_ = new DevToolsRemoteListenSocketTester(); 364 tester_->SetUp(); 365 } 366 367 virtual void TearDown() { 368 PlatformTest::TearDown(); 369 tester_->TearDown(); 370 tester_ = NULL; 371 } 372 373 scoped_refptr<DevToolsRemoteListenSocketTester> tester_; 374 }; 375 376 // This test is flaky; see comment in ::TestServerSend. 377 TEST_F(DevToolsRemoteListenSocketTest, ServerSend) { 378 tester_->TestServerSend(); 379 } 380 381 TEST_F(DevToolsRemoteListenSocketTest, ClientSend) { 382 tester_->TestClientSend(); 383 } 384