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#include "build/build_config.h"
6
7#if defined(OS_WIN)
8#include <windows.h>
9#endif
10
11#include <string>
12
13#include "base/message_loop/message_loop.h"
14#include "base/pickle.h"
15#include "base/threading/thread.h"
16#include "ipc/ipc_message.h"
17#include "ipc/ipc_test_base.h"
18
19namespace {
20
21const size_t kLongMessageStringNumBytes = 50000;
22
23static void Send(IPC::Sender* sender, const char* text) {
24  static int message_index = 0;
25
26  IPC::Message* message = new IPC::Message(0,
27                                           2,
28                                           IPC::Message::PRIORITY_NORMAL);
29  message->WriteInt(message_index++);
30  message->WriteString(std::string(text));
31
32  // Make sure we can handle large messages.
33  char junk[kLongMessageStringNumBytes];
34  memset(junk, 'a', sizeof(junk)-1);
35  junk[sizeof(junk)-1] = 0;
36  message->WriteString(std::string(junk));
37
38  // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
39  sender->Send(message);
40}
41
42// A generic listener that expects messages of a certain type (see
43// OnMessageReceived()), and either sends a generic response or quits after the
44// 50th message (or on channel error).
45class GenericChannelListener : public IPC::Listener {
46 public:
47  GenericChannelListener() : sender_(NULL), messages_left_(50) {}
48  virtual ~GenericChannelListener() {}
49
50  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
51    PickleIterator iter(message);
52
53    int ignored;
54    EXPECT_TRUE(iter.ReadInt(&ignored));
55    std::string data;
56    EXPECT_TRUE(iter.ReadString(&data));
57    std::string big_string;
58    EXPECT_TRUE(iter.ReadString(&big_string));
59    EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length());
60
61    SendNextMessage();
62    return true;
63  }
64
65  virtual void OnChannelError() OVERRIDE {
66    // There is a race when closing the channel so the last message may be lost.
67    EXPECT_LE(messages_left_, 1);
68    base::MessageLoop::current()->Quit();
69  }
70
71  void Init(IPC::Sender* s) {
72    sender_ = s;
73  }
74
75 protected:
76  void SendNextMessage() {
77    if (--messages_left_ <= 0)
78      base::MessageLoop::current()->Quit();
79    else
80      Send(sender_, "Foo");
81  }
82
83 private:
84  IPC::Sender* sender_;
85  int messages_left_;
86};
87
88class IPCChannelTest : public IPCTestBase {
89};
90
91// TODO(viettrungluu): Move to a separate IPCMessageTest.
92TEST_F(IPCChannelTest, BasicMessageTest) {
93  int v1 = 10;
94  std::string v2("foobar");
95  std::wstring v3(L"hello world");
96
97  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
98  EXPECT_TRUE(m.WriteInt(v1));
99  EXPECT_TRUE(m.WriteString(v2));
100  EXPECT_TRUE(m.WriteWString(v3));
101
102  PickleIterator iter(m);
103
104  int vi;
105  std::string vs;
106  std::wstring vw;
107
108  EXPECT_TRUE(m.ReadInt(&iter, &vi));
109  EXPECT_EQ(v1, vi);
110
111  EXPECT_TRUE(m.ReadString(&iter, &vs));
112  EXPECT_EQ(v2, vs);
113
114  EXPECT_TRUE(m.ReadWString(&iter, &vw));
115  EXPECT_EQ(v3, vw);
116
117  // should fail
118  EXPECT_FALSE(m.ReadInt(&iter, &vi));
119  EXPECT_FALSE(m.ReadString(&iter, &vs));
120  EXPECT_FALSE(m.ReadWString(&iter, &vw));
121}
122
123TEST_F(IPCChannelTest, ChannelTest) {
124  Init("GenericClient");
125
126  // Set up IPC channel and start client.
127  GenericChannelListener listener;
128  CreateChannel(&listener);
129  listener.Init(sender());
130  ASSERT_TRUE(ConnectChannel());
131  ASSERT_TRUE(StartClient());
132
133  Send(sender(), "hello from parent");
134
135  // Run message loop.
136  base::MessageLoop::current()->Run();
137
138  // Close the channel so the client's OnChannelError() gets fired.
139  channel()->Close();
140
141  EXPECT_TRUE(WaitForClientShutdown());
142  DestroyChannel();
143}
144
145// TODO(viettrungluu): Move to a separate IPCChannelWinTest.
146#if defined(OS_WIN)
147TEST_F(IPCChannelTest, ChannelTestExistingPipe) {
148  Init("GenericClient");
149
150  // Create pipe manually using the standard Chromium name and set up IPC
151  // channel.
152  GenericChannelListener listener;
153  std::string name("\\\\.\\pipe\\chrome.");
154  name.append(GetChannelName("GenericClient"));
155  HANDLE pipe = CreateNamedPipeA(name.c_str(),
156                                 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
157                                     FILE_FLAG_FIRST_PIPE_INSTANCE,
158                                 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
159                                 1,
160                                 4096,
161                                 4096,
162                                 5000,
163                                 NULL);
164  CreateChannelFromChannelHandle(IPC::ChannelHandle(pipe), &listener);
165  CloseHandle(pipe);  // The channel duplicates the handle.
166  listener.Init(sender());
167
168  // Connect to channel and start client.
169  ASSERT_TRUE(ConnectChannel());
170  ASSERT_TRUE(StartClient());
171
172  Send(sender(), "hello from parent");
173
174  // Run message loop.
175  base::MessageLoop::current()->Run();
176
177  // Close the channel so the client's OnChannelError() gets fired.
178  channel()->Close();
179
180  EXPECT_TRUE(WaitForClientShutdown());
181  DestroyChannel();
182}
183#endif  // defined (OS_WIN)
184
185TEST_F(IPCChannelTest, ChannelProxyTest) {
186  Init("GenericClient");
187
188  base::Thread thread("ChannelProxyTestServer");
189  base::Thread::Options options;
190  options.message_loop_type = base::MessageLoop::TYPE_IO;
191  thread.StartWithOptions(options);
192
193  // Set up IPC channel proxy.
194  GenericChannelListener listener;
195  CreateChannelProxy(&listener, thread.message_loop_proxy().get());
196  listener.Init(sender());
197
198  ASSERT_TRUE(StartClient());
199
200  Send(sender(), "hello from parent");
201
202  // Run message loop.
203  base::MessageLoop::current()->Run();
204
205  EXPECT_TRUE(WaitForClientShutdown());
206
207  // Destroy the channel proxy before shutting down the thread.
208  DestroyChannelProxy();
209  thread.Stop();
210}
211
212class ChannelListenerWithOnConnectedSend : public GenericChannelListener {
213 public:
214  ChannelListenerWithOnConnectedSend() {}
215  virtual ~ChannelListenerWithOnConnectedSend() {}
216
217  virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
218    SendNextMessage();
219  }
220};
221
222#if defined(OS_WIN)
223// Acting flakey in Windows. http://crbug.com/129595
224#define MAYBE_SendMessageInChannelConnected DISABLED_SendMessageInChannelConnected
225#else
226#define MAYBE_SendMessageInChannelConnected SendMessageInChannelConnected
227#endif
228// This tests the case of a listener sending back an event in its
229// OnChannelConnected handler.
230TEST_F(IPCChannelTest, MAYBE_SendMessageInChannelConnected) {
231  Init("GenericClient");
232
233  // Set up IPC channel and start client.
234  ChannelListenerWithOnConnectedSend listener;
235  CreateChannel(&listener);
236  listener.Init(sender());
237  ASSERT_TRUE(ConnectChannel());
238  ASSERT_TRUE(StartClient());
239
240  Send(sender(), "hello from parent");
241
242  // Run message loop.
243  base::MessageLoop::current()->Run();
244
245  // Close the channel so the client's OnChannelError() gets fired.
246  channel()->Close();
247
248  EXPECT_TRUE(WaitForClientShutdown());
249  DestroyChannel();
250}
251
252MULTIPROCESS_IPC_TEST_CLIENT_MAIN(GenericClient) {
253  base::MessageLoopForIO main_message_loop;
254  GenericChannelListener listener;
255
256  // Set up IPC channel.
257  IPC::Channel channel(IPCTestBase::GetChannelName("GenericClient"),
258                       IPC::Channel::MODE_CLIENT,
259                       &listener);
260  CHECK(channel.Connect());
261  listener.Init(&channel);
262  Send(&channel, "hello from child");
263
264  base::MessageLoop::current()->Run();
265  return 0;
266}
267
268}  // namespace
269