blob: 5527abc4b538553dd6a70a29460e84aa28bd17d0 [file] [log] [blame]
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +09001// Copyright (c) 2012 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
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +090011#include "base/bind.h"
avi@chromium.orga29af562013-07-18 08:00:30 +090012#include "base/message_loop/message_loop.h"
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +090013#include "base/threading/thread.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090014#include "ipc/ipc_test_base.h"
sehr@google.com4f325aa2009-11-25 01:14:53 +090015#include "testing/gtest/include/gtest/gtest.h"
sehr@google.com4f325aa2009-11-25 01:14:53 +090016
tony@chromium.orgd4a01292011-06-03 03:37:51 +090017#if defined(OS_POSIX)
brettw@google.com7c5cc672011-01-01 11:17:08 +090018#include "base/file_descriptor_posix.h"
tony@chromium.orgd4a01292011-06-03 03:37:51 +090019#endif
sehr@google.com4f325aa2009-11-25 01:14:53 +090020
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090021// IPC messages for testing ----------------------------------------------------
darin@chromium.orgb4587d52011-08-27 06:27:30 +090022
23#define IPC_MESSAGE_IMPL
24#include "ipc/ipc_message_macros.h"
25
26#define IPC_MESSAGE_START TestMsgStart
27
28// Message class to pass a base::SyncSocket::Handle to another process. This
29// is not as easy as it sounds, because of the differences in transferring
30// Windows HANDLEs versus posix file descriptors.
31#if defined(OS_WIN)
32IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::SyncSocket::Handle)
33#elif defined(OS_POSIX)
34IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::FileDescriptor)
35#endif
36
37// Message class to pass a response to the server.
38IPC_MESSAGE_CONTROL1(MsgClassResponse, std::string)
39
40// Message class to tell the server to shut down.
41IPC_MESSAGE_CONTROL0(MsgClassShutdown)
42
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090043// -----------------------------------------------------------------------------
sehr@google.com4f325aa2009-11-25 01:14:53 +090044
45namespace {
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090046
sehr@google.com4f325aa2009-11-25 01:14:53 +090047const char kHelloString[] = "Hello, SyncSocket Client";
48const size_t kHelloStringLength = arraysize(kHelloString);
sehr@google.com4f325aa2009-11-25 01:14:53 +090049
sehr@google.com4f325aa2009-11-25 01:14:53 +090050// The SyncSocket server listener class processes two sorts of
51// messages from the client.
brettw@chromium.orgdb1259e2012-06-30 07:05:26 +090052class SyncSocketServerListener : public IPC::Listener {
sehr@google.com4f325aa2009-11-25 01:14:53 +090053 public:
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +090054 SyncSocketServerListener() : chan_(NULL) {
sehr@google.com4f325aa2009-11-25 01:14:53 +090055 }
56
57 void Init(IPC::Channel* chan) {
58 chan_ = chan;
59 }
60
rsleevi@chromium.org5a8d7ef2013-02-06 19:08:55 +090061 virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
sehr@google.com4f325aa2009-11-25 01:14:53 +090062 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
63 IPC_BEGIN_MESSAGE_MAP(SyncSocketServerListener, msg)
64 IPC_MESSAGE_HANDLER(MsgClassSetHandle, OnMsgClassSetHandle)
65 IPC_MESSAGE_HANDLER(MsgClassShutdown, OnMsgClassShutdown)
66 IPC_END_MESSAGE_MAP()
67 }
jam@chromium.org8a2c7842010-12-24 15:19:28 +090068 return true;
sehr@google.com4f325aa2009-11-25 01:14:53 +090069 }
70
71 private:
72 // This sort of message is sent first, causing the transfer of
73 // the handle for the SyncSocket. This message sends a buffer
74 // on the SyncSocket and then sends a response to the client.
sehr@google.comfdc90062009-11-26 09:28:02 +090075#if defined(OS_WIN)
sehr@google.com4f325aa2009-11-25 01:14:53 +090076 void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) {
sehr@google.comfdc90062009-11-26 09:28:02 +090077 SetHandle(handle);
78 }
79#elif defined(OS_POSIX)
80 void OnMsgClassSetHandle(const base::FileDescriptor& fd_struct) {
81 SetHandle(fd_struct.fd);
82 }
83#else
84# error "What platform?"
85#endif // defined(OS_WIN)
86
87 void SetHandle(base::SyncSocket::Handle handle) {
sehr@google.com4f325aa2009-11-25 01:14:53 +090088 base::SyncSocket sync_socket(handle);
xians@chromium.orgf7d9af82012-04-19 19:23:03 +090089 EXPECT_EQ(sync_socket.Send(kHelloString, kHelloStringLength),
90 kHelloStringLength);
sehr@google.com4f325aa2009-11-25 01:14:53 +090091 IPC::Message* msg = new MsgClassResponse(kHelloString);
sehr@google.com4f325aa2009-11-25 01:14:53 +090092 EXPECT_TRUE(chan_->Send(msg));
93 }
94
95 // When the client responds, it sends back a shutdown message,
96 // which causes the message loop to exit.
97 void OnMsgClassShutdown() {
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +090098 base::MessageLoop::current()->Quit();
sehr@google.com4f325aa2009-11-25 01:14:53 +090099 }
100
101 IPC::Channel* chan_;
102
103 DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener);
104};
105
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900106// Runs the fuzzing server child mode. Returns when the preset number of
107// messages have been received.
108MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SyncSocketServerClient) {
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900109 base::MessageLoopForIO main_message_loop;
sehr@google.com4f325aa2009-11-25 01:14:53 +0900110 SyncSocketServerListener listener;
morrita@chromium.org2ced0042014-05-30 12:58:59 +0900111 scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
112 IPCTestBase::GetChannelName("SyncSocketServerClient"),
113 &listener));
114 EXPECT_TRUE(channel->Connect());
115 listener.Init(channel.get());
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900116 base::MessageLoop::current()->Run();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900117 return 0;
118}
119
120// The SyncSocket client listener only processes one sort of message,
121// a response from the server.
brettw@chromium.orgdb1259e2012-06-30 07:05:26 +0900122class SyncSocketClientListener : public IPC::Listener {
sehr@google.com4f325aa2009-11-25 01:14:53 +0900123 public:
124 SyncSocketClientListener() {
125 }
126
127 void Init(base::SyncSocket* socket, IPC::Channel* chan) {
128 socket_ = socket;
129 chan_ = chan;
130 }
131
rsleevi@chromium.org5a8d7ef2013-02-06 19:08:55 +0900132 virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
sehr@google.com4f325aa2009-11-25 01:14:53 +0900133 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
134 IPC_BEGIN_MESSAGE_MAP(SyncSocketClientListener, msg)
135 IPC_MESSAGE_HANDLER(MsgClassResponse, OnMsgClassResponse)
136 IPC_END_MESSAGE_MAP()
137 }
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900138 return true;
sehr@google.com4f325aa2009-11-25 01:14:53 +0900139 }
140
141 private:
142 // When a response is received from the server, it sends the same
143 // string as was written on the SyncSocket. These are compared
144 // and a shutdown message is sent back to the server.
145 void OnMsgClassResponse(const std::string& str) {
cpu@chromium.org750392c2009-12-05 07:53:22 +0900146 // We rely on the order of sync_socket.Send() and chan_->Send() in
147 // the SyncSocketServerListener object.
148 EXPECT_EQ(kHelloStringLength, socket_->Peek());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900149 char buf[kHelloStringLength];
150 socket_->Receive(static_cast<void*>(buf), kHelloStringLength);
151 EXPECT_EQ(strcmp(str.c_str(), buf), 0);
sehr@google.comb72918f2009-12-07 04:45:08 +0900152 // After receiving from the socket there should be no bytes left.
thomasvl@google.com9a242072010-07-23 23:18:59 +0900153 EXPECT_EQ(0U, socket_->Peek());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900154 IPC::Message* msg = new MsgClassShutdown();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900155 EXPECT_TRUE(chan_->Send(msg));
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900156 base::MessageLoop::current()->Quit();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900157 }
158
159 base::SyncSocket* socket_;
160 IPC::Channel* chan_;
161
162 DISALLOW_COPY_AND_ASSIGN(SyncSocketClientListener);
163};
164
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900165class SyncSocketTest : public IPCTestBase {
sehr@google.com4f325aa2009-11-25 01:14:53 +0900166};
167
168TEST_F(SyncSocketTest, SanityTest) {
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900169 Init("SyncSocketServerClient");
170
sehr@google.com4f325aa2009-11-25 01:14:53 +0900171 SyncSocketClientListener listener;
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900172 CreateChannel(&listener);
173 ASSERT_TRUE(StartClient());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900174 // Create a pair of SyncSockets.
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900175 base::SyncSocket pair[2];
176 base::SyncSocket::CreatePair(&pair[0], &pair[1]);
sehr@google.comb72918f2009-12-07 04:45:08 +0900177 // Immediately after creation there should be no pending bytes.
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900178 EXPECT_EQ(0U, pair[0].Peek());
179 EXPECT_EQ(0U, pair[1].Peek());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900180 base::SyncSocket::Handle target_handle;
sehr@google.comfdc90062009-11-26 09:28:02 +0900181 // Connect the channel and listener.
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900182 ASSERT_TRUE(ConnectChannel());
183 listener.Init(&pair[0], channel());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900184#if defined(OS_WIN)
185 // On windows we need to duplicate the handle into the server process.
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900186 BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1].handle(),
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900187 client_process(), &target_handle,
sehr@google.com4f325aa2009-11-25 01:14:53 +0900188 0, FALSE, DUPLICATE_SAME_ACCESS);
189 EXPECT_TRUE(retval);
sehr@google.com4f325aa2009-11-25 01:14:53 +0900190 // Set up a message to pass the handle to the server.
191 IPC::Message* msg = new MsgClassSetHandle(target_handle);
sehr@google.comfdc90062009-11-26 09:28:02 +0900192#else
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900193 target_handle = pair[1].handle();
sehr@google.comfdc90062009-11-26 09:28:02 +0900194 // Set up a message to pass the handle to the server.
195 base::FileDescriptor filedesc(target_handle, false);
196 IPC::Message* msg = new MsgClassSetHandle(filedesc);
197#endif // defined(OS_WIN)
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900198 EXPECT_TRUE(sender()->Send(msg));
sehr@google.com4f325aa2009-11-25 01:14:53 +0900199 // Use the current thread as the I/O thread.
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900200 base::MessageLoop::current()->Run();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900201 // Shut down.
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900202 pair[0].Close();
203 pair[1].Close();
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900204 EXPECT_TRUE(WaitForClientShutdown());
205 DestroyChannel();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900206}
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900207
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900208// A blocking read operation that will block the thread until it receives
209// |length| bytes of packets or Shutdown() is called on another thread.
210static void BlockingRead(base::SyncSocket* socket, char* buf,
211 size_t length, size_t* received) {
212 DCHECK(buf != NULL);
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900213 // Notify the parent thread that we're up and running.
214 socket->Send(kHelloString, kHelloStringLength);
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900215 *received = socket->Receive(buf, length);
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900216}
217
218// Tests that we can safely end a blocking Receive operation on one thread
219// from another thread by disconnecting (but not closing) the socket.
220TEST_F(SyncSocketTest, DisconnectTest) {
221 base::CancelableSyncSocket pair[2];
222 ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
223
224 base::Thread worker("BlockingThread");
225 worker.Start();
226
227 // Try to do a blocking read from one of the sockets on the worker thread.
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900228 char buf[0xff];
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900229 size_t received = 1U; // Initialize to an unexpected value.
230 worker.message_loop()->PostTask(FROM_HERE,
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900231 base::Bind(&BlockingRead, &pair[0], &buf[0], arraysize(buf), &received));
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900232
233 // Wait for the worker thread to say hello.
234 char hello[kHelloStringLength] = {0};
235 pair[1].Receive(&hello[0], sizeof(hello));
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900236 EXPECT_EQ(0, strcmp(hello, kHelloString));
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900237 // Give the worker a chance to start Receive().
238 base::PlatformThread::YieldCurrentThread();
239
240 // Now shut down the socket that the thread is issuing a blocking read on
241 // which should cause Receive to return with an error.
242 pair[0].Shutdown();
243
244 worker.Stop();
245
246 EXPECT_EQ(0U, received);
247}
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900248
249// Tests that read is a blocking operation.
250TEST_F(SyncSocketTest, BlockingReceiveTest) {
251 base::CancelableSyncSocket pair[2];
252 ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
253
254 base::Thread worker("BlockingThread");
255 worker.Start();
256
257 // Try to do a blocking read from one of the sockets on the worker thread.
258 char buf[kHelloStringLength] = {0};
259 size_t received = 1U; // Initialize to an unexpected value.
260 worker.message_loop()->PostTask(FROM_HERE,
261 base::Bind(&BlockingRead, &pair[0], &buf[0],
262 kHelloStringLength, &received));
263
264 // Wait for the worker thread to say hello.
265 char hello[kHelloStringLength] = {0};
266 pair[1].Receive(&hello[0], sizeof(hello));
267 EXPECT_EQ(0, strcmp(hello, kHelloString));
268 // Give the worker a chance to start Receive().
269 base::PlatformThread::YieldCurrentThread();
270
271 // Send a message to the socket on the blocking thead, it should free the
272 // socket from Receive().
273 pair[1].Send(kHelloString, kHelloStringLength);
274 worker.Stop();
275
276 // Verify the socket has received the message.
277 EXPECT_TRUE(strcmp(buf, kHelloString) == 0);
278 EXPECT_EQ(kHelloStringLength, received);
279}
280
281// Tests that the write operation is non-blocking and returns immediately
282// when there is insufficient space in the socket's buffer.
283TEST_F(SyncSocketTest, NonBlockingWriteTest) {
284 base::CancelableSyncSocket pair[2];
285 ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
286
287 // Fill up the buffer for one of the socket, Send() should not block the
288 // thread even when the buffer is full.
289 while (pair[0].Send(kHelloString, kHelloStringLength) != 0) {}
290
291 // Data should be avialble on another socket.
292 size_t bytes_in_buffer = pair[1].Peek();
293 EXPECT_NE(bytes_in_buffer, 0U);
294
295 // No more data can be written to the buffer since socket has been full,
296 // verify that the amount of avialble data on another socket is unchanged.
297 EXPECT_EQ(0U, pair[0].Send(kHelloString, kHelloStringLength));
298 EXPECT_EQ(bytes_in_buffer, pair[1].Peek());
299
300 // Read from another socket to free some space for a new write.
301 char hello[kHelloStringLength] = {0};
302 pair[1].Receive(&hello[0], sizeof(hello));
303
304 // Should be able to write more data to the buffer now.
305 EXPECT_EQ(kHelloStringLength, pair[0].Send(kHelloString, kHelloStringLength));
306}
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +0900307
308} // namespace