blob: f9db649a3a9a1b8b3a7135d9c7195b3dd761e47d [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
avi42ebda42015-12-22 11:39:04 +09007#include <stddef.h>
sehr@google.com4f325aa2009-11-25 01:14:53 +09008#include <stdio.h>
danakjc3fb6c52016-04-23 13:21:09 +09009#include <memory>
sehr@google.com4f325aa2009-11-25 01:14:53 +090010#include <sstream>
skyostile468e662015-05-12 20:29:21 +090011#include <string>
sehr@google.com4f325aa2009-11-25 01:14:53 +090012
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +090013#include "base/bind.h"
skyostile468e662015-05-12 20:29:21 +090014#include "base/location.h"
avi42ebda42015-12-22 11:39:04 +090015#include "base/macros.h"
fdoray284aae52016-06-23 04:56:16 +090016#include "base/run_loop.h"
skyostile468e662015-05-12 20:29:21 +090017#include "base/single_thread_task_runner.h"
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +090018#include "base/threading/thread.h"
avi42ebda42015-12-22 11:39:04 +090019#include "build/build_config.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090020#include "ipc/ipc_test_base.h"
sehr@google.com4f325aa2009-11-25 01:14:53 +090021#include "testing/gtest/include/gtest/gtest.h"
sehr@google.com4f325aa2009-11-25 01:14:53 +090022
tony@chromium.orgd4a01292011-06-03 03:37:51 +090023#if defined(OS_POSIX)
brettw@google.com7c5cc672011-01-01 11:17:08 +090024#include "base/file_descriptor_posix.h"
tony@chromium.orgd4a01292011-06-03 03:37:51 +090025#endif
sehr@google.com4f325aa2009-11-25 01:14:53 +090026
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090027// IPC messages for testing ----------------------------------------------------
darin@chromium.orgb4587d52011-08-27 06:27:30 +090028
29#define IPC_MESSAGE_IMPL
30#include "ipc/ipc_message_macros.h"
31
32#define IPC_MESSAGE_START TestMsgStart
33
34// Message class to pass a base::SyncSocket::Handle to another process. This
35// is not as easy as it sounds, because of the differences in transferring
36// Windows HANDLEs versus posix file descriptors.
37#if defined(OS_WIN)
38IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::SyncSocket::Handle)
39#elif defined(OS_POSIX)
40IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::FileDescriptor)
41#endif
42
43// Message class to pass a response to the server.
44IPC_MESSAGE_CONTROL1(MsgClassResponse, std::string)
45
46// Message class to tell the server to shut down.
47IPC_MESSAGE_CONTROL0(MsgClassShutdown)
48
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090049// -----------------------------------------------------------------------------
sehr@google.com4f325aa2009-11-25 01:14:53 +090050
51namespace {
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090052
sehr@google.com4f325aa2009-11-25 01:14:53 +090053const char kHelloString[] = "Hello, SyncSocket Client";
54const size_t kHelloStringLength = arraysize(kHelloString);
sehr@google.com4f325aa2009-11-25 01:14:53 +090055
sehr@google.com4f325aa2009-11-25 01:14:53 +090056// The SyncSocket server listener class processes two sorts of
57// messages from the client.
brettw@chromium.orgdb1259e2012-06-30 07:05:26 +090058class SyncSocketServerListener : public IPC::Listener {
sehr@google.com4f325aa2009-11-25 01:14:53 +090059 public:
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +090060 SyncSocketServerListener() : chan_(NULL) {
sehr@google.com4f325aa2009-11-25 01:14:53 +090061 }
62
63 void Init(IPC::Channel* chan) {
64 chan_ = chan;
65 }
66
dchengef7721a2014-10-22 11:29:52 +090067 bool OnMessageReceived(const IPC::Message& msg) override {
sehr@google.com4f325aa2009-11-25 01:14:53 +090068 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
69 IPC_BEGIN_MESSAGE_MAP(SyncSocketServerListener, msg)
70 IPC_MESSAGE_HANDLER(MsgClassSetHandle, OnMsgClassSetHandle)
71 IPC_MESSAGE_HANDLER(MsgClassShutdown, OnMsgClassShutdown)
72 IPC_END_MESSAGE_MAP()
73 }
jam@chromium.org8a2c7842010-12-24 15:19:28 +090074 return true;
sehr@google.com4f325aa2009-11-25 01:14:53 +090075 }
76
77 private:
78 // This sort of message is sent first, causing the transfer of
79 // the handle for the SyncSocket. This message sends a buffer
80 // on the SyncSocket and then sends a response to the client.
sehr@google.comfdc90062009-11-26 09:28:02 +090081#if defined(OS_WIN)
sehr@google.com4f325aa2009-11-25 01:14:53 +090082 void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) {
sehr@google.comfdc90062009-11-26 09:28:02 +090083 SetHandle(handle);
84 }
85#elif defined(OS_POSIX)
86 void OnMsgClassSetHandle(const base::FileDescriptor& fd_struct) {
87 SetHandle(fd_struct.fd);
88 }
89#else
90# error "What platform?"
91#endif // defined(OS_WIN)
92
93 void SetHandle(base::SyncSocket::Handle handle) {
sehr@google.com4f325aa2009-11-25 01:14:53 +090094 base::SyncSocket sync_socket(handle);
xians@chromium.orgf7d9af82012-04-19 19:23:03 +090095 EXPECT_EQ(sync_socket.Send(kHelloString, kHelloStringLength),
96 kHelloStringLength);
sehr@google.com4f325aa2009-11-25 01:14:53 +090097 IPC::Message* msg = new MsgClassResponse(kHelloString);
sehr@google.com4f325aa2009-11-25 01:14:53 +090098 EXPECT_TRUE(chan_->Send(msg));
99 }
100
101 // When the client responds, it sends back a shutdown message,
102 // which causes the message loop to exit.
Gabriel Charette274bec82017-07-26 21:36:23 +0900103 void OnMsgClassShutdown() { base::RunLoop::QuitCurrentWhenIdleDeprecated(); }
sehr@google.com4f325aa2009-11-25 01:14:53 +0900104
105 IPC::Channel* chan_;
106
107 DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener);
108};
109
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900110// Runs the fuzzing server child mode. Returns when the preset number of
111// messages have been received.
sammce3cae212016-10-27 19:13:59 +0900112DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(SyncSocketServerClient) {
sehr@google.com4f325aa2009-11-25 01:14:53 +0900113 SyncSocketServerListener listener;
sammce3cae212016-10-27 19:13:59 +0900114 Connect(&listener);
115 listener.Init(channel());
fdoray284aae52016-06-23 04:56:16 +0900116 base::RunLoop().Run();
sammce3cae212016-10-27 19:13:59 +0900117 Close();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900118}
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:
Chris Watkins31bfe1a2017-11-30 11:11:59 +0900124 SyncSocketClientListener() = default;
sehr@google.com4f325aa2009-11-25 01:14:53 +0900125
126 void Init(base::SyncSocket* socket, IPC::Channel* chan) {
127 socket_ = socket;
128 chan_ = chan;
129 }
130
dchengef7721a2014-10-22 11:29:52 +0900131 bool OnMessageReceived(const IPC::Message& msg) override {
sehr@google.com4f325aa2009-11-25 01:14:53 +0900132 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
133 IPC_BEGIN_MESSAGE_MAP(SyncSocketClientListener, msg)
134 IPC_MESSAGE_HANDLER(MsgClassResponse, OnMsgClassResponse)
135 IPC_END_MESSAGE_MAP()
136 }
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900137 return true;
sehr@google.com4f325aa2009-11-25 01:14:53 +0900138 }
139
140 private:
141 // When a response is received from the server, it sends the same
142 // string as was written on the SyncSocket. These are compared
143 // and a shutdown message is sent back to the server.
144 void OnMsgClassResponse(const std::string& str) {
cpu@chromium.org750392c2009-12-05 07:53:22 +0900145 // We rely on the order of sync_socket.Send() and chan_->Send() in
146 // the SyncSocketServerListener object.
147 EXPECT_EQ(kHelloStringLength, socket_->Peek());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900148 char buf[kHelloStringLength];
149 socket_->Receive(static_cast<void*>(buf), kHelloStringLength);
150 EXPECT_EQ(strcmp(str.c_str(), buf), 0);
sehr@google.comb72918f2009-12-07 04:45:08 +0900151 // After receiving from the socket there should be no bytes left.
thomasvl@google.com9a242072010-07-23 23:18:59 +0900152 EXPECT_EQ(0U, socket_->Peek());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900153 IPC::Message* msg = new MsgClassShutdown();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900154 EXPECT_TRUE(chan_->Send(msg));
Gabriel Charette274bec82017-07-26 21:36:23 +0900155 base::RunLoop::QuitCurrentWhenIdleDeprecated();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900156 }
157
158 base::SyncSocket* socket_;
159 IPC::Channel* chan_;
160
161 DISALLOW_COPY_AND_ASSIGN(SyncSocketClientListener);
162};
163
sammce3cae212016-10-27 19:13:59 +0900164using SyncSocketTest = IPCChannelMojoTestBase;
sehr@google.com4f325aa2009-11-25 01:14:53 +0900165
amistry87fc78f2016-05-05 14:12:09 +0900166TEST_F(SyncSocketTest, SanityTest) {
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900167 Init("SyncSocketServerClient");
168
sehr@google.com4f325aa2009-11-25 01:14:53 +0900169 SyncSocketClientListener listener;
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900170 CreateChannel(&listener);
sehr@google.com4f325aa2009-11-25 01:14:53 +0900171 // Create a pair of SyncSockets.
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900172 base::SyncSocket pair[2];
173 base::SyncSocket::CreatePair(&pair[0], &pair[1]);
sehr@google.comb72918f2009-12-07 04:45:08 +0900174 // Immediately after creation there should be no pending bytes.
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900175 EXPECT_EQ(0U, pair[0].Peek());
176 EXPECT_EQ(0U, pair[1].Peek());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900177 base::SyncSocket::Handle target_handle;
sehr@google.comfdc90062009-11-26 09:28:02 +0900178 // Connect the channel and listener.
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900179 ASSERT_TRUE(ConnectChannel());
180 listener.Init(&pair[0], channel());
sehr@google.com4f325aa2009-11-25 01:14:53 +0900181#if defined(OS_WIN)
182 // On windows we need to duplicate the handle into the server process.
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900183 BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1].handle(),
rvargasf355d882015-01-13 07:23:23 +0900184 client_process().Handle(), &target_handle,
sehr@google.com4f325aa2009-11-25 01:14:53 +0900185 0, FALSE, DUPLICATE_SAME_ACCESS);
186 EXPECT_TRUE(retval);
sehr@google.com4f325aa2009-11-25 01:14:53 +0900187 // Set up a message to pass the handle to the server.
188 IPC::Message* msg = new MsgClassSetHandle(target_handle);
sehr@google.comfdc90062009-11-26 09:28:02 +0900189#else
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900190 target_handle = pair[1].handle();
sehr@google.comfdc90062009-11-26 09:28:02 +0900191 // Set up a message to pass the handle to the server.
192 base::FileDescriptor filedesc(target_handle, false);
193 IPC::Message* msg = new MsgClassSetHandle(filedesc);
194#endif // defined(OS_WIN)
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900195 EXPECT_TRUE(sender()->Send(msg));
sehr@google.com4f325aa2009-11-25 01:14:53 +0900196 // Use the current thread as the I/O thread.
fdoray284aae52016-06-23 04:56:16 +0900197 base::RunLoop().Run();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900198 // Shut down.
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900199 pair[0].Close();
200 pair[1].Close();
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900201 EXPECT_TRUE(WaitForClientShutdown());
202 DestroyChannel();
sehr@google.com4f325aa2009-11-25 01:14:53 +0900203}
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900204
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900205// A blocking read operation that will block the thread until it receives
206// |length| bytes of packets or Shutdown() is called on another thread.
207static void BlockingRead(base::SyncSocket* socket, char* buf,
208 size_t length, size_t* received) {
209 DCHECK(buf != NULL);
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900210 // Notify the parent thread that we're up and running.
211 socket->Send(kHelloString, kHelloStringLength);
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900212 *received = socket->Receive(buf, length);
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900213}
214
215// Tests that we can safely end a blocking Receive operation on one thread
216// from another thread by disconnecting (but not closing) the socket.
217TEST_F(SyncSocketTest, DisconnectTest) {
218 base::CancelableSyncSocket pair[2];
219 ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
220
221 base::Thread worker("BlockingThread");
222 worker.Start();
223
224 // Try to do a blocking read from one of the sockets on the worker thread.
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900225 char buf[0xff];
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900226 size_t received = 1U; // Initialize to an unexpected value.
skyostile468e662015-05-12 20:29:21 +0900227 worker.task_runner()->PostTask(
228 FROM_HERE,
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900229 base::Bind(&BlockingRead, &pair[0], &buf[0], arraysize(buf), &received));
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900230
231 // Wait for the worker thread to say hello.
232 char hello[kHelloStringLength] = {0};
233 pair[1].Receive(&hello[0], sizeof(hello));
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900234 EXPECT_EQ(0, strcmp(hello, kHelloString));
tommi@chromium.orgd5f359a2012-01-25 21:04:17 +0900235 // Give the worker a chance to start Receive().
236 base::PlatformThread::YieldCurrentThread();
237
238 // Now shut down the socket that the thread is issuing a blocking read on
239 // which should cause Receive to return with an error.
240 pair[0].Shutdown();
241
242 worker.Stop();
243
244 EXPECT_EQ(0U, received);
245}
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900246
247// Tests that read is a blocking operation.
amistry87fc78f2016-05-05 14:12:09 +0900248TEST_F(SyncSocketTest, BlockingReceiveTest) {
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900249 base::CancelableSyncSocket pair[2];
250 ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
251
252 base::Thread worker("BlockingThread");
253 worker.Start();
254
255 // Try to do a blocking read from one of the sockets on the worker thread.
256 char buf[kHelloStringLength] = {0};
257 size_t received = 1U; // Initialize to an unexpected value.
skyostile468e662015-05-12 20:29:21 +0900258 worker.task_runner()->PostTask(FROM_HERE,
259 base::Bind(&BlockingRead, &pair[0], &buf[0],
260 kHelloStringLength, &received));
xians@chromium.orgf7d9af82012-04-19 19:23:03 +0900261
262 // Wait for the worker thread to say hello.
263 char hello[kHelloStringLength] = {0};
264 pair[1].Receive(&hello[0], sizeof(hello));
265 EXPECT_EQ(0, strcmp(hello, kHelloString));
266 // Give the worker a chance to start Receive().
267 base::PlatformThread::YieldCurrentThread();
268
269 // Send a message to the socket on the blocking thead, it should free the
270 // socket from Receive().
271 pair[1].Send(kHelloString, kHelloStringLength);
272 worker.Stop();
273
274 // Verify the socket has received the message.
275 EXPECT_TRUE(strcmp(buf, kHelloString) == 0);
276 EXPECT_EQ(kHelloStringLength, received);
277}
278
279// Tests that the write operation is non-blocking and returns immediately
280// when there is insufficient space in the socket's buffer.
281TEST_F(SyncSocketTest, NonBlockingWriteTest) {
282 base::CancelableSyncSocket pair[2];
283 ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
284
285 // Fill up the buffer for one of the socket, Send() should not block the
286 // thread even when the buffer is full.
287 while (pair[0].Send(kHelloString, kHelloStringLength) != 0) {}
288
289 // Data should be avialble on another socket.
290 size_t bytes_in_buffer = pair[1].Peek();
291 EXPECT_NE(bytes_in_buffer, 0U);
292
293 // No more data can be written to the buffer since socket has been full,
294 // verify that the amount of avialble data on another socket is unchanged.
295 EXPECT_EQ(0U, pair[0].Send(kHelloString, kHelloStringLength));
296 EXPECT_EQ(bytes_in_buffer, pair[1].Peek());
297
298 // Read from another socket to free some space for a new write.
299 char hello[kHelloStringLength] = {0};
300 pair[1].Receive(&hello[0], sizeof(hello));
301
302 // Should be able to write more data to the buffer now.
303 EXPECT_EQ(kHelloStringLength, pair[0].Send(kHelloString, kHelloStringLength));
304}
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +0900305
306} // namespace