blob: 382f9bcd56272e34ebdd7ed69f9e525c6a60ad7c [file] [log] [blame]
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Florian Mayerf7f0def2018-09-27 13:59:24 +010017#include "perfetto/base/unix_socket.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000018
19#include <sys/mman.h>
20
21#include <list>
Primiano Tucci7a265b62017-12-07 18:37:31 +000022#include <thread>
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000023
24#include "gmock/gmock.h"
25#include "gtest/gtest.h"
26#include "perfetto/base/build_config.h"
27#include "perfetto/base/logging.h"
Primiano Tucci941b2212018-03-14 22:46:31 +000028#include "perfetto/base/temp_file.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000029#include "perfetto/base/utils.h"
30#include "src/base/test/test_task_runner.h"
Primiano Tuccib03ba362017-12-06 09:47:41 +000031#include "src/ipc/test/test_socket.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000032
33namespace perfetto {
Florian Mayerf7f0def2018-09-27 13:59:24 +010034namespace base {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000035namespace {
36
37using ::testing::_;
Primiano Tucci9b5d3362017-12-21 21:42:17 +010038using ::testing::AtLeast;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000039using ::testing::Invoke;
Primiano Tucci9b5d3362017-12-21 21:42:17 +010040using ::testing::InvokeWithoutArgs;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000041using ::testing::Mock;
42
Florian Mayerdbd08782018-03-21 14:07:51 +000043constexpr char kSocketName[] = TEST_SOCK_NAME("unix_socket_unittest");
Florian Mayerf3c0ac82018-10-02 11:53:55 +010044constexpr auto kBlocking = UnixSocket::BlockingMode::kBlocking;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000045
46class MockEventListener : public UnixSocket::EventListener {
47 public:
48 MOCK_METHOD2(OnNewIncomingConnection, void(UnixSocket*, UnixSocket*));
49 MOCK_METHOD2(OnConnect, void(UnixSocket*, bool));
50 MOCK_METHOD1(OnDisconnect, void(UnixSocket*));
51 MOCK_METHOD1(OnDataAvailable, void(UnixSocket*));
52
53 // GMock doesn't support mocking methods with non-copiable args.
54 void OnNewIncomingConnection(
55 UnixSocket* self,
56 std::unique_ptr<UnixSocket> new_connection) override {
57 incoming_connections_.emplace_back(std::move(new_connection));
58 OnNewIncomingConnection(self, incoming_connections_.back().get());
59 }
60
61 std::unique_ptr<UnixSocket> GetIncomingConnection() {
62 if (incoming_connections_.empty())
63 return nullptr;
64 std::unique_ptr<UnixSocket> sock = std::move(incoming_connections_.front());
65 incoming_connections_.pop_front();
66 return sock;
67 }
68
69 private:
70 std::list<std::unique_ptr<UnixSocket>> incoming_connections_;
71};
72
73class UnixSocketTest : public ::testing::Test {
74 protected:
Primiano Tuccib03ba362017-12-06 09:47:41 +000075 void SetUp() override { DESTROY_TEST_SOCK(kSocketName); }
76 void TearDown() override { DESTROY_TEST_SOCK(kSocketName); }
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000077
Florian Mayerf7f0def2018-09-27 13:59:24 +010078 TestTaskRunner task_runner_;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000079 MockEventListener event_listener_;
80};
81
82TEST_F(UnixSocketTest, ConnectionFailureIfUnreachable) {
83 auto cli = UnixSocket::Connect(kSocketName, &event_listener_, &task_runner_);
84 ASSERT_FALSE(cli->is_connected());
85 auto checkpoint = task_runner_.CreateCheckpoint("failure");
86 EXPECT_CALL(event_listener_, OnConnect(cli.get(), false))
Primiano Tucci9b5d3362017-12-21 21:42:17 +010087 .WillOnce(InvokeWithoutArgs(checkpoint));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000088 task_runner_.RunUntilCheckpoint("failure");
89}
90
91// Both server and client should see an OnDisconnect() if the server drops
92// incoming connections immediately as they are created.
93TEST_F(UnixSocketTest, ConnectionImmediatelyDroppedByServer) {
94 auto srv = UnixSocket::Listen(kSocketName, &event_listener_, &task_runner_);
95 ASSERT_TRUE(srv->is_listening());
96
97 // The server will immediately shutdown the connection upon
98 // OnNewIncomingConnection().
99 auto srv_did_shutdown = task_runner_.CreateCheckpoint("srv_did_shutdown");
100 EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
101 .WillOnce(
102 Invoke([this, srv_did_shutdown](UnixSocket*, UnixSocket* new_conn) {
103 EXPECT_CALL(event_listener_, OnDisconnect(new_conn));
Florian Mayer48c139c2018-03-12 14:07:57 +0000104 new_conn->Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000105 srv_did_shutdown();
106 }));
107
108 auto checkpoint = task_runner_.CreateCheckpoint("cli_connected");
109 auto cli = UnixSocket::Connect(kSocketName, &event_listener_, &task_runner_);
110 EXPECT_CALL(event_listener_, OnConnect(cli.get(), true))
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100111 .WillOnce(InvokeWithoutArgs(checkpoint));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000112 task_runner_.RunUntilCheckpoint("cli_connected");
113 task_runner_.RunUntilCheckpoint("srv_did_shutdown");
114
115 // Trying to send something will trigger the disconnection notification.
116 auto cli_disconnected = task_runner_.CreateCheckpoint("cli_disconnected");
117 EXPECT_CALL(event_listener_, OnDisconnect(cli.get()))
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100118 .WillOnce(InvokeWithoutArgs(cli_disconnected));
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100119 EXPECT_FALSE(cli->Send("whatever", kBlocking));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000120 task_runner_.RunUntilCheckpoint("cli_disconnected");
121}
122
123TEST_F(UnixSocketTest, ClientAndServerExchangeData) {
124 auto srv = UnixSocket::Listen(kSocketName, &event_listener_, &task_runner_);
125 ASSERT_TRUE(srv->is_listening());
126
127 auto cli = UnixSocket::Connect(kSocketName, &event_listener_, &task_runner_);
128 EXPECT_CALL(event_listener_, OnConnect(cli.get(), true));
129 auto cli_connected = task_runner_.CreateCheckpoint("cli_connected");
130 auto srv_disconnected = task_runner_.CreateCheckpoint("srv_disconnected");
131 EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
132 .WillOnce(Invoke([this, cli_connected, srv_disconnected](
133 UnixSocket*, UnixSocket* srv_conn) {
134 EXPECT_CALL(event_listener_, OnDisconnect(srv_conn))
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100135 .WillOnce(InvokeWithoutArgs(srv_disconnected));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000136 cli_connected();
137 }));
138 task_runner_.RunUntilCheckpoint("cli_connected");
139
140 auto srv_conn = event_listener_.GetIncomingConnection();
141 ASSERT_TRUE(srv_conn);
142 ASSERT_TRUE(cli->is_connected());
143
144 auto cli_did_recv = task_runner_.CreateCheckpoint("cli_did_recv");
145 EXPECT_CALL(event_listener_, OnDataAvailable(cli.get()))
146 .WillOnce(Invoke([cli_did_recv](UnixSocket* s) {
147 ASSERT_EQ("srv>cli", s->ReceiveString());
148 cli_did_recv();
149 }));
150
151 auto srv_did_recv = task_runner_.CreateCheckpoint("srv_did_recv");
152 EXPECT_CALL(event_listener_, OnDataAvailable(srv_conn.get()))
153 .WillOnce(Invoke([srv_did_recv](UnixSocket* s) {
154 ASSERT_EQ("cli>srv", s->ReceiveString());
155 srv_did_recv();
156 }));
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100157 ASSERT_TRUE(cli->Send("cli>srv", kBlocking));
158 ASSERT_TRUE(srv_conn->Send("srv>cli", kBlocking));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000159 task_runner_.RunUntilCheckpoint("cli_did_recv");
160 task_runner_.RunUntilCheckpoint("srv_did_recv");
161
162 // Check that Send/Receive() fails gracefully once the socket is closed.
163 auto cli_disconnected = task_runner_.CreateCheckpoint("cli_disconnected");
164 EXPECT_CALL(event_listener_, OnDisconnect(cli.get()))
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100165 .WillOnce(InvokeWithoutArgs(cli_disconnected));
Florian Mayer48c139c2018-03-12 14:07:57 +0000166 cli->Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000167 char msg[4];
168 ASSERT_EQ(0u, cli->Receive(&msg, sizeof(msg)));
169 ASSERT_EQ("", cli->ReceiveString());
170 ASSERT_EQ(0u, srv_conn->Receive(&msg, sizeof(msg)));
171 ASSERT_EQ("", srv_conn->ReceiveString());
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100172 ASSERT_FALSE(cli->Send("foo", kBlocking));
173 ASSERT_FALSE(srv_conn->Send("bar", kBlocking));
Florian Mayer48c139c2018-03-12 14:07:57 +0000174 srv->Shutdown(true);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000175 task_runner_.RunUntilCheckpoint("cli_disconnected");
176 task_runner_.RunUntilCheckpoint("srv_disconnected");
177}
178
Florian Mayere1cd07d2018-07-31 11:56:41 +0100179constexpr char cli_str[] = "cli>srv";
180constexpr char srv_str[] = "srv>cli";
181
182TEST_F(UnixSocketTest, ClientAndServerExchangeFDs) {
183 auto srv = UnixSocket::Listen(kSocketName, &event_listener_, &task_runner_);
184 ASSERT_TRUE(srv->is_listening());
185
186 auto cli = UnixSocket::Connect(kSocketName, &event_listener_, &task_runner_);
187 EXPECT_CALL(event_listener_, OnConnect(cli.get(), true));
188 auto cli_connected = task_runner_.CreateCheckpoint("cli_connected");
189 auto srv_disconnected = task_runner_.CreateCheckpoint("srv_disconnected");
190 EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
191 .WillOnce(Invoke([this, cli_connected, srv_disconnected](
192 UnixSocket*, UnixSocket* srv_conn) {
193 EXPECT_CALL(event_listener_, OnDisconnect(srv_conn))
194 .WillOnce(InvokeWithoutArgs(srv_disconnected));
195 cli_connected();
196 }));
197 task_runner_.RunUntilCheckpoint("cli_connected");
198
199 auto srv_conn = event_listener_.GetIncomingConnection();
200 ASSERT_TRUE(srv_conn);
201 ASSERT_TRUE(cli->is_connected());
202
Florian Mayerf7f0def2018-09-27 13:59:24 +0100203 ScopedFile null_fd(open("/dev/null", O_RDONLY));
204 ScopedFile zero_fd(open("/dev/zero", O_RDONLY));
Florian Mayere1cd07d2018-07-31 11:56:41 +0100205
206 auto cli_did_recv = task_runner_.CreateCheckpoint("cli_did_recv");
207 EXPECT_CALL(event_listener_, OnDataAvailable(cli.get()))
208 .WillRepeatedly(Invoke([cli_did_recv](UnixSocket* s) {
Florian Mayerf7f0def2018-09-27 13:59:24 +0100209 ScopedFile fd_buf[3];
Florian Mayere1cd07d2018-07-31 11:56:41 +0100210 char buf[sizeof(cli_str)];
Florian Mayerf7f0def2018-09-27 13:59:24 +0100211 if (!s->Receive(buf, sizeof(buf), fd_buf, ArraySize(fd_buf)))
Florian Mayere1cd07d2018-07-31 11:56:41 +0100212 return;
213 ASSERT_STREQ(srv_str, buf);
214 ASSERT_NE(*fd_buf[0], -1);
215 ASSERT_NE(*fd_buf[1], -1);
216 ASSERT_EQ(*fd_buf[2], -1);
217
218 char rd_buf[1];
219 // /dev/null
220 ASSERT_EQ(read(*fd_buf[0], rd_buf, sizeof(rd_buf)), 0);
221 // /dev/zero
222 ASSERT_EQ(read(*fd_buf[1], rd_buf, sizeof(rd_buf)), 1);
223 cli_did_recv();
224 }));
225
226 auto srv_did_recv = task_runner_.CreateCheckpoint("srv_did_recv");
227 EXPECT_CALL(event_listener_, OnDataAvailable(srv_conn.get()))
228 .WillRepeatedly(Invoke([srv_did_recv](UnixSocket* s) {
Florian Mayerf7f0def2018-09-27 13:59:24 +0100229 ScopedFile fd_buf[3];
Florian Mayere1cd07d2018-07-31 11:56:41 +0100230 char buf[sizeof(srv_str)];
Florian Mayerf7f0def2018-09-27 13:59:24 +0100231 if (!s->Receive(buf, sizeof(buf), fd_buf, ArraySize(fd_buf)))
Florian Mayere1cd07d2018-07-31 11:56:41 +0100232 return;
233 ASSERT_STREQ(cli_str, buf);
234 ASSERT_NE(*fd_buf[0], -1);
235 ASSERT_NE(*fd_buf[1], -1);
236 ASSERT_EQ(*fd_buf[2], -1);
237
238 char rd_buf[1];
239 // /dev/null
240 ASSERT_EQ(read(*fd_buf[0], rd_buf, sizeof(rd_buf)), 0);
241 // /dev/zero
242 ASSERT_EQ(read(*fd_buf[1], rd_buf, sizeof(rd_buf)), 1);
243 srv_did_recv();
244 }));
245
246 int buf_fd[2] = {null_fd.get(), zero_fd.get()};
247
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100248 ASSERT_TRUE(cli->Send(cli_str, sizeof(cli_str), buf_fd,
249 base::ArraySize(buf_fd), kBlocking));
Florian Mayere1cd07d2018-07-31 11:56:41 +0100250 ASSERT_TRUE(srv_conn->Send(srv_str, sizeof(srv_str), buf_fd,
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100251 base::ArraySize(buf_fd), kBlocking));
Florian Mayere1cd07d2018-07-31 11:56:41 +0100252 task_runner_.RunUntilCheckpoint("srv_did_recv");
253 task_runner_.RunUntilCheckpoint("cli_did_recv");
254
255 auto cli_disconnected = task_runner_.CreateCheckpoint("cli_disconnected");
256 EXPECT_CALL(event_listener_, OnDisconnect(cli.get()))
257 .WillOnce(InvokeWithoutArgs(cli_disconnected));
258 cli->Shutdown(true);
259 srv->Shutdown(true);
260 task_runner_.RunUntilCheckpoint("srv_disconnected");
261 task_runner_.RunUntilCheckpoint("cli_disconnected");
262}
263
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100264TEST_F(UnixSocketTest, ListenWithPassedFileDescriptor) {
265 auto fd = UnixSocket::CreateAndBind(kSocketName);
266 auto srv = UnixSocket::Listen(std::move(fd), &event_listener_, &task_runner_);
267 ASSERT_TRUE(srv->is_listening());
268
269 auto cli = UnixSocket::Connect(kSocketName, &event_listener_, &task_runner_);
270 EXPECT_CALL(event_listener_, OnConnect(cli.get(), true));
271 auto cli_connected = task_runner_.CreateCheckpoint("cli_connected");
272 auto srv_disconnected = task_runner_.CreateCheckpoint("srv_disconnected");
273 EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
274 .WillOnce(Invoke([this, cli_connected, srv_disconnected](
275 UnixSocket*, UnixSocket* srv_conn) {
276 // Read the EOF state.
277 EXPECT_CALL(event_listener_, OnDataAvailable(srv_conn))
278 .WillOnce(
279 InvokeWithoutArgs([srv_conn] { srv_conn->ReceiveString(); }));
280 EXPECT_CALL(event_listener_, OnDisconnect(srv_conn))
281 .WillOnce(InvokeWithoutArgs(srv_disconnected));
282 cli_connected();
283 }));
284 task_runner_.RunUntilCheckpoint("cli_connected");
285 ASSERT_TRUE(cli->is_connected());
286 cli.reset();
287 task_runner_.RunUntilCheckpoint("srv_disconnected");
288}
289
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000290// Mostly a stress tests. Connects kNumClients clients to the same server and
291// tests that all can exchange data and can see the expected sequence of events.
292TEST_F(UnixSocketTest, SeveralClients) {
293 auto srv = UnixSocket::Listen(kSocketName, &event_listener_, &task_runner_);
294 ASSERT_TRUE(srv->is_listening());
295 constexpr size_t kNumClients = 32;
296 std::unique_ptr<UnixSocket> cli[kNumClients];
297
298 EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
299 .Times(kNumClients)
300 .WillRepeatedly(Invoke([this](UnixSocket*, UnixSocket* s) {
301 EXPECT_CALL(event_listener_, OnDataAvailable(s))
302 .WillOnce(Invoke([](UnixSocket* t) {
303 ASSERT_EQ("PING", t->ReceiveString());
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100304 ASSERT_TRUE(t->Send("PONG", kBlocking));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000305 }));
306 }));
307
308 for (size_t i = 0; i < kNumClients; i++) {
309 cli[i] = UnixSocket::Connect(kSocketName, &event_listener_, &task_runner_);
310 EXPECT_CALL(event_listener_, OnConnect(cli[i].get(), true))
311 .WillOnce(Invoke([](UnixSocket* s, bool success) {
312 ASSERT_TRUE(success);
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100313 ASSERT_TRUE(s->Send("PING", kBlocking));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000314 }));
315
316 auto checkpoint = task_runner_.CreateCheckpoint(std::to_string(i));
317 EXPECT_CALL(event_listener_, OnDataAvailable(cli[i].get()))
318 .WillOnce(Invoke([checkpoint](UnixSocket* s) {
319 ASSERT_EQ("PONG", s->ReceiveString());
320 checkpoint();
321 }));
322 }
323
324 for (size_t i = 0; i < kNumClients; i++) {
325 task_runner_.RunUntilCheckpoint(std::to_string(i));
326 ASSERT_TRUE(Mock::VerifyAndClearExpectations(cli[i].get()));
327 }
328}
329
330// Creates two processes. The server process creates a file and passes it over
331// the socket to the client. Both processes mmap the file in shared mode and
332// check that they see the same contents.
333TEST_F(UnixSocketTest, SharedMemory) {
334 int pipes[2];
335 ASSERT_EQ(0, pipe(pipes));
336
337 pid_t pid = fork();
338 ASSERT_GE(pid, 0);
339 constexpr size_t kTmpSize = 4096;
340
341 if (pid == 0) {
342 // Child process.
Florian Mayerf7f0def2018-09-27 13:59:24 +0100343 TempFile scoped_tmp = TempFile::CreateUnlinked();
Primiano Tucci941b2212018-03-14 22:46:31 +0000344 int tmp_fd = scoped_tmp.fd();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000345 ASSERT_FALSE(ftruncate(tmp_fd, kTmpSize));
346 char* mem = reinterpret_cast<char*>(
347 mmap(nullptr, kTmpSize, PROT_READ | PROT_WRITE, MAP_SHARED, tmp_fd, 0));
348 ASSERT_NE(nullptr, mem);
349 memcpy(mem, "shm rocks", 10);
350
351 auto srv = UnixSocket::Listen(kSocketName, &event_listener_, &task_runner_);
352 ASSERT_TRUE(srv->is_listening());
353 // Signal the other process that it can connect.
354 ASSERT_EQ(1, PERFETTO_EINTR(write(pipes[1], ".", 1)));
355 auto checkpoint = task_runner_.CreateCheckpoint("change_seen_by_server");
356 EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
357 .WillOnce(Invoke(
358 [this, tmp_fd, checkpoint, mem](UnixSocket*, UnixSocket* new_conn) {
359 ASSERT_EQ(geteuid(), static_cast<uint32_t>(new_conn->peer_uid()));
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100360 ASSERT_TRUE(new_conn->Send("txfd", 5, tmp_fd, kBlocking));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000361 // Wait for the client to change this again.
362 EXPECT_CALL(event_listener_, OnDataAvailable(new_conn))
363 .WillOnce(Invoke([checkpoint, mem](UnixSocket* s) {
364 ASSERT_EQ("change notify", s->ReceiveString());
365 ASSERT_STREQ("rock more", mem);
366 checkpoint();
367 }));
368 }));
369 task_runner_.RunUntilCheckpoint("change_seen_by_server");
370 ASSERT_TRUE(Mock::VerifyAndClearExpectations(&event_listener_));
371 _exit(0);
372 } else {
373 char sync_cmd = '\0';
374 ASSERT_EQ(1, PERFETTO_EINTR(read(pipes[0], &sync_cmd, 1)));
375 ASSERT_EQ('.', sync_cmd);
376 auto cli =
377 UnixSocket::Connect(kSocketName, &event_listener_, &task_runner_);
378 EXPECT_CALL(event_listener_, OnConnect(cli.get(), true));
379 auto checkpoint = task_runner_.CreateCheckpoint("change_seen_by_client");
380 EXPECT_CALL(event_listener_, OnDataAvailable(cli.get()))
381 .WillOnce(Invoke([checkpoint](UnixSocket* s) {
382 char msg[32];
Florian Mayerf7f0def2018-09-27 13:59:24 +0100383 ScopedFile fd;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000384 ASSERT_EQ(5u, s->Receive(msg, sizeof(msg), &fd));
385 ASSERT_STREQ("txfd", msg);
386 ASSERT_TRUE(fd);
387 char* mem = reinterpret_cast<char*>(mmap(
388 nullptr, kTmpSize, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0));
389 ASSERT_NE(nullptr, mem);
390 mem[9] = '\0'; // Just to get a clean error in case of test failure.
391 ASSERT_STREQ("shm rocks", mem);
392
393 // Now change the shared memory and ping the other process.
394 memcpy(mem, "rock more", 10);
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100395 ASSERT_TRUE(s->Send("change notify", kBlocking));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000396 checkpoint();
397 }));
398 task_runner_.RunUntilCheckpoint("change_seen_by_client");
399 int st = 0;
400 PERFETTO_EINTR(waitpid(pid, &st, 0));
401 ASSERT_FALSE(WIFSIGNALED(st)) << "Server died with signal " << WTERMSIG(st);
402 EXPECT_TRUE(WIFEXITED(st));
403 ASSERT_EQ(0, WEXITSTATUS(st));
404 }
405}
406
407constexpr size_t kAtomicWrites_FrameSize = 1123;
408bool AtomicWrites_SendAttempt(UnixSocket* s,
Florian Mayerf7f0def2018-09-27 13:59:24 +0100409 TaskRunner* task_runner,
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000410 int num_frame) {
411 char buf[kAtomicWrites_FrameSize];
412 memset(buf, static_cast<char>(num_frame), sizeof(buf));
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100413 if (s->Send(buf, sizeof(buf), -1, kBlocking))
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000414 return true;
415 task_runner->PostTask(
416 std::bind(&AtomicWrites_SendAttempt, s, task_runner, num_frame));
417 return false;
418}
419
420// Creates a client-server pair. The client sends continuously data to the
421// server. Upon each Send() attempt, the client sends a buffer which is memset()
422// with a unique number (0 to kNumFrames). We are deliberately trying to fill
423// the socket output buffer, so we expect some of these Send()s to fail.
424// The client is extremely aggressive and, when a Send() fails, just keeps
425// re-posting it with the same unique number. The server verifies that we
426// receive one and exactly one of each buffers, without any gaps or truncation.
Florian Mayer39bac132018-05-23 18:22:37 +0100427TEST_F(UnixSocketTest, DISABLED_SendIsAtomic) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000428 static constexpr int kNumFrames = 127;
429
430 auto srv = UnixSocket::Listen(kSocketName, &event_listener_, &task_runner_);
431 ASSERT_TRUE(srv->is_listening());
432
433 auto cli = UnixSocket::Connect(kSocketName, &event_listener_, &task_runner_);
434
435 auto all_frames_done = task_runner_.CreateCheckpoint("all_frames_done");
436 std::set<int> received_iterations;
437 EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
438 .WillOnce(Invoke([this, &received_iterations, all_frames_done](
439 UnixSocket*, UnixSocket* srv_conn) {
440 EXPECT_CALL(event_listener_, OnDataAvailable(srv_conn))
441 .WillRepeatedly(
442 Invoke([&received_iterations, all_frames_done](UnixSocket* s) {
443 char buf[kAtomicWrites_FrameSize];
444 size_t res = s->Receive(buf, sizeof(buf));
445 if (res == 0)
446 return; // Spurious select(), could happen.
447 ASSERT_EQ(kAtomicWrites_FrameSize, res);
448 // Check that we didn't get two truncated frames.
449 for (size_t i = 0; i < sizeof(buf); i++)
450 ASSERT_EQ(buf[0], buf[i]);
451 ASSERT_EQ(0u, received_iterations.count(buf[0]));
452 received_iterations.insert(buf[0]);
453 if (received_iterations.size() == kNumFrames)
454 all_frames_done();
455 }));
456 }));
457
458 auto cli_connected = task_runner_.CreateCheckpoint("cli_connected");
459 EXPECT_CALL(event_listener_, OnConnect(cli.get(), true))
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100460 .WillOnce(InvokeWithoutArgs(cli_connected));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000461 task_runner_.RunUntilCheckpoint("cli_connected");
462 ASSERT_TRUE(cli->is_connected());
463 ASSERT_EQ(geteuid(), static_cast<uint32_t>(cli->peer_uid()));
464
465 bool did_requeue = false;
466 for (int i = 0; i < kNumFrames; i++)
467 did_requeue |= !AtomicWrites_SendAttempt(cli.get(), &task_runner_, i);
468
469 // We expect that at least one of the kNumFrames didn't fit in the socket
470 // buffer and was re-posted, otherwise this entire test would be pointless.
471 ASSERT_TRUE(did_requeue);
472
473 task_runner_.RunUntilCheckpoint("all_frames_done");
474}
475
476// Checks that the peer_uid() is retained after the client disconnects. The IPC
477// layer needs to rely on this to validate messages received immediately before
478// a client disconnects.
Florian Mayerfa1659e2018-08-07 10:45:19 +0100479TEST_F(UnixSocketTest, PeerCredentialsRetainedAfterDisconnect) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000480 auto srv = UnixSocket::Listen(kSocketName, &event_listener_, &task_runner_);
481 ASSERT_TRUE(srv->is_listening());
482 UnixSocket* srv_client_conn = nullptr;
483 auto srv_connected = task_runner_.CreateCheckpoint("srv_connected");
484 EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
485 .WillOnce(Invoke(
486 [&srv_client_conn, srv_connected](UnixSocket*, UnixSocket* srv_conn) {
487 srv_client_conn = srv_conn;
488 EXPECT_EQ(geteuid(), static_cast<uint32_t>(srv_conn->peer_uid()));
Florian Mayerfa1659e2018-08-07 10:45:19 +0100489#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
490 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
491 EXPECT_EQ(getpid(), static_cast<uint32_t>(srv_conn->peer_pid()));
492#endif
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000493 srv_connected();
494 }));
495 auto cli_connected = task_runner_.CreateCheckpoint("cli_connected");
496 auto cli = UnixSocket::Connect(kSocketName, &event_listener_, &task_runner_);
497 EXPECT_CALL(event_listener_, OnConnect(cli.get(), true))
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100498 .WillOnce(InvokeWithoutArgs(cli_connected));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000499
500 task_runner_.RunUntilCheckpoint("cli_connected");
501 task_runner_.RunUntilCheckpoint("srv_connected");
502 ASSERT_NE(nullptr, srv_client_conn);
503 ASSERT_TRUE(srv_client_conn->is_connected());
504
505 auto cli_disconnected = task_runner_.CreateCheckpoint("cli_disconnected");
506 EXPECT_CALL(event_listener_, OnDisconnect(srv_client_conn))
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100507 .WillOnce(InvokeWithoutArgs(cli_disconnected));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000508
509 // TODO(primiano): when the a peer disconnects, the other end receives a
510 // spurious OnDataAvailable() that needs to be acked with a Receive() to read
511 // the EOF. See b/69536434.
512 EXPECT_CALL(event_listener_, OnDataAvailable(srv_client_conn))
513 .WillOnce(Invoke([](UnixSocket* sock) { sock->ReceiveString(); }));
514
515 cli.reset();
516 task_runner_.RunUntilCheckpoint("cli_disconnected");
517 ASSERT_FALSE(srv_client_conn->is_connected());
518 EXPECT_EQ(geteuid(), static_cast<uint32_t>(srv_client_conn->peer_uid()));
Florian Mayerfa1659e2018-08-07 10:45:19 +0100519#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
520 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
521 EXPECT_EQ(getpid(), static_cast<uint32_t>(srv_client_conn->peer_pid()));
522#endif
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000523}
524
Primiano Tucci7a265b62017-12-07 18:37:31 +0000525TEST_F(UnixSocketTest, BlockingSend) {
526 auto srv = UnixSocket::Listen(kSocketName, &event_listener_, &task_runner_);
527 ASSERT_TRUE(srv->is_listening());
528
529 auto all_frames_done = task_runner_.CreateCheckpoint("all_frames_done");
530 size_t total_bytes_received = 0;
Primiano Tuccicee10fc2017-12-11 00:22:58 +0000531 constexpr size_t kTotalBytes = 1024 * 1024 * 4;
Primiano Tucci7a265b62017-12-07 18:37:31 +0000532 EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
533 .WillOnce(Invoke([this, &total_bytes_received, all_frames_done](
534 UnixSocket*, UnixSocket* srv_conn) {
535 EXPECT_CALL(event_listener_, OnDataAvailable(srv_conn))
536 .WillRepeatedly(
537 Invoke([&total_bytes_received, all_frames_done](UnixSocket* s) {
538 char buf[1024];
539 size_t res = s->Receive(buf, sizeof(buf));
540 total_bytes_received += res;
541 if (total_bytes_received == kTotalBytes)
542 all_frames_done();
543 }));
544 }));
545
546 // Override default timeout as this test can take time on the emulator.
Primiano Tuccicee10fc2017-12-11 00:22:58 +0000547 const int kTimeoutMs = 60000 * 3;
Primiano Tucci7a265b62017-12-07 18:37:31 +0000548
549 // Perform the blocking send form another thread.
550 std::thread tx_thread([] {
Florian Mayerf7f0def2018-09-27 13:59:24 +0100551 TestTaskRunner tx_task_runner;
Primiano Tucci7a265b62017-12-07 18:37:31 +0000552 MockEventListener tx_events;
553 auto cli = UnixSocket::Connect(kSocketName, &tx_events, &tx_task_runner);
554
555 auto cli_connected = tx_task_runner.CreateCheckpoint("cli_connected");
556 EXPECT_CALL(tx_events, OnConnect(cli.get(), true))
Primiano Tucci9b5d3362017-12-21 21:42:17 +0100557 .WillOnce(InvokeWithoutArgs(cli_connected));
Primiano Tucci7a265b62017-12-07 18:37:31 +0000558 tx_task_runner.RunUntilCheckpoint("cli_connected");
559
560 auto all_sent = tx_task_runner.CreateCheckpoint("all_sent");
Primiano Tuccicee10fc2017-12-11 00:22:58 +0000561 char buf[1024 * 32] = {};
562 tx_task_runner.PostTask([&cli, &buf, all_sent] {
Primiano Tucci7a265b62017-12-07 18:37:31 +0000563 for (size_t i = 0; i < kTotalBytes / sizeof(buf); i++)
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100564 cli->Send(buf, sizeof(buf), -1 /*fd*/, kBlocking);
Primiano Tucci7a265b62017-12-07 18:37:31 +0000565 all_sent();
566 });
567 tx_task_runner.RunUntilCheckpoint("all_sent", kTimeoutMs);
568 });
569
570 task_runner_.RunUntilCheckpoint("all_frames_done", kTimeoutMs);
571 tx_thread.join();
572}
573
Primiano Tucci5ae66da2018-03-28 15:57:34 +0100574// Regression test for b/76155349 . If the receiver end disconnects while the
575// sender is in the middle of a large send(), the socket should gracefully give
576// up (i.e. Shutdown()) but not crash.
577TEST_F(UnixSocketTest, ReceiverDisconnectsDuringSend) {
578 auto srv = UnixSocket::Listen(kSocketName, &event_listener_, &task_runner_);
579 ASSERT_TRUE(srv->is_listening());
580 const int kTimeoutMs = 30000;
581
582 auto receive_done = task_runner_.CreateCheckpoint("receive_done");
583 EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
584 .WillOnce(Invoke([this, receive_done](UnixSocket*, UnixSocket* srv_conn) {
585 EXPECT_CALL(event_listener_, OnDataAvailable(srv_conn))
586 .WillOnce(Invoke([receive_done](UnixSocket* s) {
587 char buf[1024];
588 size_t res = s->Receive(buf, sizeof(buf));
589 ASSERT_EQ(1024u, res);
590 s->Shutdown(false /*notify*/);
591 receive_done();
592 }));
593 }));
594
595 // Perform the blocking send form another thread.
596 std::thread tx_thread([] {
Florian Mayerf7f0def2018-09-27 13:59:24 +0100597 TestTaskRunner tx_task_runner;
Primiano Tucci5ae66da2018-03-28 15:57:34 +0100598 MockEventListener tx_events;
599 auto cli = UnixSocket::Connect(kSocketName, &tx_events, &tx_task_runner);
600
601 auto cli_connected = tx_task_runner.CreateCheckpoint("cli_connected");
602 EXPECT_CALL(tx_events, OnConnect(cli.get(), true))
603 .WillOnce(InvokeWithoutArgs(cli_connected));
604 tx_task_runner.RunUntilCheckpoint("cli_connected");
605
606 auto send_done = tx_task_runner.CreateCheckpoint("send_done");
607 // We need a
608 static constexpr size_t kBufSize = 32 * 1024 * 1024;
Primiano Tucciea56fd32018-03-28 20:15:26 +0100609 std::unique_ptr<char[]> buf(new char[kBufSize]());
Primiano Tucci5ae66da2018-03-28 15:57:34 +0100610 tx_task_runner.PostTask([&cli, &buf, send_done] {
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100611 bool send_res = cli->Send(buf.get(), kBufSize, -1 /*fd*/, kBlocking);
Primiano Tucci5ae66da2018-03-28 15:57:34 +0100612 ASSERT_FALSE(send_res);
613 send_done();
614 });
615
616 tx_task_runner.RunUntilCheckpoint("send_done", kTimeoutMs);
617 });
618 task_runner_.RunUntilCheckpoint("receive_done", kTimeoutMs);
619 tx_thread.join();
620}
621
Florian Mayerf3c0ac82018-10-02 11:53:55 +0100622TEST_F(UnixSocketTest, ShiftMsgHdrSendPartialFirst) {
623 // Send a part of the first iov, then send the rest.
624 struct iovec iov[2] = {};
625 char hello[] = "hello";
626 char world[] = "world";
627 iov[0].iov_base = &hello[0];
628 iov[0].iov_len = base::ArraySize(hello);
629
630 iov[1].iov_base = &world[0];
631 iov[1].iov_len = base::ArraySize(world);
632
633 struct msghdr hdr = {};
634 hdr.msg_iov = iov;
635 hdr.msg_iovlen = base::ArraySize(iov);
636
637 ShiftMsgHdr(1, &hdr);
638 EXPECT_NE(hdr.msg_iov, nullptr);
639 EXPECT_EQ(hdr.msg_iov[0].iov_base, &hello[1]);
640 EXPECT_EQ(hdr.msg_iov[1].iov_base, &world[0]);
641 EXPECT_EQ(hdr.msg_iovlen, 2);
642 EXPECT_STREQ(reinterpret_cast<char*>(hdr.msg_iov[0].iov_base), "ello");
643 EXPECT_EQ(iov[0].iov_len, base::ArraySize(hello) - 1);
644
645 ShiftMsgHdr(base::ArraySize(hello) - 1, &hdr);
646 EXPECT_EQ(hdr.msg_iov, &iov[1]);
647 EXPECT_EQ(hdr.msg_iovlen, 1);
648 EXPECT_STREQ(reinterpret_cast<char*>(hdr.msg_iov[0].iov_base), world);
649 EXPECT_EQ(hdr.msg_iov[0].iov_len, base::ArraySize(world));
650
651 ShiftMsgHdr(base::ArraySize(world), &hdr);
652 EXPECT_EQ(hdr.msg_iov, nullptr);
653 EXPECT_EQ(hdr.msg_iovlen, 0);
654}
655
656TEST_F(UnixSocketTest, ShiftMsgHdrSendFirstAndPartial) {
657 // Send first iov and part of the second iov, then send the rest.
658 struct iovec iov[2] = {};
659 char hello[] = "hello";
660 char world[] = "world";
661 iov[0].iov_base = &hello[0];
662 iov[0].iov_len = base::ArraySize(hello);
663
664 iov[1].iov_base = &world[0];
665 iov[1].iov_len = base::ArraySize(world);
666
667 struct msghdr hdr = {};
668 hdr.msg_iov = iov;
669 hdr.msg_iovlen = base::ArraySize(iov);
670
671 ShiftMsgHdr(base::ArraySize(hello) + 1, &hdr);
672 EXPECT_NE(hdr.msg_iov, nullptr);
673 EXPECT_EQ(hdr.msg_iovlen, 1);
674 EXPECT_STREQ(reinterpret_cast<char*>(hdr.msg_iov[0].iov_base), "orld");
675 EXPECT_EQ(hdr.msg_iov[0].iov_len, base::ArraySize(world) - 1);
676
677 ShiftMsgHdr(base::ArraySize(world) - 1, &hdr);
678 EXPECT_EQ(hdr.msg_iov, nullptr);
679 EXPECT_EQ(hdr.msg_iovlen, 0);
680}
681
682TEST_F(UnixSocketTest, ShiftMsgHdrSendEverything) {
683 // Send everything at once.
684 struct iovec iov[2] = {};
685 char hello[] = "hello";
686 char world[] = "world";
687 iov[0].iov_base = &hello[0];
688 iov[0].iov_len = base::ArraySize(hello);
689
690 iov[1].iov_base = &world[0];
691 iov[1].iov_len = base::ArraySize(world);
692
693 struct msghdr hdr = {};
694 hdr.msg_iov = iov;
695 hdr.msg_iovlen = base::ArraySize(iov);
696
697 ShiftMsgHdr(base::ArraySize(world) + base::ArraySize(hello), &hdr);
698 EXPECT_EQ(hdr.msg_iov, nullptr);
699 EXPECT_EQ(hdr.msg_iovlen, 0);
700}
701
702void Handler(int) {}
703
704int RollbackSigaction(const struct sigaction* act) {
705 return sigaction(SIGWINCH, act, nullptr);
706}
707
708TEST_F(UnixSocketTest, PartialSendMsgAll) {
709 int sv[2];
710 ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sv), 0);
711 base::ScopedFile send_socket(sv[0]);
712 base::ScopedFile recv_socket(sv[1]);
713
714 // Set bufsize to minimum.
715 int bufsize = 1024;
716 ASSERT_EQ(setsockopt(*send_socket, SOL_SOCKET, SO_SNDBUF, &bufsize,
717 sizeof(bufsize)),
718 0);
719 ASSERT_EQ(setsockopt(*recv_socket, SOL_SOCKET, SO_RCVBUF, &bufsize,
720 sizeof(bufsize)),
721 0);
722
723 // Send something larger than send + recv kernel buffers combined to make
724 // sendmsg block.
725 char send_buf[8192];
726 // Make MSAN happy.
727 for (size_t i = 0; i < sizeof(send_buf); ++i)
728 send_buf[i] = static_cast<char>(i % 256);
729 char recv_buf[sizeof(send_buf)];
730
731 // Need to install signal handler to cause the interrupt to happen.
732 // man 3 pthread_kill:
733 // Signal dispositions are process-wide: if a signal handler is
734 // installed, the handler will be invoked in the thread thread, but if
735 // the disposition of the signal is "stop", "continue", or "terminate",
736 // this action will affect the whole process.
737 struct sigaction oldact;
738 struct sigaction newact = {};
739 newact.sa_handler = Handler;
740 ASSERT_EQ(sigaction(SIGWINCH, &newact, &oldact), 0);
741 base::ScopedResource<const struct sigaction*, RollbackSigaction, nullptr>
742 rollback(&oldact);
743
744 auto blocked_thread = pthread_self();
745 std::thread th([blocked_thread, &recv_socket, &recv_buf] {
746 ssize_t rd = PERFETTO_EINTR(read(*recv_socket, recv_buf, 1));
747 ASSERT_EQ(rd, 1);
748 // We are now sure the other thread is in sendmsg, interrupt send.
749 ASSERT_EQ(pthread_kill(blocked_thread, SIGWINCH), 0);
750 // Drain the socket to allow SendMsgAll to succeed.
751 size_t offset = 1;
752 while (offset < sizeof(recv_buf)) {
753 rd = PERFETTO_EINTR(
754 read(*recv_socket, recv_buf + offset, sizeof(recv_buf) - offset));
755 ASSERT_GE(rd, 0);
756 offset += static_cast<size_t>(rd);
757 }
758 });
759
760 // Test sending the send_buf in several chunks as an iov to exercise the
761 // more complicated code-paths of SendMsgAll.
762 struct msghdr hdr = {};
763 struct iovec iov[4];
764 static_assert(sizeof(send_buf) % base::ArraySize(iov) == 0,
765 "Cannot split buffer into even pieces.");
766 constexpr size_t kChunkSize = sizeof(send_buf) / base::ArraySize(iov);
767 for (size_t i = 0; i < base::ArraySize(iov); ++i) {
768 iov[i].iov_base = send_buf + i * kChunkSize;
769 iov[i].iov_len = kChunkSize;
770 }
771 hdr.msg_iov = iov;
772 hdr.msg_iovlen = base::ArraySize(iov);
773
774 ASSERT_EQ(SendMsgAll(*send_socket, &hdr, 0), sizeof(send_buf));
775 send_socket.reset();
776 th.join();
777 // Make sure the re-entry logic was actually triggered.
778 ASSERT_EQ(hdr.msg_iov, nullptr);
779 ASSERT_EQ(memcmp(send_buf, recv_buf, sizeof(send_buf)), 0);
780}
781
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000782// TODO(primiano): add a test to check that in the case of a peer sending a fd
783// and the other end just doing a recv (without taking it), the fd is closed and
784// not left around.
785
786// TODO(primiano); add a test to check that a socket can be reused after
787// Shutdown(),
788
789// TODO(primiano): add a test to check that OnDisconnect() is called in all
790// possible cases.
791
792// TODO(primiano): add tests that destroy the socket in all possible stages and
793// verify that no spurious EventListener callback is received.
794
795} // namespace
Florian Mayerf7f0def2018-09-27 13:59:24 +0100796} // namespace base
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000797} // namespace perfetto