blob: 4b2dd131a92048f3c9c5e45ce3594b9013f3119f [file] [log] [blame]
brettw@google.com7c5cc672011-01-01 11:17:08 +09001// Copyright (c) 2010 The Chromium Authors. All rights reserved.
sehr@google.com4f325aa2009-11-25 01:14:53 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +09005#include "base/sync_socket.h"
6
sehr@google.com4f325aa2009-11-25 01:14:53 +09007#include <stdio.h>
sehr@google.com4f325aa2009-11-25 01:14:53 +09008#include <string>
9#include <sstream>
10
11#include "base/message_loop.h"
sehr@google.com4f325aa2009-11-25 01:14:53 +090012#include "base/process_util.h"
brettw@google.com7c5cc672011-01-01 11:17:08 +090013#include "build/build_config.h"
sehr@google.com4f325aa2009-11-25 01:14:53 +090014#include "ipc/ipc_channel.h"
15#include "ipc/ipc_channel_proxy.h"
brettw@google.com7c5cc672011-01-01 11:17:08 +090016#include "ipc/ipc_message_macros.h"
sehr@google.com4f325aa2009-11-25 01:14:53 +090017#include "ipc/ipc_message_utils.h"
erg@google.come6ffcb52010-08-18 03:38:24 +090018#include "ipc/ipc_message_utils_impl.h"
sehr@google.com4f325aa2009-11-25 01:14:53 +090019#include "ipc/ipc_tests.h"
20#include "testing/gtest/include/gtest/gtest.h"
21#include "testing/multiprocess_func_list.h"
22
brettw@google.com7c5cc672011-01-01 11:17:08 +090023#if defined(OS_LINUX) || defined(OS_MACOSX)
24#include "base/file_descriptor_posix.h"
25#endif // defined(OS_LINUX) || defined(OS_MACOSX)
sehr@google.com4f325aa2009-11-25 01:14:53 +090026
27enum IPCMessageIds {
28 UNUSED_IPC_TYPE,
29 SERVER_FIRST_IPC_TYPE, // SetHandle message sent to server.
30 SERVER_SECOND_IPC_TYPE, // Shutdown message sent to server.
31 CLIENT_FIRST_IPC_TYPE // Response message sent to client.
32};
33
34namespace {
35const char kHelloString[] = "Hello, SyncSocket Client";
36const size_t kHelloStringLength = arraysize(kHelloString);
37} // namespace
38
sehr@google.comfdc90062009-11-26 09:28:02 +090039// Message class to pass a base::SyncSocket::Handle to another process.
40// This is not as easy as it sounds, because of the differences in transferring
41// Windows HANDLEs versus posix file descriptors.
42#if defined(OS_WIN)
sehr@google.com4f325aa2009-11-25 01:14:53 +090043class MsgClassSetHandle
44 : public IPC::MessageWithTuple< Tuple1<base::SyncSocket::Handle> > {
45 public:
46 enum { ID = SERVER_FIRST_IPC_TYPE };
47 explicit MsgClassSetHandle(const base::SyncSocket::Handle arg1)
48 : IPC::MessageWithTuple< Tuple1<base::SyncSocket::Handle> >(
49 MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {}
50
51 private:
52 DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle);
53};
sehr@google.comfdc90062009-11-26 09:28:02 +090054#elif defined(OS_POSIX)
55class MsgClassSetHandle
56 : public IPC::MessageWithTuple< Tuple1<base::FileDescriptor> > {
57 public:
58 enum { ID = SERVER_FIRST_IPC_TYPE };
59 explicit MsgClassSetHandle(const base::FileDescriptor& arg1)
60 : IPC::MessageWithTuple< Tuple1<base::FileDescriptor> >(
61 MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {}
62
63 private:
64 DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle);
65};
66#else
67# error "What platform?"
68#endif // defined(OS_WIN)
sehr@google.com4f325aa2009-11-25 01:14:53 +090069
70// Message class to pass a response to the server.
71class MsgClassResponse
72 : public IPC::MessageWithTuple< Tuple1<std::string> > {
73 public:
74 enum { ID = CLIENT_FIRST_IPC_TYPE };
75 explicit MsgClassResponse(const std::string& arg1)
76 : IPC::MessageWithTuple< Tuple1<std::string> >(
77 MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {}
78
79 private:
80 DISALLOW_COPY_AND_ASSIGN(MsgClassResponse);
81};
82
83// Message class to tell the server to shut down.
84class MsgClassShutdown
85 : public IPC::MessageWithTuple< Tuple0 > {
86 public:
87 enum { ID = SERVER_SECOND_IPC_TYPE };
88 MsgClassShutdown()
89 : IPC::MessageWithTuple< Tuple0 >(
90 MSG_ROUTING_CONTROL, ID, MakeTuple()) {}
91
92 private:
93 DISALLOW_COPY_AND_ASSIGN(MsgClassShutdown);
94};
95
96// The SyncSocket server listener class processes two sorts of
97// messages from the client.
98class SyncSocketServerListener : public IPC::Channel::Listener {
99 public:
100 SyncSocketServerListener() : chan_(NULL) {
101 }
102
103 void Init(IPC::Channel* chan) {
104 chan_ = chan;
105 }
106
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900107 virtual bool OnMessageReceived(const IPC::Message& msg) {
sehr@google.com4f325aa2009-11-25 01:14:53 +0900108 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
109 IPC_BEGIN_MESSAGE_MAP(SyncSocketServerListener, msg)
110 IPC_MESSAGE_HANDLER(MsgClassSetHandle, OnMsgClassSetHandle)
111 IPC_MESSAGE_HANDLER(MsgClassShutdown, OnMsgClassShutdown)
112 IPC_END_MESSAGE_MAP()
113 }
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900114 return true;
sehr@google.com4f325aa2009-11-25 01:14:53 +0900115 }
116
117 private:
118 // This sort of message is sent first, causing the transfer of
119 // the handle for the SyncSocket. This message sends a buffer
120 // on the SyncSocket and then sends a response to the client.
sehr@google.comfdc90062009-11-26 09:28:02 +0900121#if defined(OS_WIN)
sehr@google.com4f325aa2009-11-25 01:14:53 +0900122 void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) {
sehr@google.comfdc90062009-11-26 09:28:02 +0900123 SetHandle(handle);
124 }
125#elif defined(OS_POSIX)
126 void OnMsgClassSetHandle(const base::FileDescriptor& fd_struct) {
127 SetHandle(fd_struct.fd);
128 }
129#else
130# error "What platform?"
131#endif // defined(OS_WIN)
132
133 void SetHandle(base::SyncSocket::Handle handle) {
sehr@google.com4f325aa2009-11-25 01:14:53 +0900134 base::SyncSocket sync_socket(handle);
135 EXPECT_EQ(sync_socket.Send(static_cast<const void*>(kHelloString),
136 kHelloStringLength), kHelloStringLength);
137 IPC::Message* msg = new MsgClassResponse(kHelloString);
sehr@google.com4f325aa2009-11-25 01:14:53 +0900138 EXPECT_TRUE(chan_->Send(msg));
139 }
140
141 // When the client responds, it sends back a shutdown message,
142 // which causes the message loop to exit.
143 void OnMsgClassShutdown() {
144 MessageLoop::current()->Quit();
145 }
146
147 IPC::Channel* chan_;
148
149 DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener);
150};
151
152// Runs the fuzzing server child mode. Returns when the preset number
153// of messages have been received.
154MULTIPROCESS_TEST_MAIN(RunSyncSocketServer) {
155 MessageLoopForIO main_message_loop;
156 SyncSocketServerListener listener;
157 IPC::Channel chan(kSyncSocketChannel, IPC::Channel::MODE_CLIENT, &listener);
158 EXPECT_TRUE(chan.Connect());
159 listener.Init(&chan);
160 MessageLoop::current()->Run();
161 return 0;
162}
163
164// The SyncSocket client listener only processes one sort of message,
165// a response from the server.
166class SyncSocketClientListener : public IPC::Channel::Listener {
167 public:
168 SyncSocketClientListener() {
169 }
170
171 void Init(base::SyncSocket* socket, IPC::Channel* chan) {
172 socket_ = socket;
173 chan_ = chan;
174 }
175
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900176 virtual bool OnMessageReceived(const IPC::Message& msg) {
sehr@google.com4f325aa2009-11-25 01:14:53 +0900177 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
178 IPC_BEGIN_MESSAGE_MAP(SyncSocketClientListener, msg)
179 IPC_MESSAGE_HANDLER(MsgClassResponse, OnMsgClassResponse)
180 IPC_END_MESSAGE_MAP()
181 }
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900182 return true;
sehr@google.com4f325aa2009-11-25 01:14:53 +0900183 }
184
185 private:
186 // When a response is received from the server, it sends the same
187 // string as was written on the SyncSocket. These are compared
188 // and a shutdown message is sent back to the server.
189 void OnMsgClassResponse(const std::string& str) {
cpu@chromium.org750392c2009-12-05 07:53:22 +0900190 // We rely on the order of sync_socket.Send() and chan_->Send() in
191 // the SyncSocketServerListener object.
192 EXPECT_EQ(kHelloStringLength, socket_->Peek());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900193 char buf[kHelloStringLength];
194 socket_->Receive(static_cast<void*>(buf), kHelloStringLength);
195 EXPECT_EQ(strcmp(str.c_str(), buf), 0);
sehr@google.comb72918f2009-12-07 04:45:08 +0900196 // After receiving from the socket there should be no bytes left.
thomasvl@google.com9a242072010-07-23 23:18:59 +0900197 EXPECT_EQ(0U, socket_->Peek());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900198 IPC::Message* msg = new MsgClassShutdown();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900199 EXPECT_TRUE(chan_->Send(msg));
200 MessageLoop::current()->Quit();
201 }
202
203 base::SyncSocket* socket_;
204 IPC::Channel* chan_;
205
206 DISALLOW_COPY_AND_ASSIGN(SyncSocketClientListener);
207};
208
209class SyncSocketTest : public IPCChannelTest {
210};
211
212TEST_F(SyncSocketTest, SanityTest) {
213 SyncSocketClientListener listener;
214 IPC::Channel chan(kSyncSocketChannel, IPC::Channel::MODE_SERVER,
215 &listener);
216 base::ProcessHandle server_process = SpawnChild(SYNC_SOCKET_SERVER, &chan);
217 ASSERT_TRUE(server_process);
218 // Create a pair of SyncSockets.
219 base::SyncSocket* pair[2];
220 base::SyncSocket::CreatePair(pair);
sehr@google.comb72918f2009-12-07 04:45:08 +0900221 // Immediately after creation there should be no pending bytes.
thomasvl@google.com9a242072010-07-23 23:18:59 +0900222 EXPECT_EQ(0U, pair[0]->Peek());
223 EXPECT_EQ(0U, pair[1]->Peek());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900224 base::SyncSocket::Handle target_handle;
sehr@google.comfdc90062009-11-26 09:28:02 +0900225 // Connect the channel and listener.
226 ASSERT_TRUE(chan.Connect());
227 listener.Init(pair[0], &chan);
sehr@google.com4f325aa2009-11-25 01:14:53 +0900228#if defined(OS_WIN)
229 // On windows we need to duplicate the handle into the server process.
230 BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1]->handle(),
231 server_process, &target_handle,
232 0, FALSE, DUPLICATE_SAME_ACCESS);
233 EXPECT_TRUE(retval);
sehr@google.com4f325aa2009-11-25 01:14:53 +0900234 // Set up a message to pass the handle to the server.
235 IPC::Message* msg = new MsgClassSetHandle(target_handle);
sehr@google.comfdc90062009-11-26 09:28:02 +0900236#else
237 target_handle = pair[1]->handle();
238 // Set up a message to pass the handle to the server.
239 base::FileDescriptor filedesc(target_handle, false);
240 IPC::Message* msg = new MsgClassSetHandle(filedesc);
241#endif // defined(OS_WIN)
sehr@google.com4f325aa2009-11-25 01:14:53 +0900242 EXPECT_TRUE(chan.Send(msg));
243 // Use the current thread as the I/O thread.
244 MessageLoop::current()->Run();
245 // Shut down.
246 delete pair[0];
247 delete pair[1];
248 EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000));
249 base::CloseProcessHandle(server_process);
250}