Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / ipc / ipc_channel_posix_unittest.cc
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.
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/file_util.h"
16 #include "base/files/file_path.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/path_service.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "base/process/kill.h"
22 #include "base/test/multiprocess_test.h"
23 #include "base/test/test_timeouts.h"
24 #include "ipc/ipc_listener.h"
25 #include "ipc/unix_domain_socket_util.h"
26 #include "testing/multiprocess_func_list.h"
27
28 namespace {
29
30 static const uint32 kQuitMessage = 47;
31
32 class IPCChannelPosixTestListener : public IPC::Listener {
33  public:
34   enum STATUS {
35     DISCONNECTED,
36     MESSAGE_RECEIVED,
37     CHANNEL_ERROR,
38     CONNECTED,
39     DENIED,
40     LISTEN_ERROR
41   };
42
43   IPCChannelPosixTestListener(bool quit_only_on_message)
44       : status_(DISCONNECTED),
45         quit_only_on_message_(quit_only_on_message) {
46   }
47
48   virtual ~IPCChannelPosixTestListener() {}
49
50   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
51     EXPECT_EQ(message.type(), kQuitMessage);
52     status_ = MESSAGE_RECEIVED;
53     QuitRunLoop();
54     return true;
55   }
56
57   virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
58     status_ = CONNECTED;
59     if (!quit_only_on_message_) {
60       QuitRunLoop();
61     }
62   }
63
64   virtual void OnChannelError() OVERRIDE {
65     status_ = CHANNEL_ERROR;
66     QuitRunLoop();
67   }
68
69   virtual void OnChannelDenied() OVERRIDE {
70     status_ = DENIED;
71     if (!quit_only_on_message_) {
72       QuitRunLoop();
73     }
74   }
75
76   virtual void OnChannelListenError() OVERRIDE {
77     status_ = LISTEN_ERROR;
78     if (!quit_only_on_message_) {
79       QuitRunLoop();
80     }
81   }
82
83   STATUS status() { return status_; }
84
85   void QuitRunLoop() {
86     base::MessageLoopForIO* loop = base::MessageLoopForIO::current();
87     if (loop->is_running()) {
88       loop->QuitNow();
89     } else {
90       // Die as soon as Run is called.
91       loop->PostTask(FROM_HERE, loop->QuitClosure());
92     }
93   }
94
95  private:
96   // The current status of the listener.
97   STATUS status_;
98   // If |quit_only_on_message_| then the listener will only break out of
99   // the run loop when kQuitMessage is received.
100   bool quit_only_on_message_;
101 };
102
103 class IPCChannelPosixTest : public base::MultiProcessTest {
104  public:
105   static void SetUpSocket(IPC::ChannelHandle *handle,
106                           IPC::Channel::Mode mode);
107   static void SpinRunLoop(base::TimeDelta delay);
108   static const std::string GetConnectionSocketName();
109   static const std::string GetChannelDirName();
110
111  protected:
112   virtual void SetUp();
113   virtual void TearDown();
114
115  private:
116   scoped_ptr<base::MessageLoopForIO> message_loop_;
117 };
118
119 const std::string IPCChannelPosixTest::GetChannelDirName() {
120 #if defined(OS_ANDROID)
121   base::FilePath tmp_dir;
122   PathService::Get(base::DIR_CACHE, &tmp_dir);
123   return tmp_dir.value();
124 #else
125   return "/var/tmp";
126 #endif
127 }
128
129 const std::string IPCChannelPosixTest::GetConnectionSocketName() {
130   return GetChannelDirName() + "/chrome_IPCChannelPosixTest__ConnectionSocket";
131 }
132
133 void IPCChannelPosixTest::SetUp() {
134   MultiProcessTest::SetUp();
135   // Construct a fresh IO Message loop for the duration of each test.
136   message_loop_.reset(new base::MessageLoopForIO());
137 }
138
139 void IPCChannelPosixTest::TearDown() {
140   message_loop_.reset(NULL);
141   MultiProcessTest::TearDown();
142 }
143
144 // Create up a socket and bind and listen to it, or connect it
145 // depending on the |mode|.
146 void IPCChannelPosixTest::SetUpSocket(IPC::ChannelHandle *handle,
147                                       IPC::Channel::Mode mode) {
148   const std::string& name = handle->name;
149
150   int socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
151   ASSERT_GE(socket_fd, 0) << name;
152   ASSERT_GE(fcntl(socket_fd, F_SETFL, O_NONBLOCK), 0);
153   struct sockaddr_un server_address = { 0 };
154   memset(&server_address, 0, sizeof(server_address));
155   server_address.sun_family = AF_UNIX;
156   int path_len = snprintf(server_address.sun_path, IPC::kMaxSocketNameLength,
157                           "%s", name.c_str());
158   DCHECK_EQ(static_cast<int>(name.length()), path_len);
159   size_t server_address_len = offsetof(struct sockaddr_un,
160                                        sun_path) + path_len + 1;
161
162   if (mode == IPC::Channel::MODE_NAMED_SERVER) {
163     // Only one server at a time. Cleanup garbage if it exists.
164     unlink(name.c_str());
165     // Make sure the path we need exists.
166     base::FilePath path(name);
167     base::FilePath dir_path = path.DirName();
168     ASSERT_TRUE(base::CreateDirectory(dir_path));
169     ASSERT_GE(bind(socket_fd,
170                    reinterpret_cast<struct sockaddr *>(&server_address),
171                    server_address_len), 0) << server_address.sun_path
172                                            << ": " << strerror(errno)
173                                            << "(" << errno << ")";
174     ASSERT_GE(listen(socket_fd, SOMAXCONN), 0) << server_address.sun_path
175                                                << ": " << strerror(errno)
176                                                << "(" << errno << ")";
177   } else if (mode == IPC::Channel::MODE_NAMED_CLIENT) {
178     ASSERT_GE(connect(socket_fd,
179                       reinterpret_cast<struct sockaddr *>(&server_address),
180                       server_address_len), 0) << server_address.sun_path
181                                               << ": " << strerror(errno)
182                                               << "(" << errno << ")";
183   } else {
184     FAIL() << "Unknown mode " << mode;
185   }
186   handle->socket.fd = socket_fd;
187 }
188
189 void IPCChannelPosixTest::SpinRunLoop(base::TimeDelta delay) {
190   base::MessageLoopForIO* loop = base::MessageLoopForIO::current();
191   // Post a quit task so that this loop eventually ends and we don't hang
192   // in the case of a bad test. Usually, the run loop will quit sooner than
193   // that because all tests use a IPCChannelPosixTestListener which quits the
194   // current run loop on any channel activity.
195   loop->PostDelayedTask(FROM_HERE, loop->QuitClosure(), delay);
196   loop->Run();
197 }
198
199 TEST_F(IPCChannelPosixTest, BasicListen) {
200   const std::string kChannelName =
201       GetChannelDirName() + "/IPCChannelPosixTest_BasicListen";
202
203   // Test creating a socket that is listening.
204   IPC::ChannelHandle handle(kChannelName);
205   SetUpSocket(&handle, IPC::Channel::MODE_NAMED_SERVER);
206   unlink(handle.name.c_str());
207   IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_SERVER, NULL);
208   ASSERT_TRUE(channel.Connect());
209   ASSERT_TRUE(channel.AcceptsConnections());
210   ASSERT_FALSE(channel.HasAcceptedConnection());
211   channel.ResetToAcceptingConnectionState();
212   ASSERT_FALSE(channel.HasAcceptedConnection());
213 }
214
215 TEST_F(IPCChannelPosixTest, BasicConnected) {
216   // Test creating a socket that is connected.
217   int pipe_fds[2];
218   ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds));
219   std::string socket_name("/var/tmp/IPCChannelPosixTest_BasicConnected");
220   ASSERT_GE(fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK), 0);
221
222   base::FileDescriptor fd(pipe_fds[0], false);
223   IPC::ChannelHandle handle(socket_name, fd);
224   IPC::Channel channel(handle, IPC::Channel::MODE_SERVER, NULL);
225   ASSERT_TRUE(channel.Connect());
226   ASSERT_FALSE(channel.AcceptsConnections());
227   channel.Close();
228   ASSERT_TRUE(IGNORE_EINTR(close(pipe_fds[1])) == 0);
229
230   // Make sure that we can use the socket that is created for us by
231   // a standard channel.
232   IPC::Channel channel2(socket_name, IPC::Channel::MODE_SERVER, NULL);
233   ASSERT_TRUE(channel2.Connect());
234   ASSERT_FALSE(channel2.AcceptsConnections());
235 }
236
237 // If a connection closes right before a Send() call, we may end up closing
238 // the connection without notifying the listener, which can cause hangs in
239 // sync_message_filter and others. Make sure the listener is notified.
240 TEST_F(IPCChannelPosixTest, SendHangTest) {
241   IPCChannelPosixTestListener out_listener(true);
242   IPCChannelPosixTestListener in_listener(true);
243   IPC::ChannelHandle in_handle("IN");
244   IPC::Channel in_chan(in_handle, IPC::Channel::MODE_SERVER, &in_listener);
245   base::FileDescriptor out_fd(in_chan.TakeClientFileDescriptor(), false);
246   IPC::ChannelHandle out_handle("OUT", out_fd);
247   IPC::Channel out_chan(out_handle, IPC::Channel::MODE_CLIENT, &out_listener);
248   ASSERT_TRUE(in_chan.Connect());
249   ASSERT_TRUE(out_chan.Connect());
250   in_chan.Close();  // simulate remote process dying at an unfortunate time.
251   // Send will fail, because it cannot write the message.
252   ASSERT_FALSE(out_chan.Send(new IPC::Message(
253       0,  // routing_id
254       kQuitMessage,  // message type
255       IPC::Message::PRIORITY_NORMAL)));
256   SpinRunLoop(TestTimeouts::action_max_timeout());
257   ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, out_listener.status());
258 }
259
260 // If a connection closes right before a Connect() call, we may end up closing
261 // the connection without notifying the listener, which can cause hangs in
262 // sync_message_filter and others. Make sure the listener is notified.
263 TEST_F(IPCChannelPosixTest, AcceptHangTest) {
264   IPCChannelPosixTestListener out_listener(true);
265   IPCChannelPosixTestListener in_listener(true);
266   IPC::ChannelHandle in_handle("IN");
267   IPC::Channel in_chan(in_handle, IPC::Channel::MODE_SERVER, &in_listener);
268   base::FileDescriptor out_fd(in_chan.TakeClientFileDescriptor(), false);
269   IPC::ChannelHandle out_handle("OUT", out_fd);
270   IPC::Channel out_chan(out_handle, IPC::Channel::MODE_CLIENT, &out_listener);
271   ASSERT_TRUE(in_chan.Connect());
272   in_chan.Close();  // simulate remote process dying at an unfortunate time.
273   ASSERT_FALSE(out_chan.Connect());
274   SpinRunLoop(TestTimeouts::action_max_timeout());
275   ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, out_listener.status());
276 }
277
278 TEST_F(IPCChannelPosixTest, AdvancedConnected) {
279   // Test creating a connection to an external process.
280   IPCChannelPosixTestListener listener(false);
281   IPC::ChannelHandle chan_handle(GetConnectionSocketName());
282   SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
283   IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
284   ASSERT_TRUE(channel.Connect());
285   ASSERT_TRUE(channel.AcceptsConnections());
286   ASSERT_FALSE(channel.HasAcceptedConnection());
287
288   base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
289   ASSERT_TRUE(handle);
290   SpinRunLoop(TestTimeouts::action_max_timeout());
291   ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
292   ASSERT_TRUE(channel.HasAcceptedConnection());
293   IPC::Message* message = new IPC::Message(0,  // routing_id
294                                            kQuitMessage,  // message type
295                                            IPC::Message::PRIORITY_NORMAL);
296   channel.Send(message);
297   SpinRunLoop(TestTimeouts::action_timeout());
298   int exit_code = 0;
299   EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
300   EXPECT_EQ(0, exit_code);
301   ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
302   ASSERT_FALSE(channel.HasAcceptedConnection());
303 }
304
305 TEST_F(IPCChannelPosixTest, ResetState) {
306   // Test creating a connection to an external process. Close the connection,
307   // but continue to listen and make sure another external process can connect
308   // to us.
309   IPCChannelPosixTestListener listener(false);
310   IPC::ChannelHandle chan_handle(GetConnectionSocketName());
311   SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
312   IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
313   ASSERT_TRUE(channel.Connect());
314   ASSERT_TRUE(channel.AcceptsConnections());
315   ASSERT_FALSE(channel.HasAcceptedConnection());
316
317   base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
318   ASSERT_TRUE(handle);
319   SpinRunLoop(TestTimeouts::action_max_timeout());
320   ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
321   ASSERT_TRUE(channel.HasAcceptedConnection());
322   channel.ResetToAcceptingConnectionState();
323   ASSERT_FALSE(channel.HasAcceptedConnection());
324
325   base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixTestConnectionProc");
326   ASSERT_TRUE(handle2);
327   SpinRunLoop(TestTimeouts::action_max_timeout());
328   ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
329   ASSERT_TRUE(channel.HasAcceptedConnection());
330   IPC::Message* message = new IPC::Message(0,  // routing_id
331                                            kQuitMessage,  // message type
332                                            IPC::Message::PRIORITY_NORMAL);
333   channel.Send(message);
334   SpinRunLoop(TestTimeouts::action_timeout());
335   EXPECT_TRUE(base::KillProcess(handle, 0, false));
336   int exit_code = 0;
337   EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
338   EXPECT_EQ(0, exit_code);
339   ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
340   ASSERT_FALSE(channel.HasAcceptedConnection());
341 }
342
343 TEST_F(IPCChannelPosixTest, BadChannelName) {
344   // Test empty name
345   IPC::ChannelHandle handle("");
346   IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_SERVER, NULL);
347   ASSERT_FALSE(channel.Connect());
348
349   // Test name that is too long.
350   const char *kTooLongName = "This_is_a_very_long_name_to_proactively_implement"
351                              "client-centered_synergy_through_top-line"
352                              "platforms_Phosfluorescently_disintermediate_"
353                              "clicks-and-mortar_best_practices_without_"
354                              "future-proof_growth_strategies_Continually"
355                              "pontificate_proactive_potentialities_before"
356                              "leading-edge_processes";
357   EXPECT_GE(strlen(kTooLongName), IPC::kMaxSocketNameLength);
358   IPC::ChannelHandle handle2(kTooLongName);
359   IPC::Channel channel2(handle2, IPC::Channel::MODE_NAMED_SERVER, NULL);
360   EXPECT_FALSE(channel2.Connect());
361 }
362
363 TEST_F(IPCChannelPosixTest, MultiConnection) {
364   // Test setting up a connection to an external process, and then have
365   // another external process attempt to connect to us.
366   IPCChannelPosixTestListener listener(false);
367   IPC::ChannelHandle chan_handle(GetConnectionSocketName());
368   SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
369   IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
370   ASSERT_TRUE(channel.Connect());
371   ASSERT_TRUE(channel.AcceptsConnections());
372   ASSERT_FALSE(channel.HasAcceptedConnection());
373
374   base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
375   ASSERT_TRUE(handle);
376   SpinRunLoop(TestTimeouts::action_max_timeout());
377   ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
378   ASSERT_TRUE(channel.HasAcceptedConnection());
379   base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixFailConnectionProc");
380   ASSERT_TRUE(handle2);
381   SpinRunLoop(TestTimeouts::action_max_timeout());
382   int exit_code = 0;
383   EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
384   EXPECT_EQ(exit_code, 0);
385   ASSERT_EQ(IPCChannelPosixTestListener::DENIED, listener.status());
386   ASSERT_TRUE(channel.HasAcceptedConnection());
387   IPC::Message* message = new IPC::Message(0,  // routing_id
388                                            kQuitMessage,  // message type
389                                            IPC::Message::PRIORITY_NORMAL);
390   channel.Send(message);
391   SpinRunLoop(TestTimeouts::action_timeout());
392   EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
393   EXPECT_EQ(exit_code, 0);
394   ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
395   ASSERT_FALSE(channel.HasAcceptedConnection());
396 }
397
398 TEST_F(IPCChannelPosixTest, DoubleServer) {
399   // Test setting up two servers with the same name.
400   IPCChannelPosixTestListener listener(false);
401   IPCChannelPosixTestListener listener2(false);
402   IPC::ChannelHandle chan_handle(GetConnectionSocketName());
403   IPC::Channel channel(chan_handle, IPC::Channel::MODE_SERVER, &listener);
404   IPC::Channel channel2(chan_handle, IPC::Channel::MODE_SERVER, &listener2);
405   ASSERT_TRUE(channel.Connect());
406   ASSERT_FALSE(channel2.Connect());
407 }
408
409 TEST_F(IPCChannelPosixTest, BadMode) {
410   // Test setting up two servers with a bad mode.
411   IPCChannelPosixTestListener listener(false);
412   IPC::ChannelHandle chan_handle(GetConnectionSocketName());
413   IPC::Channel channel(chan_handle, IPC::Channel::MODE_NONE, &listener);
414   ASSERT_FALSE(channel.Connect());
415 }
416
417 TEST_F(IPCChannelPosixTest, IsNamedServerInitialized) {
418   const std::string& connection_socket_name = GetConnectionSocketName();
419   IPCChannelPosixTestListener listener(false);
420   IPC::ChannelHandle chan_handle(connection_socket_name);
421   ASSERT_TRUE(base::DeleteFile(base::FilePath(connection_socket_name), false));
422   ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
423       connection_socket_name));
424   IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
425   ASSERT_TRUE(IPC::Channel::IsNamedServerInitialized(
426       connection_socket_name));
427   channel.Close();
428   ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
429       connection_socket_name));
430 }
431
432 // A long running process that connects to us
433 MULTIPROCESS_TEST_MAIN(IPCChannelPosixTestConnectionProc) {
434   base::MessageLoopForIO message_loop;
435   IPCChannelPosixTestListener listener(true);
436   IPC::ChannelHandle handle(IPCChannelPosixTest::GetConnectionSocketName());
437   IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT);
438   IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_CLIENT, &listener);
439   EXPECT_TRUE(channel.Connect());
440   IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout());
441   EXPECT_EQ(IPCChannelPosixTestListener::MESSAGE_RECEIVED, listener.status());
442   return 0;
443 }
444
445 // Simple external process that shouldn't be able to connect to us.
446 MULTIPROCESS_TEST_MAIN(IPCChannelPosixFailConnectionProc) {
447   base::MessageLoopForIO message_loop;
448   IPCChannelPosixTestListener listener(false);
449   IPC::ChannelHandle handle(IPCChannelPosixTest::GetConnectionSocketName());
450   IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT);
451   IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_CLIENT, &listener);
452
453   // In this case connect may succeed or fail depending on if the packet
454   // actually gets sent at sendmsg. Since we never delay on send, we may not
455   // see the error. However even if connect succeeds, eventually we will get an
456   // error back since the channel will be closed when we attempt to read from
457   // it.
458   bool connected = channel.Connect();
459   if (connected) {
460     IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout());
461     EXPECT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
462   } else {
463     EXPECT_EQ(IPCChannelPosixTestListener::DISCONNECTED, listener.status());
464   }
465   return 0;
466 }
467
468 }  // namespace