1 // Copyright 2014 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.
5 #include "mojo/embedder/platform_channel_pair.h"
11 #include <sys/socket.h>
12 #include <sys/types.h>
18 #include "base/file_util.h"
19 #include "base/files/file_path.h"
20 #include "base/files/scoped_file.h"
21 #include "base/files/scoped_temp_dir.h"
22 #include "base/logging.h"
23 #include "base/macros.h"
24 #include "mojo/common/test/test_utils.h"
25 #include "mojo/embedder/platform_channel_utils_posix.h"
26 #include "mojo/embedder/platform_handle.h"
27 #include "mojo/embedder/platform_handle_vector.h"
28 #include "mojo/embedder/scoped_platform_handle.h"
29 #include "testing/gtest/include/gtest/gtest.h"
35 void WaitReadable(PlatformHandle h
) {
36 struct pollfd pfds
= {};
39 CHECK_EQ(poll(&pfds
, 1, -1), 1);
42 class PlatformChannelPairPosixTest
: public testing::Test
{
44 PlatformChannelPairPosixTest() {}
45 virtual ~PlatformChannelPairPosixTest() {}
47 virtual void SetUp() OVERRIDE
{
48 // Make sure |SIGPIPE| isn't being ignored.
49 struct sigaction action
= {};
50 action
.sa_handler
= SIG_DFL
;
51 ASSERT_EQ(0, sigaction(SIGPIPE
, &action
, &old_action_
));
54 virtual void TearDown() OVERRIDE
{
55 // Restore the |SIGPIPE| handler.
56 ASSERT_EQ(0, sigaction(SIGPIPE
, &old_action_
, NULL
));
60 struct sigaction old_action_
;
62 DISALLOW_COPY_AND_ASSIGN(PlatformChannelPairPosixTest
);
65 TEST_F(PlatformChannelPairPosixTest
, NoSigPipe
) {
66 PlatformChannelPair channel_pair
;
67 ScopedPlatformHandle server_handle
= channel_pair
.PassServerHandle().Pass();
68 ScopedPlatformHandle client_handle
= channel_pair
.PassClientHandle().Pass();
70 // Write to the client.
71 static const char kHello
[] = "hello";
72 EXPECT_EQ(static_cast<ssize_t
>(sizeof(kHello
)),
73 write(client_handle
.get().fd
, kHello
, sizeof(kHello
)));
76 client_handle
.reset();
78 // Read from the server; this should be okay.
79 char buffer
[100] = {};
80 EXPECT_EQ(static_cast<ssize_t
>(sizeof(kHello
)),
81 read(server_handle
.get().fd
, buffer
, sizeof(buffer
)));
82 EXPECT_STREQ(kHello
, buffer
);
85 ssize_t result
= read(server_handle
.get().fd
, buffer
, sizeof(buffer
));
86 // We should probably get zero (for "end of file"), but -1 would also be okay.
87 EXPECT_TRUE(result
== 0 || result
== -1);
89 PLOG(WARNING
) << "read (expected 0 for EOF)";
91 // Test our replacement for |write()|/|send()|.
92 result
= PlatformChannelWrite(server_handle
.get(), kHello
, sizeof(kHello
));
93 EXPECT_EQ(-1, result
);
95 PLOG(WARNING
) << "write (expected EPIPE)";
97 // Test our replacement for |writev()|/|sendv()|.
98 struct iovec iov
[2] = {
99 { const_cast<char*>(kHello
), sizeof(kHello
) },
100 { const_cast<char*>(kHello
), sizeof(kHello
) }
102 result
= PlatformChannelWritev(server_handle
.get(), iov
, 2);
103 EXPECT_EQ(-1, result
);
105 PLOG(WARNING
) << "write (expected EPIPE)";
108 TEST_F(PlatformChannelPairPosixTest
, SendReceiveData
) {
109 PlatformChannelPair channel_pair
;
110 ScopedPlatformHandle server_handle
= channel_pair
.PassServerHandle().Pass();
111 ScopedPlatformHandle client_handle
= channel_pair
.PassClientHandle().Pass();
113 for (size_t i
= 0; i
< 10; i
++) {
114 std::string
send_string(1 << i
, 'A' + i
);
116 EXPECT_EQ(static_cast<ssize_t
>(send_string
.size()),
117 PlatformChannelWrite(server_handle
.get(), send_string
.data(),
118 send_string
.size()));
120 WaitReadable(client_handle
.get());
122 char buf
[10000] = {};
123 std::deque
<PlatformHandle
> received_handles
;
124 ssize_t result
= PlatformChannelRecvmsg(client_handle
.get(), buf
,
125 sizeof(buf
), &received_handles
);
126 EXPECT_EQ(static_cast<ssize_t
>(send_string
.size()), result
);
127 EXPECT_EQ(send_string
, std::string(buf
, static_cast<size_t>(result
)));
128 EXPECT_TRUE(received_handles
.empty());
132 TEST_F(PlatformChannelPairPosixTest
, SendReceiveFDs
) {
133 base::ScopedTempDir temp_dir
;
134 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
136 static const char kHello
[] = "hello";
138 PlatformChannelPair channel_pair
;
139 ScopedPlatformHandle server_handle
= channel_pair
.PassServerHandle().Pass();
140 ScopedPlatformHandle client_handle
= channel_pair
.PassClientHandle().Pass();
142 for (size_t i
= 1; i
< kPlatformChannelMaxNumHandles
; i
++) {
143 // Make |i| files, with the j-th file consisting of j copies of the digit i.
144 PlatformHandleVector platform_handles
;
145 for (size_t j
= 1; j
<= i
; j
++) {
146 base::FilePath unused
;
148 base::CreateAndOpenTemporaryFileInDir(temp_dir
.path(), &unused
));
150 ASSERT_EQ(j
, fwrite(std::string(j
, '0' + i
).data(), 1, j
, fp
.get()));
151 platform_handles
.push_back(
152 test::PlatformHandleFromFILE(fp
.Pass()).release());
153 ASSERT_TRUE(platform_handles
.back().is_valid());
156 // Send the FDs (+ "hello").
157 struct iovec iov
= { const_cast<char*>(kHello
), sizeof(kHello
) };
158 // We assume that the |sendmsg()| actually sends all the data.
159 EXPECT_EQ(static_cast<ssize_t
>(sizeof(kHello
)),
160 PlatformChannelSendmsgWithHandles(server_handle
.get(), &iov
, 1,
161 &platform_handles
[0],
162 platform_handles
.size()));
164 WaitReadable(client_handle
.get());
167 std::deque
<PlatformHandle
> received_handles
;
168 // We assume that the |recvmsg()| actually reads all the data.
169 EXPECT_EQ(static_cast<ssize_t
>(sizeof(kHello
)),
170 PlatformChannelRecvmsg(client_handle
.get(), buf
, sizeof(buf
),
172 EXPECT_STREQ(kHello
, buf
);
173 EXPECT_EQ(i
, received_handles
.size());
175 for (size_t j
= 0; !received_handles
.empty(); j
++) {
176 base::ScopedFILE
fp(test::FILEFromPlatformHandle(
177 ScopedPlatformHandle(received_handles
.front()), "rb"));
178 received_handles
.pop_front();
182 size_t bytes_read
= fread(read_buf
, 1, sizeof(read_buf
), fp
.get());
183 EXPECT_EQ(j
+ 1, bytes_read
);
184 EXPECT_EQ(std::string(j
+ 1, '0' + i
), std::string(read_buf
, bytes_read
));
189 TEST_F(PlatformChannelPairPosixTest
, AppendReceivedFDs
) {
190 base::ScopedTempDir temp_dir
;
191 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
193 static const char kHello
[] = "hello";
195 PlatformChannelPair channel_pair
;
196 ScopedPlatformHandle server_handle
= channel_pair
.PassServerHandle().Pass();
197 ScopedPlatformHandle client_handle
= channel_pair
.PassClientHandle().Pass();
199 const std::string
file_contents("hello world");
202 base::FilePath unused
;
203 base::ScopedFILE
fp(base::CreateAndOpenTemporaryFileInDir(temp_dir
.path(),
206 ASSERT_EQ(file_contents
.size(),
207 fwrite(file_contents
.data(), 1, file_contents
.size(), fp
.get()));
208 PlatformHandleVector platform_handles
;
209 platform_handles
.push_back(
210 test::PlatformHandleFromFILE(fp
.Pass()).release());
211 ASSERT_TRUE(platform_handles
.back().is_valid());
213 // Send the FD (+ "hello").
214 struct iovec iov
= { const_cast<char*>(kHello
), sizeof(kHello
) };
215 // We assume that the |sendmsg()| actually sends all the data.
216 EXPECT_EQ(static_cast<ssize_t
>(sizeof(kHello
)),
217 PlatformChannelSendmsgWithHandles(server_handle
.get(), &iov
, 1,
218 &platform_handles
[0],
219 platform_handles
.size()));
222 WaitReadable(client_handle
.get());
224 // Start with an invalid handle in the deque.
225 std::deque
<PlatformHandle
> received_handles
;
226 received_handles
.push_back(PlatformHandle());
229 // We assume that the |recvmsg()| actually reads all the data.
230 EXPECT_EQ(static_cast<ssize_t
>(sizeof(kHello
)),
231 PlatformChannelRecvmsg(client_handle
.get(), buf
, sizeof(buf
),
233 EXPECT_STREQ(kHello
, buf
);
234 ASSERT_EQ(2u, received_handles
.size());
235 EXPECT_FALSE(received_handles
[0].is_valid());
236 EXPECT_TRUE(received_handles
[1].is_valid());
239 base::ScopedFILE
fp(test::FILEFromPlatformHandle(
240 ScopedPlatformHandle(received_handles
[1]), "rb"));
241 received_handles
[1] = PlatformHandle();
245 size_t bytes_read
= fread(read_buf
, 1, sizeof(read_buf
), fp
.get());
246 EXPECT_EQ(file_contents
.size(), bytes_read
);
247 EXPECT_EQ(file_contents
, std::string(read_buf
, bytes_read
));
252 } // namespace embedder