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), quit_only_on_message_(quit_only_on_message) {} 45 46 virtual ~IPCChannelPosixTestListener() {} 47 48 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 49 EXPECT_EQ(message.type(), kQuitMessage); 50 status_ = MESSAGE_RECEIVED; 51 QuitRunLoop(); 52 return true; 53 } 54 55 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE { 56 status_ = CONNECTED; 57 if (!quit_only_on_message_) { 58 QuitRunLoop(); 59 } 60 } 61 62 virtual void OnChannelError() OVERRIDE { 63 status_ = CHANNEL_ERROR; 64 if (!quit_only_on_message_) { 65 QuitRunLoop(); 66 } 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::current()->QuitNow(); 87 } 88 89 private: 90 // The current status of the listener. 91 STATUS status_; 92 // If |quit_only_on_message_| then the listener will only break out of 93 // the run loop when kQuitMessage is received. 94 bool quit_only_on_message_; 95 }; 96 97 class IPCChannelPosixTest : public base::MultiProcessTest { 98 public: 99 static void SetUpSocket(IPC::ChannelHandle *handle, 100 IPC::Channel::Mode mode); 101 static void SpinRunLoop(base::TimeDelta delay); 102 static const std::string GetConnectionSocketName(); 103 static const std::string GetChannelDirName(); 104 105 protected: 106 virtual void SetUp(); 107 virtual void TearDown(); 108 109 private: 110 scoped_ptr<base::MessageLoopForIO> message_loop_; 111 }; 112 113 const std::string IPCChannelPosixTest::GetChannelDirName() { 114 #if defined(OS_ANDROID) 115 base::FilePath tmp_dir; 116 PathService::Get(base::DIR_CACHE, &tmp_dir); 117 return tmp_dir.value(); 118 #else 119 return "/var/tmp"; 120 #endif 121 } 122 123 const std::string IPCChannelPosixTest::GetConnectionSocketName() { 124 return GetChannelDirName() + "/chrome_IPCChannelPosixTest__ConnectionSocket"; 125 } 126 127 void IPCChannelPosixTest::SetUp() { 128 MultiProcessTest::SetUp(); 129 // Construct a fresh IO Message loop for the duration of each test. 130 message_loop_.reset(new base::MessageLoopForIO()); 131 } 132 133 void IPCChannelPosixTest::TearDown() { 134 message_loop_.reset(NULL); 135 MultiProcessTest::TearDown(); 136 } 137 138 // Create up a socket and bind and listen to it, or connect it 139 // depending on the |mode|. 140 void IPCChannelPosixTest::SetUpSocket(IPC::ChannelHandle *handle, 141 IPC::Channel::Mode mode) { 142 const std::string& name = handle->name; 143 144 int socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); 145 ASSERT_GE(socket_fd, 0) << name; 146 ASSERT_GE(fcntl(socket_fd, F_SETFL, O_NONBLOCK), 0); 147 struct sockaddr_un server_address = { 0 }; 148 memset(&server_address, 0, sizeof(server_address)); 149 server_address.sun_family = AF_UNIX; 150 int path_len = snprintf(server_address.sun_path, IPC::kMaxSocketNameLength, 151 "%s", name.c_str()); 152 DCHECK_EQ(static_cast<int>(name.length()), path_len); 153 size_t server_address_len = offsetof(struct sockaddr_un, 154 sun_path) + path_len + 1; 155 156 if (mode == IPC::Channel::MODE_NAMED_SERVER) { 157 // Only one server at a time. Cleanup garbage if it exists. 158 unlink(name.c_str()); 159 // Make sure the path we need exists. 160 base::FilePath path(name); 161 base::FilePath dir_path = path.DirName(); 162 ASSERT_TRUE(base::CreateDirectory(dir_path)); 163 ASSERT_GE(bind(socket_fd, 164 reinterpret_cast<struct sockaddr *>(&server_address), 165 server_address_len), 0) << server_address.sun_path 166 << ": " << strerror(errno) 167 << "(" << errno << ")"; 168 ASSERT_GE(listen(socket_fd, SOMAXCONN), 0) << server_address.sun_path 169 << ": " << strerror(errno) 170 << "(" << errno << ")"; 171 } else if (mode == IPC::Channel::MODE_NAMED_CLIENT) { 172 ASSERT_GE(connect(socket_fd, 173 reinterpret_cast<struct sockaddr *>(&server_address), 174 server_address_len), 0) << server_address.sun_path 175 << ": " << strerror(errno) 176 << "(" << errno << ")"; 177 } else { 178 FAIL() << "Unknown mode " << mode; 179 } 180 handle->socket.fd = socket_fd; 181 } 182 183 void IPCChannelPosixTest::SpinRunLoop(base::TimeDelta delay) { 184 base::MessageLoopForIO* loop = base::MessageLoopForIO::current(); 185 // Post a quit task so that this loop eventually ends and we don't hang 186 // in the case of a bad test. Usually, the run loop will quit sooner than 187 // that because all tests use a IPCChannelPosixTestListener which quits the 188 // current run loop on any channel activity. 189 loop->PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(), delay); 190 loop->Run(); 191 } 192 193 TEST_F(IPCChannelPosixTest, BasicListen) { 194 const std::string kChannelName = 195 GetChannelDirName() + "/IPCChannelPosixTest_BasicListen"; 196 197 // Test creating a socket that is listening. 198 IPC::ChannelHandle handle(kChannelName); 199 SetUpSocket(&handle, IPC::Channel::MODE_NAMED_SERVER); 200 unlink(handle.name.c_str()); 201 IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_SERVER, NULL); 202 ASSERT_TRUE(channel.Connect()); 203 ASSERT_TRUE(channel.AcceptsConnections()); 204 ASSERT_FALSE(channel.HasAcceptedConnection()); 205 channel.ResetToAcceptingConnectionState(); 206 ASSERT_FALSE(channel.HasAcceptedConnection()); 207 } 208 209 TEST_F(IPCChannelPosixTest, BasicConnected) { 210 // Test creating a socket that is connected. 211 int pipe_fds[2]; 212 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds)); 213 std::string socket_name("/var/tmp/IPCChannelPosixTest_BasicConnected"); 214 ASSERT_GE(fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK), 0); 215 216 base::FileDescriptor fd(pipe_fds[0], false); 217 IPC::ChannelHandle handle(socket_name, fd); 218 IPC::Channel channel(handle, IPC::Channel::MODE_SERVER, NULL); 219 ASSERT_TRUE(channel.Connect()); 220 ASSERT_FALSE(channel.AcceptsConnections()); 221 channel.Close(); 222 ASSERT_TRUE(IGNORE_EINTR(close(pipe_fds[1])) == 0); 223 224 // Make sure that we can use the socket that is created for us by 225 // a standard channel. 226 IPC::Channel channel2(socket_name, IPC::Channel::MODE_SERVER, NULL); 227 ASSERT_TRUE(channel2.Connect()); 228 ASSERT_FALSE(channel2.AcceptsConnections()); 229 } 230 231 TEST_F(IPCChannelPosixTest, AdvancedConnected) { 232 // Test creating a connection to an external process. 233 IPCChannelPosixTestListener listener(false); 234 IPC::ChannelHandle chan_handle(GetConnectionSocketName()); 235 SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER); 236 IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener); 237 ASSERT_TRUE(channel.Connect()); 238 ASSERT_TRUE(channel.AcceptsConnections()); 239 ASSERT_FALSE(channel.HasAcceptedConnection()); 240 241 base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc", 242 false); 243 ASSERT_TRUE(handle); 244 SpinRunLoop(TestTimeouts::action_max_timeout()); 245 ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status()); 246 ASSERT_TRUE(channel.HasAcceptedConnection()); 247 IPC::Message* message = new IPC::Message(0, // routing_id 248 kQuitMessage, // message type 249 IPC::Message::PRIORITY_NORMAL); 250 channel.Send(message); 251 SpinRunLoop(TestTimeouts::action_timeout()); 252 int exit_code = 0; 253 EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code)); 254 EXPECT_EQ(0, exit_code); 255 ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status()); 256 ASSERT_FALSE(channel.HasAcceptedConnection()); 257 } 258 259 TEST_F(IPCChannelPosixTest, ResetState) { 260 // Test creating a connection to an external process. Close the connection, 261 // but continue to listen and make sure another external process can connect 262 // to us. 263 IPCChannelPosixTestListener listener(false); 264 IPC::ChannelHandle chan_handle(GetConnectionSocketName()); 265 SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER); 266 IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener); 267 ASSERT_TRUE(channel.Connect()); 268 ASSERT_TRUE(channel.AcceptsConnections()); 269 ASSERT_FALSE(channel.HasAcceptedConnection()); 270 271 base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc", 272 false); 273 ASSERT_TRUE(handle); 274 SpinRunLoop(TestTimeouts::action_max_timeout()); 275 ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status()); 276 ASSERT_TRUE(channel.HasAcceptedConnection()); 277 channel.ResetToAcceptingConnectionState(); 278 ASSERT_FALSE(channel.HasAcceptedConnection()); 279 280 base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixTestConnectionProc", 281 false); 282 ASSERT_TRUE(handle2); 283 SpinRunLoop(TestTimeouts::action_max_timeout()); 284 ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status()); 285 ASSERT_TRUE(channel.HasAcceptedConnection()); 286 IPC::Message* message = new IPC::Message(0, // routing_id 287 kQuitMessage, // message type 288 IPC::Message::PRIORITY_NORMAL); 289 channel.Send(message); 290 SpinRunLoop(TestTimeouts::action_timeout()); 291 EXPECT_TRUE(base::KillProcess(handle, 0, false)); 292 int exit_code = 0; 293 EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code)); 294 EXPECT_EQ(0, exit_code); 295 ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status()); 296 ASSERT_FALSE(channel.HasAcceptedConnection()); 297 } 298 299 TEST_F(IPCChannelPosixTest, BadChannelName) { 300 // Test empty name 301 IPC::ChannelHandle handle(""); 302 IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_SERVER, NULL); 303 ASSERT_FALSE(channel.Connect()); 304 305 // Test name that is too long. 306 const char *kTooLongName = "This_is_a_very_long_name_to_proactively_implement" 307 "client-centered_synergy_through_top-line" 308 "platforms_Phosfluorescently_disintermediate_" 309 "clicks-and-mortar_best_practices_without_" 310 "future-proof_growth_strategies_Continually" 311 "pontificate_proactive_potentialities_before" 312 "leading-edge_processes"; 313 EXPECT_GE(strlen(kTooLongName), IPC::kMaxSocketNameLength); 314 IPC::ChannelHandle handle2(kTooLongName); 315 IPC::Channel channel2(handle2, IPC::Channel::MODE_NAMED_SERVER, NULL); 316 EXPECT_FALSE(channel2.Connect()); 317 } 318 319 TEST_F(IPCChannelPosixTest, MultiConnection) { 320 // Test setting up a connection to an external process, and then have 321 // another external process attempt to connect to us. 322 IPCChannelPosixTestListener listener(false); 323 IPC::ChannelHandle chan_handle(GetConnectionSocketName()); 324 SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER); 325 IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener); 326 ASSERT_TRUE(channel.Connect()); 327 ASSERT_TRUE(channel.AcceptsConnections()); 328 ASSERT_FALSE(channel.HasAcceptedConnection()); 329 330 base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc", 331 false); 332 ASSERT_TRUE(handle); 333 SpinRunLoop(TestTimeouts::action_max_timeout()); 334 ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status()); 335 ASSERT_TRUE(channel.HasAcceptedConnection()); 336 base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixFailConnectionProc", 337 false); 338 ASSERT_TRUE(handle2); 339 SpinRunLoop(TestTimeouts::action_max_timeout()); 340 int exit_code = 0; 341 EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code)); 342 EXPECT_EQ(exit_code, 0); 343 ASSERT_EQ(IPCChannelPosixTestListener::DENIED, listener.status()); 344 ASSERT_TRUE(channel.HasAcceptedConnection()); 345 IPC::Message* message = new IPC::Message(0, // routing_id 346 kQuitMessage, // message type 347 IPC::Message::PRIORITY_NORMAL); 348 channel.Send(message); 349 SpinRunLoop(TestTimeouts::action_timeout()); 350 EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code)); 351 EXPECT_EQ(exit_code, 0); 352 ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status()); 353 ASSERT_FALSE(channel.HasAcceptedConnection()); 354 } 355 356 TEST_F(IPCChannelPosixTest, DoubleServer) { 357 // Test setting up two servers with the same name. 358 IPCChannelPosixTestListener listener(false); 359 IPCChannelPosixTestListener listener2(false); 360 IPC::ChannelHandle chan_handle(GetConnectionSocketName()); 361 IPC::Channel channel(chan_handle, IPC::Channel::MODE_SERVER, &listener); 362 IPC::Channel channel2(chan_handle, IPC::Channel::MODE_SERVER, &listener2); 363 ASSERT_TRUE(channel.Connect()); 364 ASSERT_FALSE(channel2.Connect()); 365 } 366 367 TEST_F(IPCChannelPosixTest, BadMode) { 368 // Test setting up two servers with a bad mode. 369 IPCChannelPosixTestListener listener(false); 370 IPC::ChannelHandle chan_handle(GetConnectionSocketName()); 371 IPC::Channel channel(chan_handle, IPC::Channel::MODE_NONE, &listener); 372 ASSERT_FALSE(channel.Connect()); 373 } 374 375 TEST_F(IPCChannelPosixTest, IsNamedServerInitialized) { 376 const std::string& connection_socket_name = GetConnectionSocketName(); 377 IPCChannelPosixTestListener listener(false); 378 IPC::ChannelHandle chan_handle(connection_socket_name); 379 ASSERT_TRUE(base::DeleteFile(base::FilePath(connection_socket_name), false)); 380 ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized( 381 connection_socket_name)); 382 IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener); 383 ASSERT_TRUE(IPC::Channel::IsNamedServerInitialized( 384 connection_socket_name)); 385 channel.Close(); 386 ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized( 387 connection_socket_name)); 388 } 389 390 // A long running process that connects to us 391 MULTIPROCESS_TEST_MAIN(IPCChannelPosixTestConnectionProc) { 392 base::MessageLoopForIO message_loop; 393 IPCChannelPosixTestListener listener(true); 394 IPC::ChannelHandle handle(IPCChannelPosixTest::GetConnectionSocketName()); 395 IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT); 396 IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_CLIENT, &listener); 397 EXPECT_TRUE(channel.Connect()); 398 IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout()); 399 EXPECT_EQ(IPCChannelPosixTestListener::MESSAGE_RECEIVED, listener.status()); 400 return 0; 401 } 402 403 // Simple external process that shouldn't be able to connect to us. 404 MULTIPROCESS_TEST_MAIN(IPCChannelPosixFailConnectionProc) { 405 base::MessageLoopForIO message_loop; 406 IPCChannelPosixTestListener listener(false); 407 IPC::ChannelHandle handle(IPCChannelPosixTest::GetConnectionSocketName()); 408 IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT); 409 IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_CLIENT, &listener); 410 411 // In this case connect may succeed or fail depending on if the packet 412 // actually gets sent at sendmsg. Since we never delay on send, we may not 413 // see the error. However even if connect succeeds, eventually we will get an 414 // error back since the channel will be closed when we attempt to read from 415 // it. 416 bool connected = channel.Connect(); 417 if (connected) { 418 IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout()); 419 EXPECT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status()); 420 } else { 421 EXPECT_EQ(IPCChannelPosixTestListener::DISCONNECTED, listener.status()); 422 } 423 return 0; 424 } 425 426 } // namespace 427