1 // Copyright (c) 2010 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.
5 #include "base/sync_socket.h"
11 #include "base/message_loop.h"
12 #include "base/process_util.h"
13 #include "build/build_config.h"
14 #include "ipc/ipc_channel.h"
15 #include "ipc/ipc_channel_proxy.h"
16 #include "ipc/ipc_message_macros.h"
17 #include "ipc/ipc_message_utils.h"
18 #include "ipc/ipc_message_utils_impl.h"
19 #include "ipc/ipc_tests.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "testing/multiprocess_func_list.h"
24 #include "base/file_descriptor_posix.h"
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.
35 const char kHelloString
[] = "Hello, SyncSocket Client";
36 const size_t kHelloStringLength
= arraysize(kHelloString
);
39 // 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.
43 class MsgClassSetHandle
44 : public IPC::MessageWithTuple
< Tuple1
<base::SyncSocket::Handle
> > {
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
)) {}
52 DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle
);
54 #elif defined(OS_POSIX)
55 class MsgClassSetHandle
56 : public IPC::MessageWithTuple
< Tuple1
<base::FileDescriptor
> > {
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
)) {}
64 DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle
);
67 # error "What platform?"
68 #endif // defined(OS_WIN)
70 // Message class to pass a response to the server.
71 class MsgClassResponse
72 : public IPC::MessageWithTuple
< Tuple1
<std::string
> > {
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
)) {}
80 DISALLOW_COPY_AND_ASSIGN(MsgClassResponse
);
83 // Message class to tell the server to shut down.
84 class MsgClassShutdown
85 : public IPC::MessageWithTuple
< Tuple0
> {
87 enum { ID
= SERVER_SECOND_IPC_TYPE
};
89 : IPC::MessageWithTuple
< Tuple0
>(
90 MSG_ROUTING_CONTROL
, ID
, MakeTuple()) {}
93 DISALLOW_COPY_AND_ASSIGN(MsgClassShutdown
);
96 // The SyncSocket server listener class processes two sorts of
97 // messages from the client.
98 class SyncSocketServerListener
: public IPC::Channel::Listener
{
100 SyncSocketServerListener() : chan_(NULL
) {
103 void Init(IPC::Channel
* chan
) {
107 virtual bool OnMessageReceived(const IPC::Message
& msg
) {
108 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()
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.
122 void OnMsgClassSetHandle(const base::SyncSocket::Handle handle
) {
125 #elif defined(OS_POSIX)
126 void OnMsgClassSetHandle(const base::FileDescriptor
& fd_struct
) {
127 SetHandle(fd_struct
.fd
);
130 # error "What platform?"
131 #endif // defined(OS_WIN)
133 void SetHandle(base::SyncSocket::Handle handle
) {
134 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
);
138 EXPECT_TRUE(chan_
->Send(msg
));
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();
149 DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener
);
152 // Runs the fuzzing server child mode. Returns when the preset number
153 // of messages have been received.
154 MULTIPROCESS_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();
164 // The SyncSocket client listener only processes one sort of message,
165 // a response from the server.
166 class SyncSocketClientListener
: public IPC::Channel::Listener
{
168 SyncSocketClientListener() {
171 void Init(base::SyncSocket
* socket
, IPC::Channel
* chan
) {
176 virtual bool OnMessageReceived(const IPC::Message
& msg
) {
177 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()
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
) {
190 // We rely on the order of sync_socket.Send() and chan_->Send() in
191 // the SyncSocketServerListener object.
192 EXPECT_EQ(kHelloStringLength
, socket_
->Peek());
193 char buf
[kHelloStringLength
];
194 socket_
->Receive(static_cast<void*>(buf
), kHelloStringLength
);
195 EXPECT_EQ(strcmp(str
.c_str(), buf
), 0);
196 // After receiving from the socket there should be no bytes left.
197 EXPECT_EQ(0U, socket_
->Peek());
198 IPC::Message
* msg
= new MsgClassShutdown();
199 EXPECT_TRUE(chan_
->Send(msg
));
200 MessageLoop::current()->Quit();
203 base::SyncSocket
* socket_
;
206 DISALLOW_COPY_AND_ASSIGN(SyncSocketClientListener
);
209 class SyncSocketTest
: public IPCChannelTest
{
212 TEST_F(SyncSocketTest
, SanityTest
) {
213 SyncSocketClientListener listener
;
214 IPC::Channel
chan(kSyncSocketChannel
, IPC::Channel::MODE_SERVER
,
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
);
221 // Immediately after creation there should be no pending bytes.
222 EXPECT_EQ(0U, pair
[0]->Peek());
223 EXPECT_EQ(0U, pair
[1]->Peek());
224 base::SyncSocket::Handle target_handle
;
225 // Connect the channel and listener.
226 ASSERT_TRUE(chan
.Connect());
227 listener
.Init(pair
[0], &chan
);
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
);
234 // Set up a message to pass the handle to the server.
235 IPC::Message
* msg
= new MsgClassSetHandle(target_handle
);
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)
242 EXPECT_TRUE(chan
.Send(msg
));
243 // Use the current thread as the I/O thread.
244 MessageLoop::current()->Run();
248 EXPECT_TRUE(base::WaitForSingleProcess(server_process
, 5000));
249 base::CloseProcessHandle(server_process
);