blob: aa5da1526ad916c01634f4775e7e05be00cbf2da [file] [log] [blame]
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +09001// 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#elif defined(OS_POSIX)
10#include <sys/types.h>
11#include <unistd.h>
12#endif
13
14#include <stdio.h>
15#include <string>
16#include <utility>
17
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090018#include "base/command_line.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090019#include "base/pickle.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090020#include "base/threading/thread.h"
21#include "base/time.h"
22#include "ipc/ipc_descriptors.h"
23#include "ipc/ipc_channel.h"
24#include "ipc/ipc_channel_proxy.h"
25#include "ipc/ipc_message_utils.h"
26#include "ipc/ipc_multiprocess_test.h"
27#include "ipc/ipc_sender.h"
28#include "ipc/ipc_switches.h"
29#include "ipc/ipc_test_base.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090030
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090031namespace {
32
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090033const size_t kLongMessageStringNumBytes = 50000;
34
35class IPCChannelTest : public IPCTestBase {
36};
37
38TEST_F(IPCChannelTest, BasicMessageTest) {
39 int v1 = 10;
40 std::string v2("foobar");
41 std::wstring v3(L"hello world");
42
43 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
44 EXPECT_TRUE(m.WriteInt(v1));
45 EXPECT_TRUE(m.WriteString(v2));
46 EXPECT_TRUE(m.WriteWString(v3));
47
48 PickleIterator iter(m);
49
50 int vi;
51 std::string vs;
52 std::wstring vw;
53
54 EXPECT_TRUE(m.ReadInt(&iter, &vi));
55 EXPECT_EQ(v1, vi);
56
57 EXPECT_TRUE(m.ReadString(&iter, &vs));
58 EXPECT_EQ(v2, vs);
59
60 EXPECT_TRUE(m.ReadWString(&iter, &vw));
61 EXPECT_EQ(v3, vw);
62
63 // should fail
64 EXPECT_FALSE(m.ReadInt(&iter, &vi));
65 EXPECT_FALSE(m.ReadString(&iter, &vs));
66 EXPECT_FALSE(m.ReadWString(&iter, &vw));
67}
68
69static void Send(IPC::Sender* sender, const char* text) {
70 static int message_index = 0;
71
72 IPC::Message* message = new IPC::Message(0,
73 2,
74 IPC::Message::PRIORITY_NORMAL);
75 message->WriteInt(message_index++);
76 message->WriteString(std::string(text));
77
78 // Make sure we can handle large messages.
79 char junk[kLongMessageStringNumBytes];
80 memset(junk, 'a', sizeof(junk)-1);
81 junk[sizeof(junk)-1] = 0;
82 message->WriteString(std::string(junk));
83
84 // DEBUG: printf("[%u] sending message [%s]\n", GetCurrentProcessId(), text);
85 sender->Send(message);
86}
87
88class MyChannelListener : public IPC::Listener {
89 public:
90 virtual bool OnMessageReceived(const IPC::Message& message) {
91 PickleIterator iter(message);
92
93 int ignored;
94 EXPECT_TRUE(iter.ReadInt(&ignored));
95 std::string data;
96 EXPECT_TRUE(iter.ReadString(&data));
97 std::string big_string;
98 EXPECT_TRUE(iter.ReadString(&big_string));
99 EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length());
100
101
102 if (--messages_left_ == 0) {
103 MessageLoop::current()->Quit();
104 } else {
105 Send(sender_, "Foo");
106 }
107 return true;
108 }
109
110 virtual void OnChannelError() {
111 // There is a race when closing the channel so the last message may be lost.
112 EXPECT_LE(messages_left_, 1);
113 MessageLoop::current()->Quit();
114 }
115
116 void Init(IPC::Sender* s) {
117 sender_ = s;
118 messages_left_ = 50;
119 }
120
121 private:
122 IPC::Sender* sender_;
123 int messages_left_;
124};
125
126TEST_F(IPCChannelTest, ChannelTest) {
127 MyChannelListener channel_listener;
128 // Setup IPC channel.
129 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
130 &channel_listener);
131 ASSERT_TRUE(chan.Connect());
132
133 channel_listener.Init(&chan);
134
135 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
136 ASSERT_TRUE(process_handle);
137
138 Send(&chan, "hello from parent");
139
140 // Run message loop.
141 MessageLoop::current()->Run();
142
143 // Close Channel so client gets its OnChannelError() callback fired.
144 chan.Close();
145
146 // Cleanup child process.
147 EXPECT_TRUE(base::WaitForSingleProcess(
148 process_handle, base::TimeDelta::FromSeconds(5)));
149 base::CloseProcessHandle(process_handle);
150}
151
152#if defined(OS_WIN)
153TEST_F(IPCChannelTest, ChannelTestExistingPipe) {
154 MyChannelListener channel_listener;
155 // Setup IPC channel with existing pipe. Specify name in Chrome format.
156 std::string name("\\\\.\\pipe\\chrome.");
157 name.append(kTestClientChannel);
158 const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
159 FILE_FLAG_FIRST_PIPE_INSTANCE;
160 HANDLE pipe = CreateNamedPipeA(name.c_str(),
161 open_mode,
162 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
163 1,
164 4096,
165 4096,
166 5000,
167 NULL);
168 IPC::Channel chan(IPC::ChannelHandle(pipe), IPC::Channel::MODE_SERVER,
169 &channel_listener);
170 // Channel will duplicate the handle.
171 CloseHandle(pipe);
172 ASSERT_TRUE(chan.Connect());
173
174 channel_listener.Init(&chan);
175
176 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &chan);
177 ASSERT_TRUE(process_handle);
178
179 Send(&chan, "hello from parent");
180
181 // Run message loop.
182 MessageLoop::current()->Run();
183
184 // Close Channel so client gets its OnChannelError() callback fired.
185 chan.Close();
186
187 // Cleanup child process.
188 EXPECT_TRUE(base::WaitForSingleProcess(
189 process_handle, base::TimeDelta::FromSeconds(5)));
190 base::CloseProcessHandle(process_handle);
191}
192#endif // defined (OS_WIN)
193
194TEST_F(IPCChannelTest, ChannelProxyTest) {
195 MyChannelListener channel_listener;
196
197 // The thread needs to out-live the ChannelProxy.
198 base::Thread thread("ChannelProxyTestServer");
199 base::Thread::Options options;
200 options.message_loop_type = MessageLoop::TYPE_IO;
201 thread.StartWithOptions(options);
202 {
203 // setup IPC channel proxy
204 IPC::ChannelProxy chan(kTestClientChannel, IPC::Channel::MODE_SERVER,
205 &channel_listener, thread.message_loop_proxy());
206
207 channel_listener.Init(&chan);
208
209#if defined(OS_WIN)
210 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, NULL);
211#elif defined(OS_POSIX)
212 bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch(
213 switches::kDebugChildren);
214 base::FileHandleMappingVector fds_to_map;
215 const int ipcfd = chan.GetClientFileDescriptor();
216 if (ipcfd > -1) {
217 fds_to_map.push_back(std::pair<int, int>(ipcfd, kPrimaryIPCChannel + 3));
218 }
219
220 base::ProcessHandle process_handle = MultiProcessTest::SpawnChild(
221 "RunTestClient",
222 fds_to_map,
223 debug_on_start);
224#endif // defined(OS_POSIX)
225
226 ASSERT_TRUE(process_handle);
227
228 Send(&chan, "hello from parent");
229
230 // run message loop
231 MessageLoop::current()->Run();
232
233 // cleanup child process
234 EXPECT_TRUE(base::WaitForSingleProcess(
235 process_handle, base::TimeDelta::FromSeconds(5)));
236 base::CloseProcessHandle(process_handle);
237 }
238 thread.Stop();
239}
240
241class ChannelListenerWithOnConnectedSend : public IPC::Listener {
242 public:
243 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
244 SendNextMessage();
245 }
246
247 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
248 PickleIterator iter(message);
249
250 int ignored;
251 EXPECT_TRUE(iter.ReadInt(&ignored));
252 std::string data;
253 EXPECT_TRUE(iter.ReadString(&data));
254 std::string big_string;
255 EXPECT_TRUE(iter.ReadString(&big_string));
256 EXPECT_EQ(kLongMessageStringNumBytes - 1, big_string.length());
257 SendNextMessage();
258 return true;
259 }
260
261 virtual void OnChannelError() OVERRIDE {
262 // There is a race when closing the channel so the last message may be lost.
263 EXPECT_LE(messages_left_, 1);
264 MessageLoop::current()->Quit();
265 }
266
267 void Init(IPC::Sender* s) {
268 sender_ = s;
269 messages_left_ = 50;
270 }
271
272 private:
273 void SendNextMessage() {
274 if (--messages_left_ == 0) {
275 MessageLoop::current()->Quit();
276 } else {
277 Send(sender_, "Foo");
278 }
279 }
280
281 IPC::Sender* sender_;
282 int messages_left_;
283};
284
285#if defined(OS_WIN)
286// Acting flakey in Windows. http://crbug.com/129595
287#define MAYBE_SendMessageInChannelConnected DISABLED_SendMessageInChannelConnected
288#else
289#define MAYBE_SendMessageInChannelConnected SendMessageInChannelConnected
290#endif
291TEST_F(IPCChannelTest, MAYBE_SendMessageInChannelConnected) {
292 // This tests the case of a listener sending back an event in it's
293 // OnChannelConnected handler.
294
295 ChannelListenerWithOnConnectedSend channel_listener;
296 // Setup IPC channel.
297 IPC::Channel channel(kTestClientChannel, IPC::Channel::MODE_SERVER,
298 &channel_listener);
299 channel_listener.Init(&channel);
300 ASSERT_TRUE(channel.Connect());
301
302 base::ProcessHandle process_handle = SpawnChild(TEST_CLIENT, &channel);
303 ASSERT_TRUE(process_handle);
304
305 Send(&channel, "hello from parent");
306
307 // Run message loop.
308 MessageLoop::current()->Run();
309
310 // Close Channel so client gets its OnChannelError() callback fired.
311 channel.Close();
312
313 // Cleanup child process.
314 EXPECT_TRUE(base::WaitForSingleProcess(
315 process_handle, base::TimeDelta::FromSeconds(5)));
316 base::CloseProcessHandle(process_handle);
317}
318
319MULTIPROCESS_IPC_TEST_MAIN(RunTestClient) {
320 MessageLoopForIO main_message_loop;
321 MyChannelListener channel_listener;
322
323 // setup IPC channel
324 IPC::Channel chan(kTestClientChannel, IPC::Channel::MODE_CLIENT,
325 &channel_listener);
326 CHECK(chan.Connect());
327 channel_listener.Init(&chan);
328 Send(&chan, "hello from child");
329 // run message loop
330 MessageLoop::current()->Run();
331 return 0;
332}
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +0900333
334} // namespace