sync_socket_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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. #include <stddef.h>
  5. #include <stdio.h>
  6. #include <memory>
  7. #include <sstream>
  8. #include <string>
  9. #include "base/bind.h"
  10. #include "base/location.h"
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/run_loop.h"
  13. #include "base/sync_socket.h"
  14. #include "base/task/single_thread_task_runner.h"
  15. #include "base/threading/thread.h"
  16. #include "build/build_config.h"
  17. #include "ipc/ipc_test_base.h"
  18. #include "testing/gtest/include/gtest/gtest.h"
  19. #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
  20. #include "base/file_descriptor_posix.h"
  21. #endif
  22. // IPC messages for testing ----------------------------------------------------
  23. #define IPC_MESSAGE_IMPL
  24. #include "ipc/ipc_message_macros.h"
  25. #include "ipc/ipc_message_start.h"
  26. #define IPC_MESSAGE_START TestMsgStart
  27. // Message class to pass a base::SyncSocket::Handle to another process. This
  28. // is not as easy as it sounds, because of the differences in transferring
  29. // Windows HANDLEs versus posix file descriptors.
  30. #if BUILDFLAG(IS_WIN)
  31. IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::SyncSocket::Handle)
  32. #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
  33. IPC_MESSAGE_CONTROL1(MsgClassSetHandle, base::FileDescriptor)
  34. #endif
  35. // Message class to pass a response to the server.
  36. IPC_MESSAGE_CONTROL1(MsgClassResponse, std::string)
  37. // Message class to tell the server to shut down.
  38. IPC_MESSAGE_CONTROL0(MsgClassShutdown)
  39. // -----------------------------------------------------------------------------
  40. namespace {
  41. const char kHelloString[] = "Hello, SyncSocket Client";
  42. const size_t kHelloStringLength = std::size(kHelloString);
  43. // The SyncSocket server listener class processes two sorts of
  44. // messages from the client.
  45. class SyncSocketServerListener : public IPC::Listener {
  46. public:
  47. SyncSocketServerListener() : chan_(nullptr) {}
  48. SyncSocketServerListener(const SyncSocketServerListener&) = delete;
  49. SyncSocketServerListener& operator=(const SyncSocketServerListener&) = delete;
  50. void Init(IPC::Channel* chan) {
  51. chan_ = chan;
  52. }
  53. bool OnMessageReceived(const IPC::Message& msg) override {
  54. if (msg.routing_id() == MSG_ROUTING_CONTROL) {
  55. IPC_BEGIN_MESSAGE_MAP(SyncSocketServerListener, msg)
  56. IPC_MESSAGE_HANDLER(MsgClassSetHandle, OnMsgClassSetHandle)
  57. IPC_MESSAGE_HANDLER(MsgClassShutdown, OnMsgClassShutdown)
  58. IPC_END_MESSAGE_MAP()
  59. }
  60. return true;
  61. }
  62. private:
  63. // This sort of message is sent first, causing the transfer of
  64. // the handle for the SyncSocket. This message sends a buffer
  65. // on the SyncSocket and then sends a response to the client.
  66. #if BUILDFLAG(IS_WIN)
  67. void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) {
  68. SetHandle(handle);
  69. }
  70. #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
  71. void OnMsgClassSetHandle(const base::FileDescriptor& fd_struct) {
  72. SetHandle(fd_struct.fd);
  73. }
  74. #else
  75. # error "What platform?"
  76. #endif // BUILDFLAG(IS_WIN)
  77. void SetHandle(base::SyncSocket::Handle handle) {
  78. base::SyncSocket sync_socket(handle);
  79. EXPECT_EQ(sync_socket.Send(kHelloString, kHelloStringLength),
  80. kHelloStringLength);
  81. IPC::Message* msg = new MsgClassResponse(kHelloString);
  82. EXPECT_TRUE(chan_->Send(msg));
  83. }
  84. // When the client responds, it sends back a shutdown message,
  85. // which causes the message loop to exit.
  86. void OnMsgClassShutdown() { base::RunLoop::QuitCurrentWhenIdleDeprecated(); }
  87. raw_ptr<IPC::Channel> chan_;
  88. };
  89. // Runs the fuzzing server child mode. Returns when the preset number of
  90. // messages have been received.
  91. DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(SyncSocketServerClient) {
  92. SyncSocketServerListener listener;
  93. Connect(&listener);
  94. listener.Init(channel());
  95. base::RunLoop().Run();
  96. Close();
  97. }
  98. // The SyncSocket client listener only processes one sort of message,
  99. // a response from the server.
  100. class SyncSocketClientListener : public IPC::Listener {
  101. public:
  102. SyncSocketClientListener() = default;
  103. SyncSocketClientListener(const SyncSocketClientListener&) = delete;
  104. SyncSocketClientListener& operator=(const SyncSocketClientListener&) = delete;
  105. void Init(base::SyncSocket* socket, IPC::Channel* chan) {
  106. socket_ = socket;
  107. chan_ = chan;
  108. }
  109. bool OnMessageReceived(const IPC::Message& msg) override {
  110. if (msg.routing_id() == MSG_ROUTING_CONTROL) {
  111. IPC_BEGIN_MESSAGE_MAP(SyncSocketClientListener, msg)
  112. IPC_MESSAGE_HANDLER(MsgClassResponse, OnMsgClassResponse)
  113. IPC_END_MESSAGE_MAP()
  114. }
  115. return true;
  116. }
  117. private:
  118. // When a response is received from the server, it sends the same
  119. // string as was written on the SyncSocket. These are compared
  120. // and a shutdown message is sent back to the server.
  121. void OnMsgClassResponse(const std::string& str) {
  122. // We rely on the order of sync_socket.Send() and chan_->Send() in
  123. // the SyncSocketServerListener object.
  124. EXPECT_EQ(kHelloStringLength, socket_->Peek());
  125. char buf[kHelloStringLength];
  126. socket_->Receive(static_cast<void*>(buf), kHelloStringLength);
  127. EXPECT_EQ(strcmp(str.c_str(), buf), 0);
  128. // After receiving from the socket there should be no bytes left.
  129. EXPECT_EQ(0U, socket_->Peek());
  130. IPC::Message* msg = new MsgClassShutdown();
  131. EXPECT_TRUE(chan_->Send(msg));
  132. base::RunLoop::QuitCurrentWhenIdleDeprecated();
  133. }
  134. raw_ptr<base::SyncSocket> socket_;
  135. raw_ptr<IPC::Channel> chan_;
  136. };
  137. using SyncSocketTest = IPCChannelMojoTestBase;
  138. TEST_F(SyncSocketTest, SanityTest) {
  139. Init("SyncSocketServerClient");
  140. SyncSocketClientListener listener;
  141. CreateChannel(&listener);
  142. // Create a pair of SyncSockets.
  143. base::SyncSocket pair[2];
  144. base::SyncSocket::CreatePair(&pair[0], &pair[1]);
  145. // Immediately after creation there should be no pending bytes.
  146. EXPECT_EQ(0U, pair[0].Peek());
  147. EXPECT_EQ(0U, pair[1].Peek());
  148. base::SyncSocket::Handle target_handle;
  149. // Connect the channel and listener.
  150. ASSERT_TRUE(ConnectChannel());
  151. listener.Init(&pair[0], channel());
  152. #if BUILDFLAG(IS_WIN)
  153. // On windows we need to duplicate the handle into the server process.
  154. BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1].handle(),
  155. client_process().Handle(), &target_handle,
  156. 0, FALSE, DUPLICATE_SAME_ACCESS);
  157. EXPECT_TRUE(retval);
  158. // Set up a message to pass the handle to the server.
  159. IPC::Message* msg = new MsgClassSetHandle(target_handle);
  160. #else
  161. target_handle = pair[1].handle();
  162. // Set up a message to pass the handle to the server.
  163. base::FileDescriptor filedesc(target_handle, false);
  164. IPC::Message* msg = new MsgClassSetHandle(filedesc);
  165. #endif // BUILDFLAG(IS_WIN)
  166. EXPECT_TRUE(sender()->Send(msg));
  167. // Use the current thread as the I/O thread.
  168. base::RunLoop().Run();
  169. // Shut down.
  170. pair[0].Close();
  171. pair[1].Close();
  172. EXPECT_TRUE(WaitForClientShutdown());
  173. DestroyChannel();
  174. }
  175. // A blocking read operation that will block the thread until it receives
  176. // |length| bytes of packets or Shutdown() is called on another thread.
  177. static void BlockingRead(base::SyncSocket* socket, char* buf,
  178. size_t length, size_t* received) {
  179. DCHECK_NE(buf, nullptr);
  180. // Notify the parent thread that we're up and running.
  181. socket->Send(kHelloString, kHelloStringLength);
  182. *received = socket->Receive(buf, length);
  183. }
  184. // Tests that we can safely end a blocking Receive operation on one thread
  185. // from another thread by disconnecting (but not closing) the socket.
  186. TEST_F(SyncSocketTest, DisconnectTest) {
  187. base::CancelableSyncSocket pair[2];
  188. ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
  189. base::Thread worker("BlockingThread");
  190. worker.Start();
  191. // Try to do a blocking read from one of the sockets on the worker thread.
  192. char buf[0xff];
  193. size_t received = 1U; // Initialize to an unexpected value.
  194. worker.task_runner()->PostTask(
  195. FROM_HERE, base::BindOnce(&BlockingRead, &pair[0], &buf[0],
  196. std::size(buf), &received));
  197. // Wait for the worker thread to say hello.
  198. char hello[kHelloStringLength] = {0};
  199. pair[1].Receive(&hello[0], sizeof(hello));
  200. EXPECT_EQ(0, strcmp(hello, kHelloString));
  201. // Give the worker a chance to start Receive().
  202. base::PlatformThread::YieldCurrentThread();
  203. // Now shut down the socket that the thread is issuing a blocking read on
  204. // which should cause Receive to return with an error.
  205. pair[0].Shutdown();
  206. worker.Stop();
  207. EXPECT_EQ(0U, received);
  208. }
  209. // Tests that read is a blocking operation.
  210. TEST_F(SyncSocketTest, BlockingReceiveTest) {
  211. base::CancelableSyncSocket pair[2];
  212. ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
  213. base::Thread worker("BlockingThread");
  214. worker.Start();
  215. // Try to do a blocking read from one of the sockets on the worker thread.
  216. char buf[kHelloStringLength] = {0};
  217. size_t received = 1U; // Initialize to an unexpected value.
  218. worker.task_runner()->PostTask(
  219. FROM_HERE, base::BindOnce(&BlockingRead, &pair[0], &buf[0],
  220. kHelloStringLength, &received));
  221. // Wait for the worker thread to say hello.
  222. char hello[kHelloStringLength] = {0};
  223. pair[1].Receive(&hello[0], sizeof(hello));
  224. EXPECT_EQ(0, strcmp(hello, kHelloString));
  225. // Give the worker a chance to start Receive().
  226. base::PlatformThread::YieldCurrentThread();
  227. // Send a message to the socket on the blocking thead, it should free the
  228. // socket from Receive().
  229. pair[1].Send(kHelloString, kHelloStringLength);
  230. worker.Stop();
  231. // Verify the socket has received the message.
  232. EXPECT_TRUE(strcmp(buf, kHelloString) == 0);
  233. EXPECT_EQ(kHelloStringLength, received);
  234. }
  235. // Tests that the write operation is non-blocking and returns immediately
  236. // when there is insufficient space in the socket's buffer.
  237. TEST_F(SyncSocketTest, NonBlockingWriteTest) {
  238. base::CancelableSyncSocket pair[2];
  239. ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
  240. // Fill up the buffer for one of the socket, Send() should not block the
  241. // thread even when the buffer is full.
  242. while (pair[0].Send(kHelloString, kHelloStringLength) != 0) {}
  243. // Data should be avialble on another socket.
  244. size_t bytes_in_buffer = pair[1].Peek();
  245. EXPECT_NE(bytes_in_buffer, 0U);
  246. // No more data can be written to the buffer since socket has been full,
  247. // verify that the amount of avialble data on another socket is unchanged.
  248. EXPECT_EQ(0U, pair[0].Send(kHelloString, kHelloStringLength));
  249. EXPECT_EQ(bytes_in_buffer, pair[1].Peek());
  250. // Read from another socket to free some space for a new write.
  251. char hello[kHelloStringLength] = {0};
  252. pair[1].Receive(&hello[0], sizeof(hello));
  253. // Should be able to write more data to the buffer now.
  254. EXPECT_EQ(kHelloStringLength, pair[0].Send(kHelloString, kHelloStringLength));
  255. }
  256. } // namespace