• 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 <stdio.h>
8 #include <string>
9 #include <sstream>
10 
11 #include "base/bind.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/threading/thread.h"
14 #include "ipc/ipc_test_base.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 #if defined(OS_POSIX)
18 #include "base/file_descriptor_posix.h"
19 #endif
20 
21 // IPC messages for testing ----------------------------------------------------
22 
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)
32 IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::SyncSocket::Handle)
33 #elif defined(OS_POSIX)
34 IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::FileDescriptor)
35 #endif
36 
37 // Message class to pass a response to the server.
38 IPC_MESSAGE_CONTROL1(MsgClassResponse, std::string)
39 
40 // Message class to tell the server to shut down.
41 IPC_MESSAGE_CONTROL0(MsgClassShutdown)
42 
43 // -----------------------------------------------------------------------------
44 
45 namespace {
46 
47 const char kHelloString[] = "Hello, SyncSocket Client";
48 const size_t kHelloStringLength = arraysize(kHelloString);
49 
50 // The SyncSocket server listener class processes two sorts of
51 // messages from the client.
52 class SyncSocketServerListener : public IPC::Listener {
53  public:
SyncSocketServerListener()54   SyncSocketServerListener() : chan_(NULL) {
55   }
56 
Init(IPC::Channel * chan)57   void Init(IPC::Channel* chan) {
58     chan_ = chan;
59   }
60 
OnMessageReceived(const IPC::Message & msg)61   virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
62     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     }
68     return true;
69   }
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.
75 #if defined(OS_WIN)
OnMsgClassSetHandle(const base::SyncSocket::Handle handle)76   void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) {
77     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 
SetHandle(base::SyncSocket::Handle handle)87   void SetHandle(base::SyncSocket::Handle handle) {
88     base::SyncSocket sync_socket(handle);
89     EXPECT_EQ(sync_socket.Send(kHelloString, kHelloStringLength),
90               kHelloStringLength);
91     IPC::Message* msg = new MsgClassResponse(kHelloString);
92     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.
OnMsgClassShutdown()97   void OnMsgClassShutdown() {
98     base::MessageLoop::current()->Quit();
99   }
100 
101   IPC::Channel* chan_;
102 
103   DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener);
104 };
105 
106 // Runs the fuzzing server child mode. Returns when the preset number of
107 // messages have been received.
MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SyncSocketServerClient)108 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SyncSocketServerClient) {
109   base::MessageLoopForIO main_message_loop;
110   SyncSocketServerListener listener;
111   IPC::Channel channel(IPCTestBase::GetChannelName("SyncSocketServerClient"),
112                        IPC::Channel::MODE_CLIENT,
113                        &listener);
114   EXPECT_TRUE(channel.Connect());
115   listener.Init(&channel);
116   base::MessageLoop::current()->Run();
117   return 0;
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:
SyncSocketClientListener()124   SyncSocketClientListener() {
125   }
126 
Init(base::SyncSocket * socket,IPC::Channel * chan)127   void Init(base::SyncSocket* socket, IPC::Channel* chan) {
128     socket_ = socket;
129     chan_ = chan;
130   }
131 
OnMessageReceived(const IPC::Message & msg)132   virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
133     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     }
138     return true;
139   }
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.
OnMsgClassResponse(const std::string & str)145   void OnMsgClassResponse(const std::string& str) {
146     // We rely on the order of sync_socket.Send() and chan_->Send() in
147     // the SyncSocketServerListener object.
148     EXPECT_EQ(kHelloStringLength, socket_->Peek());
149     char buf[kHelloStringLength];
150     socket_->Receive(static_cast<void*>(buf), kHelloStringLength);
151     EXPECT_EQ(strcmp(str.c_str(), buf), 0);
152     // After receiving from the socket there should be no bytes left.
153     EXPECT_EQ(0U, socket_->Peek());
154     IPC::Message* msg = new MsgClassShutdown();
155     EXPECT_TRUE(chan_->Send(msg));
156     base::MessageLoop::current()->Quit();
157   }
158 
159   base::SyncSocket* socket_;
160   IPC::Channel* chan_;
161 
162   DISALLOW_COPY_AND_ASSIGN(SyncSocketClientListener);
163 };
164 
165 class SyncSocketTest : public IPCTestBase {
166 };
167 
TEST_F(SyncSocketTest,SanityTest)168 TEST_F(SyncSocketTest, SanityTest) {
169   Init("SyncSocketServerClient");
170 
171   SyncSocketClientListener listener;
172   CreateChannel(&listener);
173   ASSERT_TRUE(StartClient());
174   // Create a pair of SyncSockets.
175   base::SyncSocket pair[2];
176   base::SyncSocket::CreatePair(&pair[0], &pair[1]);
177   // Immediately after creation there should be no pending bytes.
178   EXPECT_EQ(0U, pair[0].Peek());
179   EXPECT_EQ(0U, pair[1].Peek());
180   base::SyncSocket::Handle target_handle;
181   // Connect the channel and listener.
182   ASSERT_TRUE(ConnectChannel());
183   listener.Init(&pair[0], channel());
184 #if defined(OS_WIN)
185   // On windows we need to duplicate the handle into the server process.
186   BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1].handle(),
187                                 client_process(), &target_handle,
188                                 0, FALSE, DUPLICATE_SAME_ACCESS);
189   EXPECT_TRUE(retval);
190   // Set up a message to pass the handle to the server.
191   IPC::Message* msg = new MsgClassSetHandle(target_handle);
192 #else
193   target_handle = pair[1].handle();
194   // 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)
198   EXPECT_TRUE(sender()->Send(msg));
199   // Use the current thread as the I/O thread.
200   base::MessageLoop::current()->Run();
201   // Shut down.
202   pair[0].Close();
203   pair[1].Close();
204   EXPECT_TRUE(WaitForClientShutdown());
205   DestroyChannel();
206 }
207 
208 // A blocking read operation that will block the thread until it receives
209 // |length| bytes of packets or Shutdown() is called on another thread.
BlockingRead(base::SyncSocket * socket,char * buf,size_t length,size_t * received)210 static void BlockingRead(base::SyncSocket* socket, char* buf,
211                          size_t length, size_t* received) {
212   DCHECK(buf != NULL);
213   // Notify the parent thread that we're up and running.
214   socket->Send(kHelloString, kHelloStringLength);
215   *received = socket->Receive(buf, length);
216 }
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.
TEST_F(SyncSocketTest,DisconnectTest)220 TEST_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.
228   char buf[0xff];
229   size_t received = 1U;  // Initialize to an unexpected value.
230   worker.message_loop()->PostTask(FROM_HERE,
231       base::Bind(&BlockingRead, &pair[0], &buf[0], arraysize(buf), &received));
232 
233   // Wait for the worker thread to say hello.
234   char hello[kHelloStringLength] = {0};
235   pair[1].Receive(&hello[0], sizeof(hello));
236   EXPECT_EQ(0, strcmp(hello, kHelloString));
237   // 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 }
248 
249 // Tests that read is a blocking operation.
TEST_F(SyncSocketTest,BlockingReceiveTest)250 TEST_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.
TEST_F(SyncSocketTest,NonBlockingWriteTest)283 TEST_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 }
307 
308 }  // namespace
309