• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "base/sync_socket.h"
6 
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <memory>
10 #include <sstream>
11 #include <string>
12 
13 #include "base/bind.h"
14 #include "base/location.h"
15 #include "base/macros.h"
16 #include "base/run_loop.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/threading/thread.h"
19 #include "build/build_config.h"
20 #include "ipc/ipc_test_base.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 #if defined(OS_POSIX)
24 #include "base/file_descriptor_posix.h"
25 #endif
26 
27 // IPC messages for testing ----------------------------------------------------
28 
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)
38 IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::SyncSocket::Handle)
39 #elif defined(OS_POSIX)
40 IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::FileDescriptor)
41 #endif
42 
43 // Message class to pass a response to the server.
44 IPC_MESSAGE_CONTROL1(MsgClassResponse, std::string)
45 
46 // Message class to tell the server to shut down.
47 IPC_MESSAGE_CONTROL0(MsgClassShutdown)
48 
49 // -----------------------------------------------------------------------------
50 
51 namespace {
52 
53 const char kHelloString[] = "Hello, SyncSocket Client";
54 const size_t kHelloStringLength = arraysize(kHelloString);
55 
56 // The SyncSocket server listener class processes two sorts of
57 // messages from the client.
58 class SyncSocketServerListener : public IPC::Listener {
59  public:
SyncSocketServerListener()60   SyncSocketServerListener() : chan_(NULL) {
61   }
62 
Init(IPC::Channel * chan)63   void Init(IPC::Channel* chan) {
64     chan_ = chan;
65   }
66 
OnMessageReceived(const IPC::Message & msg)67   bool OnMessageReceived(const IPC::Message& msg) override {
68     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     }
74     return true;
75   }
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.
81 #if defined(OS_WIN)
OnMsgClassSetHandle(const base::SyncSocket::Handle handle)82   void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) {
83     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 
SetHandle(base::SyncSocket::Handle handle)93   void SetHandle(base::SyncSocket::Handle handle) {
94     base::SyncSocket sync_socket(handle);
95     EXPECT_EQ(sync_socket.Send(kHelloString, kHelloStringLength),
96               kHelloStringLength);
97     IPC::Message* msg = new MsgClassResponse(kHelloString);
98     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.
OnMsgClassShutdown()103   void OnMsgClassShutdown() { base::RunLoop::QuitCurrentWhenIdleDeprecated(); }
104 
105   IPC::Channel* chan_;
106 
107   DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener);
108 };
109 
110 // Runs the fuzzing server child mode. Returns when the preset number of
111 // messages have been received.
DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(SyncSocketServerClient)112 DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(SyncSocketServerClient) {
113   SyncSocketServerListener listener;
114   Connect(&listener);
115   listener.Init(channel());
116   base::RunLoop().Run();
117   Close();
118 }
119 
120 // The SyncSocket client listener only processes one sort of message,
121 // a response from the server.
122 class SyncSocketClientListener : public IPC::Listener {
123  public:
124   SyncSocketClientListener() = default;
125 
Init(base::SyncSocket * socket,IPC::Channel * chan)126   void Init(base::SyncSocket* socket, IPC::Channel* chan) {
127     socket_ = socket;
128     chan_ = chan;
129   }
130 
OnMessageReceived(const IPC::Message & msg)131   bool OnMessageReceived(const IPC::Message& msg) override {
132     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     }
137     return true;
138   }
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.
OnMsgClassResponse(const std::string & str)144   void OnMsgClassResponse(const std::string& str) {
145     // We rely on the order of sync_socket.Send() and chan_->Send() in
146     // the SyncSocketServerListener object.
147     EXPECT_EQ(kHelloStringLength, socket_->Peek());
148     char buf[kHelloStringLength];
149     socket_->Receive(static_cast<void*>(buf), kHelloStringLength);
150     EXPECT_EQ(strcmp(str.c_str(), buf), 0);
151     // After receiving from the socket there should be no bytes left.
152     EXPECT_EQ(0U, socket_->Peek());
153     IPC::Message* msg = new MsgClassShutdown();
154     EXPECT_TRUE(chan_->Send(msg));
155     base::RunLoop::QuitCurrentWhenIdleDeprecated();
156   }
157 
158   base::SyncSocket* socket_;
159   IPC::Channel* chan_;
160 
161   DISALLOW_COPY_AND_ASSIGN(SyncSocketClientListener);
162 };
163 
164 using SyncSocketTest = IPCChannelMojoTestBase;
165 
TEST_F(SyncSocketTest,SanityTest)166 TEST_F(SyncSocketTest, SanityTest) {
167   Init("SyncSocketServerClient");
168 
169   SyncSocketClientListener listener;
170   CreateChannel(&listener);
171   // Create a pair of SyncSockets.
172   base::SyncSocket pair[2];
173   base::SyncSocket::CreatePair(&pair[0], &pair[1]);
174   // Immediately after creation there should be no pending bytes.
175   EXPECT_EQ(0U, pair[0].Peek());
176   EXPECT_EQ(0U, pair[1].Peek());
177   base::SyncSocket::Handle target_handle;
178   // Connect the channel and listener.
179   ASSERT_TRUE(ConnectChannel());
180   listener.Init(&pair[0], channel());
181 #if defined(OS_WIN)
182   // On windows we need to duplicate the handle into the server process.
183   BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1].handle(),
184                                 client_process().Handle(), &target_handle,
185                                 0, FALSE, DUPLICATE_SAME_ACCESS);
186   EXPECT_TRUE(retval);
187   // Set up a message to pass the handle to the server.
188   IPC::Message* msg = new MsgClassSetHandle(target_handle);
189 #else
190   target_handle = pair[1].handle();
191   // 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)
195   EXPECT_TRUE(sender()->Send(msg));
196   // Use the current thread as the I/O thread.
197   base::RunLoop().Run();
198   // Shut down.
199   pair[0].Close();
200   pair[1].Close();
201   EXPECT_TRUE(WaitForClientShutdown());
202   DestroyChannel();
203 }
204 
205 // A blocking read operation that will block the thread until it receives
206 // |length| bytes of packets or Shutdown() is called on another thread.
BlockingRead(base::SyncSocket * socket,char * buf,size_t length,size_t * received)207 static void BlockingRead(base::SyncSocket* socket, char* buf,
208                          size_t length, size_t* received) {
209   DCHECK(buf != NULL);
210   // Notify the parent thread that we're up and running.
211   socket->Send(kHelloString, kHelloStringLength);
212   *received = socket->Receive(buf, length);
213 }
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.
TEST_F(SyncSocketTest,DisconnectTest)217 TEST_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.
225   char buf[0xff];
226   size_t received = 1U;  // Initialize to an unexpected value.
227   worker.task_runner()->PostTask(
228       FROM_HERE,
229       base::Bind(&BlockingRead, &pair[0], &buf[0], arraysize(buf), &received));
230 
231   // Wait for the worker thread to say hello.
232   char hello[kHelloStringLength] = {0};
233   pair[1].Receive(&hello[0], sizeof(hello));
234   EXPECT_EQ(0, strcmp(hello, kHelloString));
235   // 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 }
246 
247 // Tests that read is a blocking operation.
TEST_F(SyncSocketTest,BlockingReceiveTest)248 TEST_F(SyncSocketTest, BlockingReceiveTest) {
249   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.
258   worker.task_runner()->PostTask(FROM_HERE,
259                                  base::Bind(&BlockingRead, &pair[0], &buf[0],
260                                             kHelloStringLength, &received));
261 
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.
TEST_F(SyncSocketTest,NonBlockingWriteTest)281 TEST_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 }
305 
306 }  // namespace
307