[content shell] implement testRunner.overridePreference
[chromium-blink-merge.git] / ipc / ipc_send_fds_test.cc
blob667908800dcff36ff6f4a043200c3cb261db6c44
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 #include "ipc/ipc_tests.h"
9 #if defined(OS_MACOSX)
10 extern "C" {
11 #include <sandbox.h>
13 #endif
14 #include <fcntl.h>
15 #include <sys/stat.h>
17 #include "base/message_loop.h"
18 #include "base/posix/eintr_wrapper.h"
19 #include "ipc/ipc_channel.h"
20 #include "ipc/ipc_listener.h"
21 #include "ipc/ipc_message_utils.h"
22 #include "ipc/ipc_multiprocess_test.h"
23 #include "testing/multiprocess_func_list.h"
25 #if defined(OS_POSIX)
26 #include "base/file_descriptor_posix.h"
28 namespace {
30 const unsigned kNumFDsToSend = 20;
31 const char* kDevZeroPath = "/dev/zero";
33 static void VerifyAndCloseDescriptor(int fd, ino_t inode_num) {
34 // Check that we can read from the FD.
35 char buf;
36 ssize_t amt_read = read(fd, &buf, 1);
37 ASSERT_EQ(amt_read, 1);
38 ASSERT_EQ(buf, 0); // /dev/zero always reads NUL bytes.
40 struct stat st;
41 ASSERT_EQ(fstat(fd, &st), 0);
43 ASSERT_EQ(close(fd), 0);
45 // We compare iNode numbers to check that the file sent over the wire
46 // was actually the same physical file as the one we were expecting.
47 ASSERT_EQ(inode_num, st.st_ino);
50 class MyChannelDescriptorListener : public IPC::Listener {
51 public:
52 MyChannelDescriptorListener(ino_t expected_inode_num)
53 : expected_inode_num_(expected_inode_num),
54 num_fds_received_(0) {}
56 virtual bool OnMessageReceived(const IPC::Message& message) {
57 PickleIterator iter(message);
59 ++num_fds_received_;
60 base::FileDescriptor descriptor;
62 IPC::ParamTraits<base::FileDescriptor>::Read(
63 &message, &iter, &descriptor);
65 VerifyAndCloseDescriptor(descriptor.fd, expected_inode_num_);
66 if (num_fds_received_ == kNumFDsToSend) {
67 MessageLoop::current()->Quit();
69 return true;
72 virtual void OnChannelError() {
73 MessageLoop::current()->Quit();
76 bool GotExpectedNumberOfDescriptors() {
77 return kNumFDsToSend == num_fds_received_;
80 private:
81 ino_t expected_inode_num_;
82 unsigned num_fds_received_;
85 void TestDescriptorServer(IPC::Channel& chan,
86 base::ProcessHandle process_handle) {
87 ASSERT_TRUE(process_handle);
89 for (unsigned i = 0; i < kNumFDsToSend; ++i) {
90 base::FileDescriptor descriptor;
91 const int fd = open(kDevZeroPath, O_RDONLY);
92 ASSERT_GE(fd, 0);
93 descriptor.auto_close = true;
94 descriptor.fd = fd;
96 IPC::Message* message = new IPC::Message(0, // routing_id
97 3, // message type
98 IPC::Message::PRIORITY_NORMAL);
99 IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
100 ASSERT_TRUE(chan.Send(message));
103 // Run message loop.
104 MessageLoop::current()->Run();
106 // Close Channel so client gets its OnChannelError() callback fired.
107 chan.Close();
109 // Cleanup child process.
110 EXPECT_TRUE(base::WaitForSingleProcess(
111 process_handle, base::TimeDelta::FromSeconds(5)));
114 int TestDescriptorClient(ino_t expected_inode_num) {
115 MessageLoopForIO main_message_loop;
116 MyChannelDescriptorListener listener(expected_inode_num);
118 // Setup IPC channel.
119 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
120 &listener);
121 CHECK(chan.Connect());
123 // Run message loop so IPC Channel can handle message IO.
124 MessageLoop::current()->Run();
126 // Verify that the message loop was exited due to getting the correct
127 // number of descriptors, and not because the channel closing unexpectedly.
128 CHECK(listener.GotExpectedNumberOfDescriptors());
130 return 0;
133 } // namespace
135 // ---------------------------------------------------------------------------
136 #if defined(OS_MACOSX)
137 // TODO(port): Make this test cross-platform.
138 MULTIPROCESS_IPC_TEST_MAIN(RunTestDescriptorClientSandboxed) {
139 struct stat st;
140 const int fd = open(kDevZeroPath, O_RDONLY);
141 fstat(fd, &st);
142 if (HANDLE_EINTR(close(fd)) < 0) {
143 return -1;
146 // Enable the Sandbox.
147 char* error_buff = NULL;
148 int error = sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED,
149 &error_buff);
150 bool success = (error == 0 && error_buff == NULL);
151 if (!success) {
152 return -1;
155 sandbox_free_error(error_buff);
157 // Make sure Sandbox is really enabled.
158 if (open(kDevZeroPath, O_RDONLY) != -1) {
159 LOG(ERROR) << "Sandbox wasn't properly enabled";
160 return -1;
163 // See if we can receive a file descriptor.
164 return TestDescriptorClient(st.st_ino);
167 // Test that FDs are correctly sent to a sandboxed process.
168 TEST_F(IPCChannelTest, DescriptorTestSandboxed) {
169 // Setup IPC channel.
170 MyChannelDescriptorListener listener(-1);
172 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
173 &listener);
174 ASSERT_TRUE(chan.Connect());
176 base::ProcessHandle process_handle = SpawnChild(
177 TEST_DESCRIPTOR_CLIENT_SANDBOXED,
178 &chan);
179 TestDescriptorServer(chan, process_handle);
181 #endif // defined(OS_MACOSX)
183 MULTIPROCESS_IPC_TEST_MAIN(RunTestDescriptorClient) {
184 struct stat st;
185 const int fd = open(kDevZeroPath, O_RDONLY);
186 fstat(fd, &st);
187 EXPECT_GE(HANDLE_EINTR(close(fd)), 0);
189 return TestDescriptorClient(st.st_ino);
192 TEST_F(IPCChannelTest, DescriptorTest) {
193 // Setup IPC channel.
194 MyChannelDescriptorListener listener(-1);
196 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
197 &listener);
198 ASSERT_TRUE(chan.Connect());
200 base::ProcessHandle process_handle = SpawnChild(TEST_DESCRIPTOR_CLIENT,
201 &chan);
202 TestDescriptorServer(chan, process_handle);
205 #endif // defined(OS_POSIX)