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.
5 #include "base/sync_socket.h"
11 #include "base/bind.h"
12 #include "base/message_loop.h"
13 #include "base/process_util.h"
14 #include "base/threading/thread.h"
15 #include "ipc/ipc_channel_proxy.h"
16 #include "ipc/ipc_multiprocess_test.h"
17 #include "ipc/ipc_tests.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/multiprocess_func_list.h"
22 #include "base/file_descriptor_posix.h"
25 // IPC messages for testing ---------------------------------------------------
27 #define IPC_MESSAGE_IMPL
28 #include "ipc/ipc_message_macros.h"
30 #define IPC_MESSAGE_START TestMsgStart
32 // Message class to pass a base::SyncSocket::Handle to another process. This
33 // is not as easy as it sounds, because of the differences in transferring
34 // Windows HANDLEs versus posix file descriptors.
36 IPC_MESSAGE_CONTROL1(MsgClassSetHandle
, base::SyncSocket::Handle
)
37 #elif defined(OS_POSIX)
38 IPC_MESSAGE_CONTROL1(MsgClassSetHandle
, base::FileDescriptor
)
41 // Message class to pass a response to the server.
42 IPC_MESSAGE_CONTROL1(MsgClassResponse
, std::string
)
44 // Message class to tell the server to shut down.
45 IPC_MESSAGE_CONTROL0(MsgClassShutdown
)
47 // ----------------------------------------------------------------------------
50 const char kHelloString
[] = "Hello, SyncSocket Client";
51 const size_t kHelloStringLength
= arraysize(kHelloString
);
54 // The SyncSocket server listener class processes two sorts of
55 // messages from the client.
56 class SyncSocketServerListener
: public IPC::Listener
{
58 SyncSocketServerListener() : chan_(NULL
) {
61 void Init(IPC::Channel
* chan
) {
65 virtual bool OnMessageReceived(const IPC::Message
& msg
) {
66 if (msg
.routing_id() == MSG_ROUTING_CONTROL
) {
67 IPC_BEGIN_MESSAGE_MAP(SyncSocketServerListener
, msg
)
68 IPC_MESSAGE_HANDLER(MsgClassSetHandle
, OnMsgClassSetHandle
)
69 IPC_MESSAGE_HANDLER(MsgClassShutdown
, OnMsgClassShutdown
)
76 // This sort of message is sent first, causing the transfer of
77 // the handle for the SyncSocket. This message sends a buffer
78 // on the SyncSocket and then sends a response to the client.
80 void OnMsgClassSetHandle(const base::SyncSocket::Handle handle
) {
83 #elif defined(OS_POSIX)
84 void OnMsgClassSetHandle(const base::FileDescriptor
& fd_struct
) {
85 SetHandle(fd_struct
.fd
);
88 # error "What platform?"
89 #endif // defined(OS_WIN)
91 void SetHandle(base::SyncSocket::Handle handle
) {
92 base::SyncSocket
sync_socket(handle
);
93 EXPECT_EQ(sync_socket
.Send(kHelloString
, kHelloStringLength
),
95 IPC::Message
* msg
= new MsgClassResponse(kHelloString
);
96 EXPECT_TRUE(chan_
->Send(msg
));
99 // When the client responds, it sends back a shutdown message,
100 // which causes the message loop to exit.
101 void OnMsgClassShutdown() {
102 MessageLoop::current()->Quit();
107 DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener
);
110 // Runs the fuzzing server child mode. Returns when the preset number
111 // of messages have been received.
112 MULTIPROCESS_IPC_TEST_MAIN(RunSyncSocketServer
) {
113 MessageLoopForIO main_message_loop
;
114 SyncSocketServerListener listener
;
115 IPC::Channel
chan(kSyncSocketChannel
, IPC::Channel::MODE_CLIENT
, &listener
);
116 EXPECT_TRUE(chan
.Connect());
117 listener
.Init(&chan
);
118 MessageLoop::current()->Run();
122 // The SyncSocket client listener only processes one sort of message,
123 // a response from the server.
124 class SyncSocketClientListener
: public IPC::Listener
{
126 SyncSocketClientListener() {
129 void Init(base::SyncSocket
* socket
, IPC::Channel
* chan
) {
134 virtual bool OnMessageReceived(const IPC::Message
& msg
) {
135 if (msg
.routing_id() == MSG_ROUTING_CONTROL
) {
136 IPC_BEGIN_MESSAGE_MAP(SyncSocketClientListener
, msg
)
137 IPC_MESSAGE_HANDLER(MsgClassResponse
, OnMsgClassResponse
)
138 IPC_END_MESSAGE_MAP()
144 // When a response is received from the server, it sends the same
145 // string as was written on the SyncSocket. These are compared
146 // and a shutdown message is sent back to the server.
147 void OnMsgClassResponse(const std::string
& str
) {
148 // We rely on the order of sync_socket.Send() and chan_->Send() in
149 // the SyncSocketServerListener object.
150 EXPECT_EQ(kHelloStringLength
, socket_
->Peek());
151 char buf
[kHelloStringLength
];
152 socket_
->Receive(static_cast<void*>(buf
), kHelloStringLength
);
153 EXPECT_EQ(strcmp(str
.c_str(), buf
), 0);
154 // After receiving from the socket there should be no bytes left.
155 EXPECT_EQ(0U, socket_
->Peek());
156 IPC::Message
* msg
= new MsgClassShutdown();
157 EXPECT_TRUE(chan_
->Send(msg
));
158 MessageLoop::current()->Quit();
161 base::SyncSocket
* socket_
;
164 DISALLOW_COPY_AND_ASSIGN(SyncSocketClientListener
);
167 class SyncSocketTest
: public IPCChannelTest
{
170 TEST_F(SyncSocketTest
, SanityTest
) {
171 SyncSocketClientListener listener
;
172 IPC::Channel
chan(kSyncSocketChannel
, IPC::Channel::MODE_SERVER
,
174 base::ProcessHandle server_process
= SpawnChild(SYNC_SOCKET_SERVER
, &chan
);
175 ASSERT_TRUE(server_process
);
176 // Create a pair of SyncSockets.
177 base::SyncSocket pair
[2];
178 base::SyncSocket::CreatePair(&pair
[0], &pair
[1]);
179 // Immediately after creation there should be no pending bytes.
180 EXPECT_EQ(0U, pair
[0].Peek());
181 EXPECT_EQ(0U, pair
[1].Peek());
182 base::SyncSocket::Handle target_handle
;
183 // Connect the channel and listener.
184 ASSERT_TRUE(chan
.Connect());
185 listener
.Init(&pair
[0], &chan
);
187 // On windows we need to duplicate the handle into the server process.
188 BOOL retval
= DuplicateHandle(GetCurrentProcess(), pair
[1].handle(),
189 server_process
, &target_handle
,
190 0, FALSE
, DUPLICATE_SAME_ACCESS
);
192 // Set up a message to pass the handle to the server.
193 IPC::Message
* msg
= new MsgClassSetHandle(target_handle
);
195 target_handle
= pair
[1].handle();
196 // Set up a message to pass the handle to the server.
197 base::FileDescriptor
filedesc(target_handle
, false);
198 IPC::Message
* msg
= new MsgClassSetHandle(filedesc
);
199 #endif // defined(OS_WIN)
200 EXPECT_TRUE(chan
.Send(msg
));
201 // Use the current thread as the I/O thread.
202 MessageLoop::current()->Run();
206 EXPECT_TRUE(base::WaitForSingleProcess(
207 server_process
, base::TimeDelta::FromSeconds(5)));
208 base::CloseProcessHandle(server_process
);
212 // A blocking read operation that will block the thread until it receives
213 // |length| bytes of packets or Shutdown() is called on another thread.
214 static void BlockingRead(base::SyncSocket
* socket
, char* buf
,
215 size_t length
, size_t* received
) {
217 // Notify the parent thread that we're up and running.
218 socket
->Send(kHelloString
, kHelloStringLength
);
219 *received
= socket
->Receive(buf
, length
);
222 // Tests that we can safely end a blocking Receive operation on one thread
223 // from another thread by disconnecting (but not closing) the socket.
224 TEST_F(SyncSocketTest
, DisconnectTest
) {
225 base::CancelableSyncSocket pair
[2];
226 ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair
[0], &pair
[1]));
228 base::Thread
worker("BlockingThread");
231 // Try to do a blocking read from one of the sockets on the worker thread.
233 size_t received
= 1U; // Initialize to an unexpected value.
234 worker
.message_loop()->PostTask(FROM_HERE
,
235 base::Bind(&BlockingRead
, &pair
[0], &buf
[0], arraysize(buf
), &received
));
237 // Wait for the worker thread to say hello.
238 char hello
[kHelloStringLength
] = {0};
239 pair
[1].Receive(&hello
[0], sizeof(hello
));
240 EXPECT_EQ(0, strcmp(hello
, kHelloString
));
241 // Give the worker a chance to start Receive().
242 base::PlatformThread::YieldCurrentThread();
244 // Now shut down the socket that the thread is issuing a blocking read on
245 // which should cause Receive to return with an error.
250 EXPECT_EQ(0U, received
);
253 // Tests that read is a blocking operation.
254 TEST_F(SyncSocketTest
, BlockingReceiveTest
) {
255 base::CancelableSyncSocket pair
[2];
256 ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair
[0], &pair
[1]));
258 base::Thread
worker("BlockingThread");
261 // Try to do a blocking read from one of the sockets on the worker thread.
262 char buf
[kHelloStringLength
] = {0};
263 size_t received
= 1U; // Initialize to an unexpected value.
264 worker
.message_loop()->PostTask(FROM_HERE
,
265 base::Bind(&BlockingRead
, &pair
[0], &buf
[0],
266 kHelloStringLength
, &received
));
268 // Wait for the worker thread to say hello.
269 char hello
[kHelloStringLength
] = {0};
270 pair
[1].Receive(&hello
[0], sizeof(hello
));
271 EXPECT_EQ(0, strcmp(hello
, kHelloString
));
272 // Give the worker a chance to start Receive().
273 base::PlatformThread::YieldCurrentThread();
275 // Send a message to the socket on the blocking thead, it should free the
276 // socket from Receive().
277 pair
[1].Send(kHelloString
, kHelloStringLength
);
280 // Verify the socket has received the message.
281 EXPECT_TRUE(strcmp(buf
, kHelloString
) == 0);
282 EXPECT_EQ(kHelloStringLength
, received
);
285 // Tests that the write operation is non-blocking and returns immediately
286 // when there is insufficient space in the socket's buffer.
287 TEST_F(SyncSocketTest
, NonBlockingWriteTest
) {
288 base::CancelableSyncSocket pair
[2];
289 ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair
[0], &pair
[1]));
291 // Fill up the buffer for one of the socket, Send() should not block the
292 // thread even when the buffer is full.
293 while (pair
[0].Send(kHelloString
, kHelloStringLength
) != 0) {}
295 // Data should be avialble on another socket.
296 size_t bytes_in_buffer
= pair
[1].Peek();
297 EXPECT_NE(bytes_in_buffer
, 0U);
299 // No more data can be written to the buffer since socket has been full,
300 // verify that the amount of avialble data on another socket is unchanged.
301 EXPECT_EQ(0U, pair
[0].Send(kHelloString
, kHelloStringLength
));
302 EXPECT_EQ(bytes_in_buffer
, pair
[1].Peek());
304 // Read from another socket to free some space for a new write.
305 char hello
[kHelloStringLength
] = {0};
306 pair
[1].Receive(&hello
[0], sizeof(hello
));
308 // Should be able to write more data to the buffer now.
309 EXPECT_EQ(kHelloStringLength
, pair
[0].Send(kHelloString
, kHelloStringLength
));