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 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: 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