Fix build break
[chromium-blink-merge.git] / ipc / ipc_send_fds_test.cc
blob75d1629c48abda511ded42638fdaa7812166eb42
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.
5 #include "build/build_config.h"
7 #if defined(OS_POSIX)
8 #if defined(OS_MACOSX)
9 extern "C" {
10 #include <sandbox.h>
12 #endif
13 #include <fcntl.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
17 #include "base/file_descriptor_posix.h"
18 #include "base/message_loop.h"
19 #include "base/pickle.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "ipc/ipc_message_utils.h"
22 #include "ipc/ipc_test_base.h"
24 namespace {
26 const unsigned kNumFDsToSend = 20;
27 const char* kDevZeroPath = "/dev/zero";
29 static void VerifyAndCloseDescriptor(int fd, ino_t inode_num) {
30 // Check that we can read from the FD.
31 char buf;
32 ssize_t amt_read = read(fd, &buf, 1);
33 ASSERT_EQ(amt_read, 1);
34 ASSERT_EQ(buf, 0); // /dev/zero always reads 0 bytes.
36 struct stat st;
37 ASSERT_EQ(fstat(fd, &st), 0);
39 ASSERT_EQ(close(fd), 0);
41 // Compare inode numbers to check that the file sent over the wire is actually
42 // the one expected.
43 ASSERT_EQ(inode_num, st.st_ino);
46 class MyChannelDescriptorListener : public IPC::Listener {
47 public:
48 explicit MyChannelDescriptorListener(ino_t expected_inode_num)
49 : expected_inode_num_(expected_inode_num),
50 num_fds_received_(0) {}
52 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
53 PickleIterator iter(message);
55 ++num_fds_received_;
56 base::FileDescriptor descriptor;
58 IPC::ParamTraits<base::FileDescriptor>::Read(&message, &iter, &descriptor);
60 VerifyAndCloseDescriptor(descriptor.fd, expected_inode_num_);
61 if (num_fds_received_ == kNumFDsToSend)
62 MessageLoop::current()->Quit();
64 return true;
67 virtual void OnChannelError() OVERRIDE {
68 MessageLoop::current()->Quit();
71 bool GotExpectedNumberOfDescriptors() const {
72 return num_fds_received_ == kNumFDsToSend;
75 private:
76 ino_t expected_inode_num_;
77 unsigned num_fds_received_;
80 class IPCSendFdsTest : public IPCTestBase {
81 protected:
82 void RunServer() {
83 // Set up IPC channel and start client.
84 MyChannelDescriptorListener listener(-1);
85 CreateChannel(&listener);
86 ASSERT_TRUE(ConnectChannel());
87 ASSERT_TRUE(StartClient());
89 for (unsigned i = 0; i < kNumFDsToSend; ++i) {
90 const int fd = open(kDevZeroPath, O_RDONLY);
91 ASSERT_GE(fd, 0);
92 base::FileDescriptor descriptor(fd, true);
94 IPC::Message* message =
95 new IPC::Message(0, 3, IPC::Message::PRIORITY_NORMAL);
96 IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
97 ASSERT_TRUE(sender()->Send(message));
100 // Run message loop.
101 MessageLoop::current()->Run();
103 // Close the channel so the client's OnChannelError() gets fired.
104 channel()->Close();
106 EXPECT_TRUE(WaitForClientShutdown());
107 DestroyChannel();
111 TEST_F(IPCSendFdsTest, DescriptorTest) {
112 Init("SendFdsClient");
113 RunServer();
116 int SendFdsClientCommon(const std::string& test_client_name,
117 ino_t expected_inode_num) {
118 MessageLoopForIO main_message_loop;
119 MyChannelDescriptorListener listener(expected_inode_num);
121 // Set up IPC channel.
122 IPC::Channel channel(IPCTestBase::GetChannelName(test_client_name),
123 IPC::Channel::MODE_CLIENT,
124 &listener);
125 CHECK(channel.Connect());
127 // Run message loop.
128 MessageLoop::current()->Run();
130 // Verify that the message loop was exited due to getting the correct number
131 // of descriptors, and not because of the channel closing unexpectedly.
132 CHECK(listener.GotExpectedNumberOfDescriptors());
134 return 0;
137 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsClient) {
138 struct stat st;
139 int fd = open(kDevZeroPath, O_RDONLY);
140 fstat(fd, &st);
141 EXPECT_GE(HANDLE_EINTR(close(fd)), 0);
142 return SendFdsClientCommon("SendFdsClient", st.st_ino);
145 #if defined(OS_MACOSX)
146 // Test that FDs are correctly sent to a sandboxed process.
147 // TODO(port): Make this test cross-platform.
148 TEST_F(IPCSendFdsTest, DescriptorTestSandboxed) {
149 Init("SendFdsSandboxedClient");
150 RunServer();
153 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendFdsSandboxedClient) {
154 struct stat st;
155 const int fd = open(kDevZeroPath, O_RDONLY);
156 fstat(fd, &st);
157 if (HANDLE_EINTR(close(fd)) < 0)
158 return -1;
160 // Enable the sandbox.
161 char* error_buff = NULL;
162 int error = sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED,
163 &error_buff);
164 bool success = (error == 0 && error_buff == NULL);
165 if (!success)
166 return -1;
168 sandbox_free_error(error_buff);
170 // Make sure sandbox is really enabled.
171 if (open(kDevZeroPath, O_RDONLY) != -1) {
172 LOG(ERROR) << "Sandbox wasn't properly enabled";
173 return -1;
176 // See if we can receive a file descriptor.
177 return SendFdsClientCommon("SendFdsSandboxedClient", st.st_ino);
179 #endif // defined(OS_MACOSX)
181 } // namespace
183 #endif // defined(OS_POSIX)