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/files/file_path.h"
16#include "base/files/file_util.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
28namespace {
29
30static const uint32 kQuitMessage = 47;
31
32class 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
103class 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
119const 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
129const std::string IPCChannelPosixTest::GetConnectionSocketName() {
130  return GetChannelDirName() + "/chrome_IPCChannelPosixTest__ConnectionSocket";
131}
132
133void 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
139void 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|.
146void 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
189void 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
199TEST_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  scoped_ptr<IPC::ChannelPosix> channel(
208      new IPC::ChannelPosix(handle, IPC::Channel::MODE_NAMED_SERVER, NULL));
209  ASSERT_TRUE(channel->Connect());
210  ASSERT_TRUE(channel->AcceptsConnections());
211  ASSERT_FALSE(channel->HasAcceptedConnection());
212  channel->ResetToAcceptingConnectionState();
213  ASSERT_FALSE(channel->HasAcceptedConnection());
214}
215
216TEST_F(IPCChannelPosixTest, BasicConnected) {
217  // Test creating a socket that is connected.
218  int pipe_fds[2];
219  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds));
220  std::string socket_name("/var/tmp/IPCChannelPosixTest_BasicConnected");
221  ASSERT_GE(fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK), 0);
222
223  base::FileDescriptor fd(pipe_fds[0], false);
224  IPC::ChannelHandle handle(socket_name, fd);
225  scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
226      handle, IPC::Channel::MODE_SERVER, NULL));
227  ASSERT_TRUE(channel->Connect());
228  ASSERT_FALSE(channel->AcceptsConnections());
229  channel->Close();
230  ASSERT_TRUE(IGNORE_EINTR(close(pipe_fds[1])) == 0);
231
232  // Make sure that we can use the socket that is created for us by
233  // a standard channel.
234  scoped_ptr<IPC::ChannelPosix> channel2(new IPC::ChannelPosix(
235      socket_name, IPC::Channel::MODE_SERVER, NULL));
236  ASSERT_TRUE(channel2->Connect());
237  ASSERT_FALSE(channel2->AcceptsConnections());
238}
239
240// If a connection closes right before a Send() call, we may end up closing
241// the connection without notifying the listener, which can cause hangs in
242// sync_message_filter and others. Make sure the listener is notified.
243TEST_F(IPCChannelPosixTest, SendHangTest) {
244  IPCChannelPosixTestListener out_listener(true);
245  IPCChannelPosixTestListener in_listener(true);
246  IPC::ChannelHandle in_handle("IN");
247  scoped_ptr<IPC::ChannelPosix> in_chan(new IPC::ChannelPosix(
248      in_handle, IPC::Channel::MODE_SERVER, &in_listener));
249  base::FileDescriptor out_fd(
250      in_chan->TakeClientFileDescriptor(), false);
251  IPC::ChannelHandle out_handle("OUT", out_fd);
252  scoped_ptr<IPC::ChannelPosix> out_chan(new IPC::ChannelPosix(
253      out_handle, IPC::Channel::MODE_CLIENT, &out_listener));
254  ASSERT_TRUE(in_chan->Connect());
255  ASSERT_TRUE(out_chan->Connect());
256  in_chan->Close();  // simulate remote process dying at an unfortunate time.
257  // Send will fail, because it cannot write the message.
258  ASSERT_FALSE(out_chan->Send(new IPC::Message(
259      0,  // routing_id
260      kQuitMessage,  // message type
261      IPC::Message::PRIORITY_NORMAL)));
262  SpinRunLoop(TestTimeouts::action_max_timeout());
263  ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, out_listener.status());
264}
265
266// If a connection closes right before a Connect() call, we may end up closing
267// the connection without notifying the listener, which can cause hangs in
268// sync_message_filter and others. Make sure the listener is notified.
269TEST_F(IPCChannelPosixTest, AcceptHangTest) {
270  IPCChannelPosixTestListener out_listener(true);
271  IPCChannelPosixTestListener in_listener(true);
272  IPC::ChannelHandle in_handle("IN");
273  scoped_ptr<IPC::ChannelPosix> in_chan(new IPC::ChannelPosix(
274      in_handle, IPC::Channel::MODE_SERVER, &in_listener));
275  base::FileDescriptor out_fd(
276      in_chan->TakeClientFileDescriptor(), false);
277  IPC::ChannelHandle out_handle("OUT", out_fd);
278  scoped_ptr<IPC::ChannelPosix> out_chan(new IPC::ChannelPosix(
279      out_handle, IPC::Channel::MODE_CLIENT, &out_listener));
280  ASSERT_TRUE(in_chan->Connect());
281  in_chan->Close();  // simulate remote process dying at an unfortunate time.
282  ASSERT_FALSE(out_chan->Connect());
283  SpinRunLoop(TestTimeouts::action_max_timeout());
284  ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, out_listener.status());
285}
286
287TEST_F(IPCChannelPosixTest, AdvancedConnected) {
288  // Test creating a connection to an external process.
289  IPCChannelPosixTestListener listener(false);
290  IPC::ChannelHandle chan_handle(GetConnectionSocketName());
291  SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
292  scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
293      chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener));
294  ASSERT_TRUE(channel->Connect());
295  ASSERT_TRUE(channel->AcceptsConnections());
296  ASSERT_FALSE(channel->HasAcceptedConnection());
297
298  base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
299  ASSERT_TRUE(handle);
300  SpinRunLoop(TestTimeouts::action_max_timeout());
301  ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
302  ASSERT_TRUE(channel->HasAcceptedConnection());
303  IPC::Message* message = new IPC::Message(0,  // routing_id
304                                           kQuitMessage,  // message type
305                                           IPC::Message::PRIORITY_NORMAL);
306  channel->Send(message);
307  SpinRunLoop(TestTimeouts::action_timeout());
308  int exit_code = 0;
309  EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
310  EXPECT_EQ(0, exit_code);
311  ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
312  ASSERT_FALSE(channel->HasAcceptedConnection());
313}
314
315TEST_F(IPCChannelPosixTest, ResetState) {
316  // Test creating a connection to an external process. Close the connection,
317  // but continue to listen and make sure another external process can connect
318  // to us.
319  IPCChannelPosixTestListener listener(false);
320  IPC::ChannelHandle chan_handle(GetConnectionSocketName());
321  SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
322  scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
323      chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener));
324  ASSERT_TRUE(channel->Connect());
325  ASSERT_TRUE(channel->AcceptsConnections());
326  ASSERT_FALSE(channel->HasAcceptedConnection());
327
328  base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
329  ASSERT_TRUE(handle);
330  SpinRunLoop(TestTimeouts::action_max_timeout());
331  ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
332  ASSERT_TRUE(channel->HasAcceptedConnection());
333  channel->ResetToAcceptingConnectionState();
334  ASSERT_FALSE(channel->HasAcceptedConnection());
335
336  base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixTestConnectionProc");
337  ASSERT_TRUE(handle2);
338  SpinRunLoop(TestTimeouts::action_max_timeout());
339  ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
340  ASSERT_TRUE(channel->HasAcceptedConnection());
341  IPC::Message* message = new IPC::Message(0,  // routing_id
342                                           kQuitMessage,  // message type
343                                           IPC::Message::PRIORITY_NORMAL);
344  channel->Send(message);
345  SpinRunLoop(TestTimeouts::action_timeout());
346  EXPECT_TRUE(base::KillProcess(handle, 0, false));
347  int exit_code = 0;
348  EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
349  EXPECT_EQ(0, exit_code);
350  ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
351  ASSERT_FALSE(channel->HasAcceptedConnection());
352}
353
354TEST_F(IPCChannelPosixTest, BadChannelName) {
355  // Test empty name
356  IPC::ChannelHandle handle("");
357  scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
358      handle, IPC::Channel::MODE_NAMED_SERVER, NULL));
359  ASSERT_FALSE(channel->Connect());
360
361  // Test name that is too long.
362  const char *kTooLongName = "This_is_a_very_long_name_to_proactively_implement"
363                             "client-centered_synergy_through_top-line"
364                             "platforms_Phosfluorescently_disintermediate_"
365                             "clicks-and-mortar_best_practices_without_"
366                             "future-proof_growth_strategies_Continually"
367                             "pontificate_proactive_potentialities_before"
368                             "leading-edge_processes";
369  EXPECT_GE(strlen(kTooLongName), IPC::kMaxSocketNameLength);
370  IPC::ChannelHandle handle2(kTooLongName);
371  scoped_ptr<IPC::ChannelPosix> channel2(new IPC::ChannelPosix(
372      handle2, IPC::Channel::MODE_NAMED_SERVER, NULL));
373  EXPECT_FALSE(channel2->Connect());
374}
375
376TEST_F(IPCChannelPosixTest, MultiConnection) {
377  // Test setting up a connection to an external process, and then have
378  // another external process attempt to connect to us.
379  IPCChannelPosixTestListener listener(false);
380  IPC::ChannelHandle chan_handle(GetConnectionSocketName());
381  SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
382  scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
383      chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener));
384  ASSERT_TRUE(channel->Connect());
385  ASSERT_TRUE(channel->AcceptsConnections());
386  ASSERT_FALSE(channel->HasAcceptedConnection());
387
388  base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc");
389  ASSERT_TRUE(handle);
390  SpinRunLoop(TestTimeouts::action_max_timeout());
391  ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
392  ASSERT_TRUE(channel->HasAcceptedConnection());
393  base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixFailConnectionProc");
394  ASSERT_TRUE(handle2);
395  SpinRunLoop(TestTimeouts::action_max_timeout());
396  int exit_code = 0;
397  EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
398  EXPECT_EQ(exit_code, 0);
399  ASSERT_EQ(IPCChannelPosixTestListener::DENIED, listener.status());
400  ASSERT_TRUE(channel->HasAcceptedConnection());
401  IPC::Message* message = new IPC::Message(0,  // routing_id
402                                           kQuitMessage,  // message type
403                                           IPC::Message::PRIORITY_NORMAL);
404  channel->Send(message);
405  SpinRunLoop(TestTimeouts::action_timeout());
406  EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
407  EXPECT_EQ(exit_code, 0);
408  ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
409  ASSERT_FALSE(channel->HasAcceptedConnection());
410}
411
412TEST_F(IPCChannelPosixTest, DoubleServer) {
413  // Test setting up two servers with the same name.
414  IPCChannelPosixTestListener listener(false);
415  IPCChannelPosixTestListener listener2(false);
416  IPC::ChannelHandle chan_handle(GetConnectionSocketName());
417  scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
418      chan_handle, IPC::Channel::MODE_SERVER, &listener));
419  scoped_ptr<IPC::ChannelPosix> channel2(new IPC::ChannelPosix(
420      chan_handle, IPC::Channel::MODE_SERVER, &listener2));
421  ASSERT_TRUE(channel->Connect());
422  ASSERT_FALSE(channel2->Connect());
423}
424
425TEST_F(IPCChannelPosixTest, BadMode) {
426  // Test setting up two servers with a bad mode.
427  IPCChannelPosixTestListener listener(false);
428  IPC::ChannelHandle chan_handle(GetConnectionSocketName());
429  scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
430      chan_handle, IPC::Channel::MODE_NONE, &listener));
431  ASSERT_FALSE(channel->Connect());
432}
433
434TEST_F(IPCChannelPosixTest, IsNamedServerInitialized) {
435  const std::string& connection_socket_name = GetConnectionSocketName();
436  IPCChannelPosixTestListener listener(false);
437  IPC::ChannelHandle chan_handle(connection_socket_name);
438  ASSERT_TRUE(base::DeleteFile(base::FilePath(connection_socket_name), false));
439  ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
440      connection_socket_name));
441  scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
442      chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener));
443  ASSERT_TRUE(IPC::Channel::IsNamedServerInitialized(
444      connection_socket_name));
445  channel->Close();
446  ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
447      connection_socket_name));
448}
449
450// A long running process that connects to us
451MULTIPROCESS_TEST_MAIN(IPCChannelPosixTestConnectionProc) {
452  base::MessageLoopForIO message_loop;
453  IPCChannelPosixTestListener listener(true);
454  IPC::ChannelHandle handle(IPCChannelPosixTest::GetConnectionSocketName());
455  IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT);
456  scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
457      handle, IPC::Channel::MODE_NAMED_CLIENT, &listener));
458  EXPECT_TRUE(channel->Connect());
459  IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout());
460  EXPECT_EQ(IPCChannelPosixTestListener::MESSAGE_RECEIVED, listener.status());
461  return 0;
462}
463
464// Simple external process that shouldn't be able to connect to us.
465MULTIPROCESS_TEST_MAIN(IPCChannelPosixFailConnectionProc) {
466  base::MessageLoopForIO message_loop;
467  IPCChannelPosixTestListener listener(false);
468  IPC::ChannelHandle handle(IPCChannelPosixTest::GetConnectionSocketName());
469  IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT);
470  scoped_ptr<IPC::ChannelPosix> channel(new IPC::ChannelPosix(
471      handle, IPC::Channel::MODE_NAMED_CLIENT, &listener));
472
473  // In this case connect may succeed or fail depending on if the packet
474  // actually gets sent at sendmsg. Since we never delay on send, we may not
475  // see the error. However even if connect succeeds, eventually we will get an
476  // error back since the channel will be closed when we attempt to read from
477  // it.
478  bool connected = channel->Connect();
479  if (connected) {
480    IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout());
481    EXPECT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
482  } else {
483    EXPECT_EQ(IPCChannelPosixTestListener::DISCONNECTED, listener.status());
484  }
485  return 0;
486}
487
488}  // namespace
489