15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_POSIX) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" { 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sandbox.h> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h> 144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <sys/socket.h> 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h> 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <unistd.h> 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <queue> 194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/callback.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_descriptor_posix.h" 229ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/pickle.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h" 254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/synchronization/waitable_event.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_message_utils.h" 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_test_base.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const unsigned kNumFDsToSend = 20; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* kDevZeroPath = "/dev/zero"; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class MyChannelDescriptorListenerBase : public IPC::Listener { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PickleIterator iter(message); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::FileDescriptor descriptor; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC::ParamTraits<base::FileDescriptor>::Read(&message, &iter, &descriptor); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) HandleFD(descriptor.fd); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) protected: 484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) virtual void HandleFD(int fd) = 0; 494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class MyChannelDescriptorListener : public MyChannelDescriptorListenerBase { 524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public: 534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) explicit MyChannelDescriptorListener(ino_t expected_inode_num) 544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : MyChannelDescriptorListenerBase(), 554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) expected_inode_num_(expected_inode_num), 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) num_fds_received_(0) { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool GotExpectedNumberOfDescriptors() const { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return num_fds_received_ == kNumFDsToSend; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) virtual void OnChannelError() OVERRIDE { 644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::MessageLoop::current()->Quit(); 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) protected: 684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) virtual void HandleFD(int fd) OVERRIDE { 694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Check that we can read from the FD. 704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) char buf; 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ssize_t amt_read = read(fd, &buf, 1); 724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ASSERT_EQ(amt_read, 1); 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes. 744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) struct stat st; 764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ASSERT_EQ(fstat(fd, &st), 0); 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ASSERT_EQ(close(fd), 0); 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Compare inode numbers to check that the file sent over the wire is 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // actually the one expected. 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ASSERT_EQ(expected_inode_num_, st.st_ino); 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ++num_fds_received_; 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (num_fds_received_ == kNumFDsToSend) 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::MessageLoop::current()->Quit(); 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ino_t expected_inode_num_; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned num_fds_received_; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class IPCSendFdsTest : public IPCTestBase { 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) protected: 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void RunServer() { 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Set up IPC channel and start client. 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) MyChannelDescriptorListener listener(-1); 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CreateChannel(&listener); 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(ConnectChannel()); 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(StartClient()); 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (unsigned i = 0; i < kNumFDsToSend; ++i) { 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int fd = open(kDevZeroPath, O_RDONLY); 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_GE(fd, 0); 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FileDescriptor descriptor(fd, true); 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) IPC::Message* message = 1100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL); 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor); 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ASSERT_TRUE(sender()->Send(message)); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Run message loop. 116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->Run(); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Close the channel so the client's OnChannelError() gets fired. 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) channel()->Close(); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_TRUE(WaitForClientShutdown()); 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DestroyChannel(); 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(IPCSendFdsTest, DescriptorTest) { 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Init("SendFdsClient"); 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RunServer(); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SendFdsClientCommon(const std::string& test_client_name, 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ino_t expected_inode_num) { 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoopForIO main_message_loop; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MyChannelDescriptorListener listener(expected_inode_num); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Set up IPC channel. 137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient( 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) IPCTestBase::GetChannelName(test_client_name), 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &listener)); 140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) CHECK(channel->Connect()); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Run message loop. 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->Run(); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Verify that the message loop was exited due to getting the correct number 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // of descriptors, and not because of the channel closing unexpectedly. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(listener.GotExpectedNumberOfDescriptors()); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsClient) { 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) struct stat st; 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int fd = open(kDevZeroPath, O_RDONLY); 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fstat(fd, &st); 156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_GE(IGNORE_EINTR(close(fd)), 0); 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return SendFdsClientCommon("SendFdsClient", st.st_ino); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX) 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Test that FDs are correctly sent to a sandboxed process. 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(port): Make this test cross-platform. 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(IPCSendFdsTest, DescriptorTestSandboxed) { 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Init("SendFdsSandboxedClient"); 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RunServer(); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct stat st; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int fd = open(kDevZeroPath, O_RDONLY); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fstat(fd, &st); 172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (IGNORE_EINTR(close(fd)) < 0) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Enable the sandbox. 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* error_buff = NULL; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int error = sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &error_buff); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = (error == 0 && error_buff == NULL); 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!success) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sandbox_free_error(error_buff); 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Make sure sandbox is really enabled. 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (open(kDevZeroPath, O_RDONLY) != -1) { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Sandbox wasn't properly enabled"; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return -1; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See if we can receive a file descriptor. 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return SendFdsClientCommon("SendFdsSandboxedClient", st.st_ino); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(OS_MACOSX) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class MyCBListener : public MyChannelDescriptorListenerBase { 1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public: 1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) MyCBListener(base::Callback<void(int)> cb, int fds_to_send) 2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : MyChannelDescriptorListenerBase(), 2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) cb_(cb) { 2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) protected: 2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) virtual void HandleFD(int fd) OVERRIDE { 2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) cb_.Run(fd); 2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private: 2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Callback<void(int)> cb_; 2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::pair<int, int> make_socket_pair() { 2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int pipe_fds[2]; 2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CHECK_EQ(0, HANDLE_EINTR(socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds))); 2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return std::pair<int, int>(pipe_fds[0], pipe_fds[1]); 2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static void null_cb(int unused_fd) { 2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) NOTREACHED(); 2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class PipeChannelHelper { 2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public: 2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) PipeChannelHelper(base::Thread* in_thread, 2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Thread* out_thread, 2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Callback<void(int)> cb, 2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int fds_to_send) : 2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) in_thread_(in_thread), 2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) out_thread_(out_thread), 2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) cb_listener_(cb, fds_to_send), 2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) null_listener_(base::Bind(&null_cb), 0) { 2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) void Init() { 2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IPC::ChannelHandle in_handle("IN"); 236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) in = IPC::Channel::CreateServer(in_handle, &null_listener_); 23746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) base::FileDescriptor out_fd( 23846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) in->TakeClientFileDescriptor(), false); 2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IPC::ChannelHandle out_handle("OUT", out_fd); 240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) out = IPC::Channel::CreateClient(out_handle, &cb_listener_); 2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // PostTask the connect calls to make sure the callbacks happens 2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // on the right threads. 2434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) in_thread_->message_loop()->PostTask( 2444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FROM_HERE, 2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&PipeChannelHelper::Connect, in.get())); 2464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) out_thread_->message_loop()->PostTask( 2474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FROM_HERE, 2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&PipeChannelHelper::Connect, out.get())); 2494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static void DestroyChannel(scoped_ptr<IPC::Channel> *c, 2524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::WaitableEvent *event) { 2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) c->reset(0); 2544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) event->Signal(); 2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ~PipeChannelHelper() { 2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::WaitableEvent a(true, false); 2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::WaitableEvent b(true, false); 2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) in_thread_->message_loop()->PostTask( 2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FROM_HERE, 2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&PipeChannelHelper::DestroyChannel, &in, &a)); 2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) out_thread_->message_loop()->PostTask( 2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FROM_HERE, 2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&PipeChannelHelper::DestroyChannel, &out, &b)); 2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) a.Wait(); 2674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) b.Wait(); 2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static void Connect(IPC::Channel *channel) { 2714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) EXPECT_TRUE(channel->Connect()); 2724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) void Send(int fd) { 2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CHECK_EQ(base::MessageLoop::current(), in_thread_->message_loop()); 2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ASSERT_GE(fd, 0); 2784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::FileDescriptor descriptor(fd, true); 2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) IPC::Message* message = 2810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL); 2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor); 2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ASSERT_TRUE(in->Send(message)); 2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private: 2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<IPC::Channel> in, out; 2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Thread* in_thread_; 2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Thread* out_thread_; 2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) MyCBListener cb_listener_; 2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) MyCBListener null_listener_; 2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 2944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// This test is meant to provoke a kernel bug on OSX, and to prove 2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// that the workaround for it is working. It sets up two pipes and three 2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// threads, the producer thread creates socketpairs and sends one of the fds 2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// over pipe1 to the middleman thread. The middleman thread simply takes the fd 2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// sends it over pipe2 to the consumer thread. The consumer thread writes a byte 2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// to each fd it receives and then closes the pipe. The producer thread reads 3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// the bytes back from each pair of pipes and make sure that everything worked. 3014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// This feedback mechanism makes sure that not too many file descriptors are 3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// in flight at the same time. For more info on the bug, see: 3034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// http://crbug.com/298276 3044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class IPCMultiSendingFdsTest : public testing::Test { 3054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public: 3064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) IPCMultiSendingFdsTest() : received_(true, false) {} 3074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) void Producer(PipeChannelHelper* dest, 3094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Thread* t, 3104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int pipes_to_send) { 3114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for (int i = 0; i < pipes_to_send; i++) { 3124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) received_.Reset(); 3134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::pair<int, int> pipe_fds = make_socket_pair(); 3144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) t->message_loop()->PostTask( 3154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) FROM_HERE, 3164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&PipeChannelHelper::Send, 3174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Unretained(dest), 3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) pipe_fds.second)); 3194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) char tmp = 'x'; 3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CHECK_EQ(1, HANDLE_EINTR(write(pipe_fds.first, &tmp, 1))); 321a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CHECK_EQ(0, IGNORE_EINTR(close(pipe_fds.first))); 3224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) received_.Wait(); 3234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) void ConsumerHandleFD(int fd) { 3274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) char tmp = 'y'; 3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CHECK_EQ(1, HANDLE_EINTR(read(fd, &tmp, 1))); 3294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CHECK_EQ(tmp, 'x'); 330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CHECK_EQ(0, IGNORE_EINTR(close(fd))); 3314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) received_.Signal(); 3324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Thread* CreateThread(const char* name) { 3354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Thread* ret = new base::Thread(name); 3364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Thread::Options options; 3374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) options.message_loop_type = base::MessageLoop::TYPE_IO; 3384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ret->StartWithOptions(options); 3394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return ret; 3404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) void Run() { 3434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // On my mac, this test fails roughly 35 times per 3444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // million sends with low load, but much more with high load. 3454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Unless the workaround is in place. With 10000 sends, we 3464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // should see at least a 3% failure rate. 3474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const int pipes_to_send = 20000; 3484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<base::Thread> producer(CreateThread("producer")); 3494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<base::Thread> middleman(CreateThread("middleman")); 3504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<base::Thread> consumer(CreateThread("consumer")); 3514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) PipeChannelHelper pipe1( 3524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) middleman.get(), 3534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) consumer.get(), 3544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&IPCMultiSendingFdsTest::ConsumerHandleFD, 3554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Unretained(this)), 3564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) pipes_to_send); 3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) PipeChannelHelper pipe2( 3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) producer.get(), 3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) middleman.get(), 3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::Bind(&PipeChannelHelper::Send, base::Unretained(&pipe1)), 3614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) pipes_to_send); 3624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) pipe1.Init(); 3634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) pipe2.Init(); 3644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Producer(&pipe2, producer.get(), pipes_to_send); 3654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 3664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private: 3684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) base::WaitableEvent received_; 3694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}; 3704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(IPCMultiSendingFdsTest, StressTest) { 3724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Run(); 3734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 3744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // defined(OS_POSIX) 378