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