Initialize Tizen 2.3
[external/chromium.git] / ipc / ipc_channel_posix_unittest.cc
1 // Copyright (c) 2011 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.
4
5 // These tests are POSIX only.
6
7 #include "ipc/ipc_channel_posix.h"
8
9 #include <fcntl.h>
10 #include <sys/socket.h>
11 #include <sys/un.h>
12 #include <unistd.h>
13
14 #include "base/basictypes.h"
15 #include "base/eintr_wrapper.h"
16 #include "base/file_path.h"
17 #include "base/file_util.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/message_loop.h"
20 #include "base/test/multiprocess_test.h"
21 #include "base/test/test_timeouts.h"
22 #include "testing/multiprocess_func_list.h"
23
24 namespace {
25
26 enum {
27   QUIT_MESSAGE = 47
28 };
29
30 class IPCChannelPosixTestListener : public IPC::Channel::Listener {
31  public:
32   enum STATUS {
33     DISCONNECTED,
34     MESSAGE_RECEIVED,
35     CHANNEL_ERROR,
36     CONNECTED,
37     DENIED,
38     LISTEN_ERROR
39   };
40
41   IPCChannelPosixTestListener(bool quit_only_on_message)
42       : status_(DISCONNECTED), quit_only_on_message_(quit_only_on_message) {}
43
44   virtual ~IPCChannelPosixTestListener() {}
45
46   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
47     EXPECT_EQ(message.type(), QUIT_MESSAGE);
48     status_ = MESSAGE_RECEIVED;
49     QuitRunLoop();
50     return true;
51   }
52
53   virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
54     status_ = CONNECTED;
55     if (!quit_only_on_message_) {
56       QuitRunLoop();
57     }
58   }
59
60   virtual void OnChannelError() OVERRIDE {
61     status_ = CHANNEL_ERROR;
62     if (!quit_only_on_message_) {
63       QuitRunLoop();
64     }
65   }
66
67   virtual void OnChannelDenied() OVERRIDE {
68     status_ = DENIED;
69     if (!quit_only_on_message_) {
70       QuitRunLoop();
71     }
72   }
73
74   virtual void OnChannelListenError() OVERRIDE {
75     status_ = LISTEN_ERROR;
76     if (!quit_only_on_message_) {
77       QuitRunLoop();
78     }
79   }
80
81   STATUS status() { return status_; }
82
83   void QuitRunLoop() {
84     MessageLoopForIO::current()->QuitNow();
85   }
86
87  private:
88   // The current status of the listener.
89   STATUS status_;
90   // If |quit_only_on_message_| then the listener will only break out of
91   // the run loop when the QUIT_MESSAGE is received.
92   bool quit_only_on_message_;
93 };
94
95 }  // namespace
96
97 class IPCChannelPosixTest : public base::MultiProcessTest {
98  public:
99   static const char kConnectionSocketTestName[];
100   static void SetUpSocket(IPC::ChannelHandle *handle,
101                           IPC::Channel::Mode mode);
102   static void SpinRunLoop(int milliseconds);
103
104  protected:
105   virtual void SetUp();
106   virtual void TearDown();
107
108 private:
109   scoped_ptr<MessageLoopForIO> message_loop_;
110 };
111
112 const char IPCChannelPosixTest::kConnectionSocketTestName[] =
113     "/var/tmp/chrome_IPCChannelPosixTest__ConnectionSocket";
114
115 void IPCChannelPosixTest::SetUp() {
116   MultiProcessTest::SetUp();
117   // Construct a fresh IO Message loop for the duration of each test.
118   message_loop_.reset(new MessageLoopForIO());
119 }
120
121 void IPCChannelPosixTest::TearDown() {
122   message_loop_.reset(NULL);
123   MultiProcessTest::TearDown();
124 }
125
126 // Create up a socket and bind and listen to it, or connect it
127 // depending on the |mode|.
128 void IPCChannelPosixTest::SetUpSocket(IPC::ChannelHandle *handle,
129                                       IPC::Channel::Mode mode) {
130   const std::string& name = handle->name;
131
132   int socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
133   ASSERT_GE(socket_fd, 0) << name;
134   ASSERT_GE(fcntl(socket_fd, F_SETFL, O_NONBLOCK), 0);
135   struct sockaddr_un server_address = { 0 };
136   memset(&server_address, 0, sizeof(server_address));
137   server_address.sun_family = AF_UNIX;
138   int path_len = snprintf(server_address.sun_path, IPC::kMaxPipeNameLength,
139                           "%s", name.c_str());
140   DCHECK_EQ(static_cast<int>(name.length()), path_len);
141   size_t server_address_len = offsetof(struct sockaddr_un,
142                                        sun_path) + path_len + 1;
143
144   if (mode == IPC::Channel::MODE_NAMED_SERVER) {
145     // Only one server at a time. Cleanup garbage if it exists.
146     unlink(name.c_str());
147       // Make sure the path we need exists.
148     FilePath path(name);
149     FilePath dir_path = path.DirName();
150     ASSERT_TRUE(file_util::CreateDirectory(dir_path));
151     ASSERT_GE(bind(socket_fd,
152                    reinterpret_cast<struct sockaddr *>(&server_address),
153                    server_address_len), 0) << server_address.sun_path
154                                            << ": " << strerror(errno)
155                                            << "(" << errno << ")";
156     ASSERT_GE(listen(socket_fd, SOMAXCONN), 0) << server_address.sun_path
157                                                << ": " << strerror(errno)
158                                                << "(" << errno << ")";
159   } else if (mode == IPC::Channel::MODE_NAMED_CLIENT) {
160     ASSERT_GE(connect(socket_fd,
161                       reinterpret_cast<struct sockaddr *>(&server_address),
162                       server_address_len), 0) << server_address.sun_path
163                                               << ": " << strerror(errno)
164                                               << "(" << errno << ")";
165   } else {
166     FAIL() << "Unknown mode " << mode;
167   }
168   handle->socket.fd = socket_fd;
169 }
170
171 void IPCChannelPosixTest::SpinRunLoop(int milliseconds) {
172   MessageLoopForIO *loop = MessageLoopForIO::current();
173   // Post a quit task so that this loop eventually ends and we don't hang
174   // in the case of a bad test. Usually, the run loop will quit sooner than
175   // that because all tests use a IPCChannelPosixTestListener which quits the
176   // current run loop on any channel activity.
177   loop->PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask(), milliseconds);
178   loop->Run();
179 }
180
181 TEST_F(IPCChannelPosixTest, BasicListen) {
182   // Test creating a socket that is listening.
183   IPC::ChannelHandle handle("/var/tmp/IPCChannelPosixTest_BasicListen");
184   SetUpSocket(&handle, IPC::Channel::MODE_NAMED_SERVER);
185   unlink(handle.name.c_str());
186   IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_SERVER, NULL);
187   ASSERT_TRUE(channel.Connect());
188   ASSERT_TRUE(channel.AcceptsConnections());
189   ASSERT_FALSE(channel.HasAcceptedConnection());
190   channel.ResetToAcceptingConnectionState();
191   ASSERT_FALSE(channel.HasAcceptedConnection());
192 }
193
194 TEST_F(IPCChannelPosixTest, BasicConnected) {
195   // Test creating a socket that is connected.
196   int pipe_fds[2];
197   ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds));
198   std::string socket_name("/var/tmp/IPCChannelPosixTest_BasicConnected");
199   ASSERT_GE(fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK), 0);
200
201   base::FileDescriptor fd(pipe_fds[0], false);
202   IPC::ChannelHandle handle(socket_name, fd);
203   IPC::Channel channel(handle, IPC::Channel::MODE_SERVER, NULL);
204   ASSERT_TRUE(channel.Connect());
205   ASSERT_FALSE(channel.AcceptsConnections());
206   channel.Close();
207   ASSERT_TRUE(HANDLE_EINTR(close(pipe_fds[1])) == 0);
208
209   // Make sure that we can use the socket that is created for us by
210   // a standard channel.
211   IPC::Channel channel2(socket_name, IPC::Channel::MODE_SERVER, NULL);
212   ASSERT_TRUE(channel2.Connect());
213   ASSERT_FALSE(channel2.AcceptsConnections());
214 }
215
216 TEST_F(IPCChannelPosixTest, AdvancedConnected) {
217   // Test creating a connection to an external process.
218   IPCChannelPosixTestListener listener(false);
219   IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
220   SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
221   IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
222   ASSERT_TRUE(channel.Connect());
223   ASSERT_TRUE(channel.AcceptsConnections());
224   ASSERT_FALSE(channel.HasAcceptedConnection());
225
226   base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc",
227                                           false);
228   ASSERT_TRUE(handle);
229   SpinRunLoop(TestTimeouts::action_max_timeout_ms());
230   ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
231   ASSERT_TRUE(channel.HasAcceptedConnection());
232   IPC::Message* message = new IPC::Message(0, // routing_id
233                                            QUIT_MESSAGE, // message type
234                                            IPC::Message::PRIORITY_NORMAL);
235   channel.Send(message);
236   SpinRunLoop(TestTimeouts::action_timeout_ms());
237   int exit_code = 0;
238   EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
239   EXPECT_EQ(0, exit_code);
240   ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
241   ASSERT_FALSE(channel.HasAcceptedConnection());
242 }
243
244 TEST_F(IPCChannelPosixTest, ResetState) {
245   // Test creating a connection to an external process. Close the connection,
246   // but continue to listen and make sure another external process can connect
247   // to us.
248   IPCChannelPosixTestListener listener(false);
249   IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
250   SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
251   IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
252   ASSERT_TRUE(channel.Connect());
253   ASSERT_TRUE(channel.AcceptsConnections());
254   ASSERT_FALSE(channel.HasAcceptedConnection());
255
256   base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc",
257                                           false);
258   ASSERT_TRUE(handle);
259   SpinRunLoop(TestTimeouts::action_max_timeout_ms());
260   ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
261   ASSERT_TRUE(channel.HasAcceptedConnection());
262   channel.ResetToAcceptingConnectionState();
263   ASSERT_FALSE(channel.HasAcceptedConnection());
264
265   base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixTestConnectionProc",
266                                           false);
267   ASSERT_TRUE(handle2);
268   SpinRunLoop(TestTimeouts::action_max_timeout_ms());
269   ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
270   ASSERT_TRUE(channel.HasAcceptedConnection());
271   IPC::Message* message = new IPC::Message(0, // routing_id
272                                            QUIT_MESSAGE, // message type
273                                            IPC::Message::PRIORITY_NORMAL);
274   channel.Send(message);
275   SpinRunLoop(TestTimeouts::action_timeout_ms());
276   EXPECT_TRUE(base::KillProcess(handle, 0, false));
277   int exit_code = 0;
278   EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
279   EXPECT_EQ(0, exit_code);
280   ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
281   ASSERT_FALSE(channel.HasAcceptedConnection());
282 }
283
284 TEST_F(IPCChannelPosixTest, MultiConnection) {
285   // Test setting up a connection to an external process, and then have
286   // another external process attempt to connect to us.
287   IPCChannelPosixTestListener listener(false);
288   IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
289   SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
290   IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
291   ASSERT_TRUE(channel.Connect());
292   ASSERT_TRUE(channel.AcceptsConnections());
293   ASSERT_FALSE(channel.HasAcceptedConnection());
294
295   base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc",
296                                           false);
297   ASSERT_TRUE(handle);
298   SpinRunLoop(TestTimeouts::action_max_timeout_ms());
299   ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
300   ASSERT_TRUE(channel.HasAcceptedConnection());
301   base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixFailConnectionProc",
302                                            false);
303   ASSERT_TRUE(handle2);
304   SpinRunLoop(TestTimeouts::action_max_timeout_ms());
305   int exit_code = 0;
306   EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
307   EXPECT_EQ(exit_code, 0);
308   ASSERT_EQ(IPCChannelPosixTestListener::DENIED, listener.status());
309   ASSERT_TRUE(channel.HasAcceptedConnection());
310   IPC::Message* message = new IPC::Message(0, // routing_id
311                                            QUIT_MESSAGE, // message type
312                                            IPC::Message::PRIORITY_NORMAL);
313   channel.Send(message);
314   SpinRunLoop(TestTimeouts::action_timeout_ms());
315   EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
316   EXPECT_EQ(exit_code, 0);
317   ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
318   ASSERT_FALSE(channel.HasAcceptedConnection());
319 }
320
321 TEST_F(IPCChannelPosixTest, DoubleServer) {
322   // Test setting up two servers with the same name.
323   IPCChannelPosixTestListener listener(false);
324   IPCChannelPosixTestListener listener2(false);
325   IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
326   IPC::Channel channel(chan_handle, IPC::Channel::MODE_SERVER, &listener);
327   IPC::Channel channel2(chan_handle, IPC::Channel::MODE_SERVER, &listener2);
328   ASSERT_TRUE(channel.Connect());
329   ASSERT_FALSE(channel2.Connect());
330 }
331
332 TEST_F(IPCChannelPosixTest, BadMode) {
333   // Test setting up two servers with a bad mode.
334   IPCChannelPosixTestListener listener(false);
335   IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
336   IPC::Channel channel(chan_handle, IPC::Channel::MODE_NONE, &listener);
337   ASSERT_FALSE(channel.Connect());
338 }
339
340 TEST_F(IPCChannelPosixTest, IsNamedServerInitialized) {
341   IPCChannelPosixTestListener listener(false);
342   IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
343   ASSERT_TRUE(file_util::Delete(FilePath(kConnectionSocketTestName), false));
344   ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
345       kConnectionSocketTestName));
346   IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
347   ASSERT_TRUE(IPC::Channel::IsNamedServerInitialized(
348       kConnectionSocketTestName));
349   channel.Close();
350   ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
351       kConnectionSocketTestName));
352 }
353
354 // A long running process that connects to us
355 MULTIPROCESS_TEST_MAIN(IPCChannelPosixTestConnectionProc) {
356   MessageLoopForIO message_loop;
357   IPCChannelPosixTestListener listener(true);
358   IPC::ChannelHandle handle(IPCChannelPosixTest::kConnectionSocketTestName);
359   IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT);
360   IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_CLIENT, &listener);
361   EXPECT_TRUE(channel.Connect());
362   IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout_ms());
363   EXPECT_EQ(IPCChannelPosixTestListener::MESSAGE_RECEIVED, listener.status());
364   return 0;
365 }
366
367 // Simple external process that shouldn't be able to connect to us.
368 MULTIPROCESS_TEST_MAIN(IPCChannelPosixFailConnectionProc) {
369   MessageLoopForIO message_loop;
370   IPCChannelPosixTestListener listener(false);
371   IPC::ChannelHandle handle(IPCChannelPosixTest::kConnectionSocketTestName);
372   IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT);
373   IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_CLIENT, &listener);
374
375   // In this case connect may succeed or fail depending on if the packet
376   // actually gets sent at sendmsg. Since we never delay on send, we may not
377   // see the error. However even if connect succeeds, eventually we will get an
378   // error back since the channel will be closed when we attempt to read from
379   // it.
380   bool connected = channel.Connect();
381   if (connected) {
382     IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout_ms());
383     EXPECT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
384   } else {
385     EXPECT_EQ(IPCChannelPosixTestListener::DISCONNECTED, listener.status());
386   }
387   return 0;
388 }
389