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)
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
43// -----------------------------------------------------------------------------
44
45namespace {
46
47const char kHelloString[] = "Hello, SyncSocket Client";
48const size_t kHelloStringLength = arraysize(kHelloString);
49
50// The SyncSocket server listener class processes two sorts of
51// messages from the client.
52class SyncSocketServerListener : public IPC::Listener {
53 public:
54  SyncSocketServerListener() : chan_(NULL) {
55  }
56
57  void Init(IPC::Channel* chan) {
58    chan_ = chan;
59  }
60
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)
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
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.
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.
108MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SyncSocketServerClient) {
109  base::MessageLoopForIO main_message_loop;
110  SyncSocketServerListener listener;
111  scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
112      IPCTestBase::GetChannelName("SyncSocketServerClient"),
113      &listener));
114  EXPECT_TRUE(channel->Connect());
115  listener.Init(channel.get());
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.
122class SyncSocketClientListener : public IPC::Listener {
123 public:
124  SyncSocketClientListener() {
125  }
126
127  void Init(base::SyncSocket* socket, IPC::Channel* chan) {
128    socket_ = socket;
129    chan_ = chan;
130  }
131
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.
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
165class SyncSocketTest : public IPCTestBase {
166};
167
168TEST_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.
210static 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.
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.
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.
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}
307
308}  // namespace
309