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 // These tests are POSIX only. 6 7 #include "ipc/ipc_channel_posix.h" 8 9 #include <fcntl.h> 10 #include <sys/socket.h> 11 #include <sys/un.h> 12 #include <unistd.h> 13 14 #include "base/basictypes.h" 15 #include "base/file_util.h" 16 #include "base/files/file_path.h" 17 #include "base/memory/scoped_ptr.h" 18 #include "base/message_loop/message_loop.h" 19 #include "base/path_service.h" 20 #include "base/posix/eintr_wrapper.h" 21 #include "base/process/kill.h" 22 #include "base/test/multiprocess_test.h" 23 #include "base/test/test_timeouts.h" 24 #include "ipc/ipc_listener.h" 25 #include "ipc/unix_domain_socket_util.h" 26 #include "testing/multiprocess_func_list.h" 27 28 namespace { 29 30 static const uint32 kQuitMessage = 47; 31 32 class IPCChannelPosixTestListener : public IPC::Listener { 33 public: 34 enum STATUS { 35 DISCONNECTED, 36 MESSAGE_RECEIVED, 37 CHANNEL_ERROR, 38 CONNECTED, 39 DENIED, 40 LISTEN_ERROR 41 }; 42 43 IPCChannelPosixTestListener(bool quit_only_on_message) 44 : status_(DISCONNECTED), 45 quit_only_on_message_(quit_only_on_message) { 46 } 47 48 virtual ~IPCChannelPosixTestListener() {} 49 50 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 51 EXPECT_EQ(message.type(), kQuitMessage); 52 status_ = MESSAGE_RECEIVED; 53 QuitRunLoop(); 54 return true; 55 } 56 57 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE { 58 status_ = CONNECTED; 59 if (!quit_only_on_message_) { 60 QuitRunLoop(); 61 } 62 } 63 64 virtual void OnChannelError() OVERRIDE { 65 status_ = CHANNEL_ERROR; 66 QuitRunLoop(); 67 } 68 69 virtual void OnChannelDenied() OVERRIDE { 70 status_ = DENIED; 71 if (!quit_only_on_message_) { 72 QuitRunLoop(); 73 } 74 } 75 76 virtual void OnChannelListenError() OVERRIDE { 77 status_ = LISTEN_ERROR; 78 if (!quit_only_on_message_) { 79 QuitRunLoop(); 80 } 81 } 82 83 STATUS status() { return status_; } 84 85 void QuitRunLoop() { 86 base::MessageLoopForIO* loop = base::MessageLoopForIO::current(); 87 if (loop->is_running()) { 88 loop->QuitNow(); 89 } else { 90 // Die as soon as Run is called. 91 loop->PostTask(FROM_HERE, loop->QuitClosure()); 92 } 93 } 94 95 private: 96 // The current status of the listener. 97 STATUS status_; 98 // If |quit_only_on_message_| then the listener will only break out of 99 // the run loop when kQuitMessage is received. 100 bool quit_only_on_message_; 101 }; 102 103 class IPCChannelPosixTest : public base::MultiProcessTest { 104 public: 105 static void SetUpSocket(IPC::ChannelHandle *handle, 106 IPC::Channel::Mode mode); 107 static void SpinRunLoop(base::TimeDelta delay); 108 static const std::string GetConnectionSocketName(); 109 static const std::string GetChannelDirName(); 110 111 protected: 112 virtual void SetUp(); 113 virtual void TearDown(); 114 115 private: 116 scoped_ptr<base::MessageLoopForIO> message_loop_; 117 }; 118 119 const std::string IPCChannelPosixTest::GetChannelDirName() { 120 #if defined(OS_ANDROID) 121 base::FilePath tmp_dir; 122 PathService::Get(base::DIR_CACHE, &tmp_dir); 123 return tmp_dir.value(); 124 #else 125 return "/var/tmp"; 126 #endif 127 } 128 129 const std::string IPCChannelPosixTest::GetConnectionSocketName() { 130 return GetChannelDirName() + "/chrome_IPCChannelPosixTest__ConnectionSocket"; 131 } 132 133 void IPCChannelPosixTest::SetUp() { 134 MultiProcessTest::SetUp(); 135 // Construct a fresh IO Message loop for the duration of each test. 136 message_loop_.reset(new base::MessageLoopForIO()); 137 } 138 139 void IPCChannelPosixTest::TearDown() { 140 message_loop_.reset(NULL); 141 MultiProcessTest::TearDown(); 142 } 143 144 // Create up a socket and bind and listen to it, or connect it 145 // depending on the |mode|. 146 void IPCChannelPosixTest::SetUpSocket(IPC::ChannelHandle *handle, 147 IPC::Channel::Mode mode) { 148 const std::string& name = handle->name; 149 150 int socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); 151 ASSERT_GE(socket_fd, 0) << name; 152 ASSERT_GE(fcntl(socket_fd, F_SETFL, O_NONBLOCK), 0); 153 struct sockaddr_un server_address = { 0 }; 154 memset(&server_address, 0, sizeof(server_address)); 155 server_address.sun_family = AF_UNIX; 156 int path_len = snprintf(server_address.sun_path, IPC::kMaxSocketNameLength, 157 "%s", name.c_str()); 158 DCHECK_EQ(static_cast<int>(name.length()), path_len); 159 size_t server_address_len = offsetof(struct sockaddr_un, 160 sun_path) + path_len + 1; 161 162 if (mode == IPC::Channel::MODE_NAMED_SERVER) { 163 // Only one server at a time. Cleanup garbage if it exists. 164 unlink(name.c_str()); 165 // Make sure the path we need exists. 166 base::FilePath path(name); 167 base::FilePath dir_path = path.DirName(); 168 ASSERT_TRUE(base::CreateDirectory(dir_path)); 169 ASSERT_GE(bind(socket_fd, 170 reinterpret_cast<struct sockaddr *>(&server_address), 171 server_address_len), 0) << server_address.sun_path 172 << ": " << strerror(errno) 173 << "(" << errno << ")"; 174 ASSERT_GE(listen(socket_fd, SOMAXCONN), 0) << server_address.sun_path 175 << ": " << strerror(errno) 176 << "(" << errno << ")"; 177 } else if (mode == IPC::Channel::MODE_NAMED_CLIENT) { 178 ASSERT_GE(connect(socket_fd, 179 reinterpret_cast<struct sockaddr *>(&server_address), 180 server_address_len), 0) << server_address.sun_path 181 << ": " << strerror(errno) 182 << "(" << errno << ")"; 183 } else { 184 FAIL() << "Unknown mode " << mode; 185 } 186 handle->socket.fd = socket_fd; 187 } 188 189 void IPCChannelPosixTest::SpinRunLoop(base::TimeDelta delay) { 190 base::MessageLoopForIO* loop = base::MessageLoopForIO::current(); 191 // Post a quit task so that this loop eventually ends and we don't hang 192 // in the case of a bad test. Usually, the run loop will quit sooner than 193 // that because all tests use a IPCChannelPosixTestListener which quits the 194 // current run loop on any channel activity. 195 loop->PostDelayedTask(FROM_HERE, loop->QuitClosure(), delay); 196 loop->Run(); 197 } 198 199 TEST_F(IPCChannelPosixTest, BasicListen) { 200 const std::string kChannelName = 201 GetChannelDirName() + "/IPCChannelPosixTest_BasicListen"; 202 203 // Test creating a socket that is listening. 204 IPC::ChannelHandle handle(kChannelName); 205 SetUpSocket(&handle, IPC::Channel::MODE_NAMED_SERVER); 206 unlink(handle.name.c_str()); 207 scoped_ptr<IPC::ChannelPosix> channel( 208 new IPC::ChannelPosix(handle, IPC::Channel::MODE_NAMED_SERVER, NULL)); 209 ASSERT_TRUE(channel->Connect()); 210 ASSERT_TRUE(channel->AcceptsConnections()); 211 ASSERT_FALSE(channel->HasAcceptedConnection()); 212 channel->ResetToAcceptingConnectionState(); 213 ASSERT_FALSE(channel->HasAcceptedConnection()); 214 } 215 216 TEST_F(IPCChannelPosixTest, BasicConnected) { 217 // Test creating a socket that is connected. 218 int pipe_fds[2]; 219 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds)); 220 std::string socket_name("/var/tmp/IPCChannelPosixTest_BasicConnected"); 221 ASSERT_GE(fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK), 0); 222 223 base::FileDescriptor fd(pipe_fds[0], false); 224 IPC::ChannelHandle handle(socket_name, fd); 225 scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix( 226 handle, IPC::Channel::MODE_SERVER, NULL)); 227 ASSERT_TRUE(channel->Connect()); 228 ASSERT_FALSE(channel->AcceptsConnections()); 229 channel->Close(); 230 ASSERT_TRUE(IGNORE_EINTR(close(pipe_fds[1])) == 0); 231 232 // Make sure that we can use the socket that is created for us by 233 // a standard channel. 234 scoped_ptr<IPC::ChannelPosix> channel2(new IPC::ChannelPosix( 235 socket_name, IPC::Channel::MODE_SERVER, NULL)); 236 ASSERT_TRUE(channel2->Connect()); 237 ASSERT_FALSE(channel2->AcceptsConnections()); 238 } 239 240 // If a connection closes right before a Send() call, we may end up closing 241 // the connection without notifying the listener, which can cause hangs in 242 // sync_message_filter and others. Make sure the listener is notified. 243 TEST_F(IPCChannelPosixTest, SendHangTest) { 244 IPCChannelPosixTestListener out_listener(true); 245 IPCChannelPosixTestListener in_listener(true); 246 IPC::ChannelHandle in_handle("IN"); 247 scoped_ptr<IPC::ChannelPosix> in_chan(new IPC::ChannelPosix( 248 in_handle, IPC::Channel::MODE_SERVER, &in_listener)); 249 base::FileDescriptor out_fd( 250 in_chan->TakeClientFileDescriptor(), false); 251 IPC::ChannelHandle out_handle("OUT", out_fd); 252 scoped_ptr<IPC::ChannelPosix> out_chan(new IPC::ChannelPosix( 253 out_handle, IPC::Channel::MODE_CLIENT, &out_listener)); 254 ASSERT_TRUE(in_chan->Connect()); 255 ASSERT_TRUE(out_chan->Connect()); 256 in_chan->Close(); // simulate remote process dying at an unfortunate time. 257 // Send will fail, because it cannot write the message. 258 ASSERT_FALSE(out_chan->Send(new IPC::Message( 259 0, // routing_id 260 kQuitMessage, // message type 261 IPC::Message::PRIORITY_NORMAL))); 262 SpinRunLoop(TestTimeouts::action_max_timeout()); 263 ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, out_listener.status()); 264 } 265 266 // If a connection closes right before a Connect() call, we may end up closing 267 // the connection without notifying the listener, which can cause hangs in 268 // sync_message_filter and others. Make sure the listener is notified. 269 TEST_F(IPCChannelPosixTest, AcceptHangTest) { 270 IPCChannelPosixTestListener out_listener(true); 271 IPCChannelPosixTestListener in_listener(true); 272 IPC::ChannelHandle in_handle("IN"); 273 scoped_ptr<IPC::ChannelPosix> in_chan(new IPC::ChannelPosix( 274 in_handle, IPC::Channel::MODE_SERVER, &in_listener)); 275 base::FileDescriptor out_fd( 276 in_chan->TakeClientFileDescriptor(), false); 277 IPC::ChannelHandle out_handle("OUT", out_fd); 278 scoped_ptr<IPC::ChannelPosix> out_chan(new IPC::ChannelPosix( 279 out_handle, IPC::Channel::MODE_CLIENT, &out_listener)); 280 ASSERT_TRUE(in_chan->Connect()); 281 in_chan->Close(); // simulate remote process dying at an unfortunate time. 282 ASSERT_FALSE(out_chan->Connect()); 283 SpinRunLoop(TestTimeouts::action_max_timeout()); 284 ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, out_listener.status()); 285 } 286 287 TEST_F(IPCChannelPosixTest, AdvancedConnected) { 288 // Test creating a connection to an external process. 289 IPCChannelPosixTestListener listener(false); 290 IPC::ChannelHandle chan_handle(GetConnectionSocketName()); 291 SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER); 292 scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix( 293 chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener)); 294 ASSERT_TRUE(channel->Connect()); 295 ASSERT_TRUE(channel->AcceptsConnections()); 296 ASSERT_FALSE(channel->HasAcceptedConnection()); 297 298 base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc"); 299 ASSERT_TRUE(handle); 300 SpinRunLoop(TestTimeouts::action_max_timeout()); 301 ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status()); 302 ASSERT_TRUE(channel->HasAcceptedConnection()); 303 IPC::Message* message = new IPC::Message(0, // routing_id 304 kQuitMessage, // message type 305 IPC::Message::PRIORITY_NORMAL); 306 channel->Send(message); 307 SpinRunLoop(TestTimeouts::action_timeout()); 308 int exit_code = 0; 309 EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code)); 310 EXPECT_EQ(0, exit_code); 311 ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status()); 312 ASSERT_FALSE(channel->HasAcceptedConnection()); 313 } 314 315 TEST_F(IPCChannelPosixTest, ResetState) { 316 // Test creating a connection to an external process. Close the connection, 317 // but continue to listen and make sure another external process can connect 318 // to us. 319 IPCChannelPosixTestListener listener(false); 320 IPC::ChannelHandle chan_handle(GetConnectionSocketName()); 321 SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER); 322 scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix( 323 chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener)); 324 ASSERT_TRUE(channel->Connect()); 325 ASSERT_TRUE(channel->AcceptsConnections()); 326 ASSERT_FALSE(channel->HasAcceptedConnection()); 327 328 base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc"); 329 ASSERT_TRUE(handle); 330 SpinRunLoop(TestTimeouts::action_max_timeout()); 331 ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status()); 332 ASSERT_TRUE(channel->HasAcceptedConnection()); 333 channel->ResetToAcceptingConnectionState(); 334 ASSERT_FALSE(channel->HasAcceptedConnection()); 335 336 base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixTestConnectionProc"); 337 ASSERT_TRUE(handle2); 338 SpinRunLoop(TestTimeouts::action_max_timeout()); 339 ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status()); 340 ASSERT_TRUE(channel->HasAcceptedConnection()); 341 IPC::Message* message = new IPC::Message(0, // routing_id 342 kQuitMessage, // message type 343 IPC::Message::PRIORITY_NORMAL); 344 channel->Send(message); 345 SpinRunLoop(TestTimeouts::action_timeout()); 346 EXPECT_TRUE(base::KillProcess(handle, 0, false)); 347 int exit_code = 0; 348 EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code)); 349 EXPECT_EQ(0, exit_code); 350 ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status()); 351 ASSERT_FALSE(channel->HasAcceptedConnection()); 352 } 353 354 TEST_F(IPCChannelPosixTest, BadChannelName) { 355 // Test empty name 356 IPC::ChannelHandle handle(""); 357 scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix( 358 handle, IPC::Channel::MODE_NAMED_SERVER, NULL)); 359 ASSERT_FALSE(channel->Connect()); 360 361 // Test name that is too long. 362 const char *kTooLongName = "This_is_a_very_long_name_to_proactively_implement" 363 "client-centered_synergy_through_top-line" 364 "platforms_Phosfluorescently_disintermediate_" 365 "clicks-and-mortar_best_practices_without_" 366 "future-proof_growth_strategies_Continually" 367 "pontificate_proactive_potentialities_before" 368 "leading-edge_processes"; 369 EXPECT_GE(strlen(kTooLongName), IPC::kMaxSocketNameLength); 370 IPC::ChannelHandle handle2(kTooLongName); 371 scoped_ptr<IPC::ChannelPosix> channel2(new IPC::ChannelPosix( 372 handle2, IPC::Channel::MODE_NAMED_SERVER, NULL)); 373 EXPECT_FALSE(channel2->Connect()); 374 } 375 376 TEST_F(IPCChannelPosixTest, MultiConnection) { 377 // Test setting up a connection to an external process, and then have 378 // another external process attempt to connect to us. 379 IPCChannelPosixTestListener listener(false); 380 IPC::ChannelHandle chan_handle(GetConnectionSocketName()); 381 SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER); 382 scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix( 383 chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener)); 384 ASSERT_TRUE(channel->Connect()); 385 ASSERT_TRUE(channel->AcceptsConnections()); 386 ASSERT_FALSE(channel->HasAcceptedConnection()); 387 388 base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc"); 389 ASSERT_TRUE(handle); 390 SpinRunLoop(TestTimeouts::action_max_timeout()); 391 ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status()); 392 ASSERT_TRUE(channel->HasAcceptedConnection()); 393 base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixFailConnectionProc"); 394 ASSERT_TRUE(handle2); 395 SpinRunLoop(TestTimeouts::action_max_timeout()); 396 int exit_code = 0; 397 EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code)); 398 EXPECT_EQ(exit_code, 0); 399 ASSERT_EQ(IPCChannelPosixTestListener::DENIED, listener.status()); 400 ASSERT_TRUE(channel->HasAcceptedConnection()); 401 IPC::Message* message = new IPC::Message(0, // routing_id 402 kQuitMessage, // message type 403 IPC::Message::PRIORITY_NORMAL); 404 channel->Send(message); 405 SpinRunLoop(TestTimeouts::action_timeout()); 406 EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code)); 407 EXPECT_EQ(exit_code, 0); 408 ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status()); 409 ASSERT_FALSE(channel->HasAcceptedConnection()); 410 } 411 412 TEST_F(IPCChannelPosixTest, DoubleServer) { 413 // Test setting up two servers with the same name. 414 IPCChannelPosixTestListener listener(false); 415 IPCChannelPosixTestListener listener2(false); 416 IPC::ChannelHandle chan_handle(GetConnectionSocketName()); 417 scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix( 418 chan_handle, IPC::Channel::MODE_SERVER, &listener)); 419 scoped_ptr<IPC::ChannelPosix> channel2(new IPC::ChannelPosix( 420 chan_handle, IPC::Channel::MODE_SERVER, &listener2)); 421 ASSERT_TRUE(channel->Connect()); 422 ASSERT_FALSE(channel2->Connect()); 423 } 424 425 TEST_F(IPCChannelPosixTest, BadMode) { 426 // Test setting up two servers with a bad mode. 427 IPCChannelPosixTestListener listener(false); 428 IPC::ChannelHandle chan_handle(GetConnectionSocketName()); 429 scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix( 430 chan_handle, IPC::Channel::MODE_NONE, &listener)); 431 ASSERT_FALSE(channel->Connect()); 432 } 433 434 TEST_F(IPCChannelPosixTest, IsNamedServerInitialized) { 435 const std::string& connection_socket_name = GetConnectionSocketName(); 436 IPCChannelPosixTestListener listener(false); 437 IPC::ChannelHandle chan_handle(connection_socket_name); 438 ASSERT_TRUE(base::DeleteFile(base::FilePath(connection_socket_name), false)); 439 ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized( 440 connection_socket_name)); 441 scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix( 442 chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener)); 443 ASSERT_TRUE(IPC::Channel::IsNamedServerInitialized( 444 connection_socket_name)); 445 channel->Close(); 446 ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized( 447 connection_socket_name)); 448 } 449 450 // A long running process that connects to us 451 MULTIPROCESS_TEST_MAIN(IPCChannelPosixTestConnectionProc) { 452 base::MessageLoopForIO message_loop; 453 IPCChannelPosixTestListener listener(true); 454 IPC::ChannelHandle handle(IPCChannelPosixTest::GetConnectionSocketName()); 455 IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT); 456 scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix( 457 handle, IPC::Channel::MODE_NAMED_CLIENT, &listener)); 458 EXPECT_TRUE(channel->Connect()); 459 IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout()); 460 EXPECT_EQ(IPCChannelPosixTestListener::MESSAGE_RECEIVED, listener.status()); 461 return 0; 462 } 463 464 // Simple external process that shouldn't be able to connect to us. 465 MULTIPROCESS_TEST_MAIN(IPCChannelPosixFailConnectionProc) { 466 base::MessageLoopForIO message_loop; 467 IPCChannelPosixTestListener listener(false); 468 IPC::ChannelHandle handle(IPCChannelPosixTest::GetConnectionSocketName()); 469 IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT); 470 scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix( 471 handle, IPC::Channel::MODE_NAMED_CLIENT, &listener)); 472 473 // In this case connect may succeed or fail depending on if the packet 474 // actually gets sent at sendmsg. Since we never delay on send, we may not 475 // see the error. However even if connect succeeds, eventually we will get an 476 // error back since the channel will be closed when we attempt to read from 477 // it. 478 bool connected = channel->Connect(); 479 if (connected) { 480 IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout()); 481 EXPECT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status()); 482 } else { 483 EXPECT_EQ(IPCChannelPosixTestListener::DISCONNECTED, listener.status()); 484 } 485 return 0; 486 } 487 488 } // namespace 489