Updating trunk VERSION from 1007.0 to 1008.0
[chromium-blink-merge.git] / ipc / ipc_send_fds_test.cc
blob3b845f8cf3c24b6acfae103e02ddd686b9de03e4
1 // Copyright (c) 2009 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/eintr_wrapper.h"
18 #include "base/message_loop.h"
19 #include "ipc/ipc_channel.h"
20 #include "ipc/ipc_message_utils.h"
21 #include "testing/multiprocess_func_list.h"
23 #if defined(OS_POSIX)
24 #include "base/file_descriptor_posix.h"
26 namespace {
28 const unsigned kNumFDsToSend = 20;
29 const char* kDevZeroPath = "/dev/zero";
31 static void VerifyAndCloseDescriptor(int fd, ino_t inode_num) {
32 // Check that we can read from the FD.
33 char buf;
34 ssize_t amt_read = read(fd, &buf, 1);
35 ASSERT_EQ(amt_read, 1);
36 ASSERT_EQ(buf, 0); // /dev/zero always reads NUL bytes.
38 struct stat st;
39 ASSERT_EQ(fstat(fd, &st), 0);
41 ASSERT_EQ(close(fd), 0);
43 // We compare iNode numbers to check that the file sent over the wire
44 // was actually the same physical file as the one we were expecting.
45 ASSERT_EQ(inode_num, st.st_ino);
48 class MyChannelDescriptorListener : public IPC::Channel::Listener {
49 public:
50 MyChannelDescriptorListener(ino_t expected_inode_num)
51 : expected_inode_num_(expected_inode_num),
52 num_fds_received_(0) {}
54 virtual bool OnMessageReceived(const IPC::Message& message) {
55 void* iter = NULL;
57 ++num_fds_received_;
58 base::FileDescriptor descriptor;
60 IPC::ParamTraits<base::FileDescriptor>::Read(
61 &message, &iter, &descriptor);
63 VerifyAndCloseDescriptor(descriptor.fd, expected_inode_num_);
64 if (num_fds_received_ == kNumFDsToSend) {
65 MessageLoop::current()->Quit();
67 return true;
70 virtual void OnChannelError() {
71 MessageLoop::current()->Quit();
74 bool GotExpectedNumberOfDescriptors() {
75 return kNumFDsToSend == num_fds_received_;
78 private:
79 ino_t expected_inode_num_;
80 unsigned num_fds_received_;
83 void TestDescriptorServer(IPC::Channel &chan,
84 base::ProcessHandle process_handle) {
85 ASSERT_TRUE(process_handle);
87 for (unsigned i = 0; i < kNumFDsToSend; ++i) {
88 base::FileDescriptor descriptor;
89 const int fd = open(kDevZeroPath, O_RDONLY);
90 ASSERT_GE(fd, 0);
91 descriptor.auto_close = true;
92 descriptor.fd = fd;
94 IPC::Message* message = new IPC::Message(0, // routing_id
95 3, // message type
96 IPC::Message::PRIORITY_NORMAL);
97 IPC::ParamTraits<base::FileDescriptor>::Write(message, descriptor);
98 ASSERT_TRUE(chan.Send(message));
101 // Run message loop.
102 MessageLoop::current()->Run();
104 // Close Channel so client gets its OnChannelError() callback fired.
105 chan.Close();
107 // Cleanup child process.
108 EXPECT_TRUE(base::WaitForSingleProcess(process_handle, 5000));
111 int TestDescriptorClient(ino_t expected_inode_num) {
112 MessageLoopForIO main_message_loop;
113 MyChannelDescriptorListener listener(expected_inode_num);
115 // Setup IPC channel.
116 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
117 &listener);
118 CHECK(chan.Connect());
120 // Run message loop so IPC Channel can handle message IO.
121 MessageLoop::current()->Run();
123 // Verify that the message loop was exited due to getting the correct
124 // number of descriptors, and not because the channel closing unexpectedly.
125 CHECK(listener.GotExpectedNumberOfDescriptors());
127 return 0;
130 } // namespace
132 // ---------------------------------------------------------------------------
133 #if defined(OS_MACOSX)
134 // TODO(port): Make this test cross-platform.
135 MULTIPROCESS_TEST_MAIN(RunTestDescriptorClientSandboxed) {
136 struct stat st;
137 const int fd = open(kDevZeroPath, O_RDONLY);
138 fstat(fd, &st);
139 if (HANDLE_EINTR(close(fd)) < 0) {
140 return -1;
143 // Enable the Sandbox.
144 char* error_buff = NULL;
145 int error = sandbox_init(kSBXProfilePureComputation, SANDBOX_NAMED,
146 &error_buff);
147 bool success = (error == 0 && error_buff == NULL);
148 if (!success) {
149 return -1;
152 sandbox_free_error(error_buff);
154 // Make sure Sandbox is really enabled.
155 if (open(kDevZeroPath, O_RDONLY) != -1) {
156 LOG(ERROR) << "Sandbox wasn't properly enabled";
157 return -1;
160 // See if we can receive a file descriptor.
161 return TestDescriptorClient(st.st_ino);
164 // Test that FDs are correctly sent to a sandboxed process.
165 TEST_F(IPCChannelTest, DescriptorTestSandboxed) {
166 // Setup IPC channel.
167 MyChannelDescriptorListener listener(-1);
169 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
170 &listener);
171 ASSERT_TRUE(chan.Connect());
173 base::ProcessHandle process_handle = SpawnChild(
174 TEST_DESCRIPTOR_CLIENT_SANDBOXED,
175 &chan);
176 TestDescriptorServer(chan, process_handle);
178 #endif // defined(OS_MACOSX)
180 MULTIPROCESS_TEST_MAIN(RunTestDescriptorClient) {
181 struct stat st;
182 const int fd = open(kDevZeroPath, O_RDONLY);
183 fstat(fd, &st);
184 EXPECT_GE(HANDLE_EINTR(close(fd)), 0);
186 return TestDescriptorClient(st.st_ino);
189 TEST_F(IPCChannelTest, DescriptorTest) {
190 // Setup IPC channel.
191 MyChannelDescriptorListener listener(-1);
193 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
194 &listener);
195 ASSERT_TRUE(chan.Connect());
197 base::ProcessHandle process_handle = SpawnChild(TEST_DESCRIPTOR_CLIENT,
198 &chan);
199 TestDescriptorServer(chan, process_handle);
202 #endif // defined(OS_POSIX)