Home | History | Annotate | Download | only in ipc
      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:
     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.
    108 MULTIPROCESS_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.
    122 class 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 
    165 class SyncSocketTest : public IPCTestBase {
    166 };
    167 
    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.
    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.
    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.
    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.
    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