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