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/logging.h"
21 #include "base/macros.h"
22 #include "mojo/embedder/platform_channel_utils_posix.h"
23 #include "mojo/embedder/scoped_platform_handle.h"
24 #include "testing/gtest/include/gtest/gtest.h"
30 ScopedPlatformHandle
PlatformHandleFromFILE(FILE* fp
) {
32 return ScopedPlatformHandle(PlatformHandle(dup(fileno(fp
))));
35 FILE* FILEFromPlatformHandle(ScopedPlatformHandle h
, const char* mode
) {
37 return fdopen(h
.release().fd
, mode
);
40 void WaitReadable(PlatformHandle h
) {
41 struct pollfd pfds
= {};
44 CHECK_EQ(poll(&pfds
, 1, -1), 1);
47 class PlatformChannelPairPosixTest
: public testing::Test
{
49 PlatformChannelPairPosixTest() {}
50 virtual ~PlatformChannelPairPosixTest() {}
52 virtual void SetUp() OVERRIDE
{
53 // Make sure |SIGPIPE| isn't being ignored.
54 struct sigaction action
= {};
55 action
.sa_handler
= SIG_DFL
;
56 ASSERT_EQ(0, sigaction(SIGPIPE
, &action
, &old_action_
));
59 virtual void TearDown() OVERRIDE
{
60 // Restore the |SIGPIPE| handler.
61 ASSERT_EQ(0, sigaction(SIGPIPE
, &old_action_
, NULL
));
65 struct sigaction old_action_
;
67 DISALLOW_COPY_AND_ASSIGN(PlatformChannelPairPosixTest
);
70 TEST_F(PlatformChannelPairPosixTest
, NoSigPipe
) {
71 PlatformChannelPair channel_pair
;
72 ScopedPlatformHandle server_handle
= channel_pair
.PassServerHandle().Pass();
73 ScopedPlatformHandle client_handle
= channel_pair
.PassClientHandle().Pass();
75 // Write to the client.
76 static const char kHello
[] = "hello";
77 EXPECT_EQ(static_cast<ssize_t
>(sizeof(kHello
)),
78 write(client_handle
.get().fd
, kHello
, sizeof(kHello
)));
81 client_handle
.reset();
83 // Read from the server; this should be okay.
84 char buffer
[100] = {};
85 EXPECT_EQ(static_cast<ssize_t
>(sizeof(kHello
)),
86 read(server_handle
.get().fd
, buffer
, sizeof(buffer
)));
87 EXPECT_STREQ(kHello
, buffer
);
90 ssize_t result
= read(server_handle
.get().fd
, buffer
, sizeof(buffer
));
91 // We should probably get zero (for "end of file"), but -1 would also be okay.
92 EXPECT_TRUE(result
== 0 || result
== -1);
94 PLOG(WARNING
) << "read (expected 0 for EOF)";
96 // Test our replacement for |write()|/|send()|.
97 result
= PlatformChannelWrite(server_handle
.get(), kHello
, sizeof(kHello
));
98 EXPECT_EQ(-1, result
);
100 PLOG(WARNING
) << "write (expected EPIPE)";
102 // Test our replacement for |writev()|/|sendv()|.
103 struct iovec iov
[2] = {
104 { const_cast<char*>(kHello
), sizeof(kHello
) },
105 { const_cast<char*>(kHello
), sizeof(kHello
) }
107 result
= PlatformChannelWritev(server_handle
.get(), iov
, 2);
108 EXPECT_EQ(-1, result
);
110 PLOG(WARNING
) << "write (expected EPIPE)";
113 TEST_F(PlatformChannelPairPosixTest
, SendReceiveData
) {
114 PlatformChannelPair channel_pair
;
115 ScopedPlatformHandle server_handle
= channel_pair
.PassServerHandle().Pass();
116 ScopedPlatformHandle client_handle
= channel_pair
.PassClientHandle().Pass();
118 for (size_t i
= 0; i
< 10; i
++) {
119 std::string
send_string(1 << i
, 'A' + i
);
121 EXPECT_EQ(static_cast<ssize_t
>(send_string
.size()),
122 PlatformChannelWrite(server_handle
.get(), send_string
.data(),
123 send_string
.size()));
125 WaitReadable(client_handle
.get());
127 char buf
[10000] = {};
128 scoped_ptr
<PlatformHandleVector
> received_handles
;
129 ssize_t result
= PlatformChannelRecvmsg(client_handle
.get(), buf
,
130 sizeof(buf
), &received_handles
);
131 EXPECT_EQ(static_cast<ssize_t
>(send_string
.size()), result
);
132 EXPECT_EQ(send_string
, std::string(buf
, static_cast<size_t>(result
)));
133 EXPECT_FALSE(received_handles
);
137 TEST_F(PlatformChannelPairPosixTest
, SendReceiveFDs
) {
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 ignored
;
147 FILE* fp
= base::CreateAndOpenTemporaryFile(&ignored
);
149 platform_handles
.push_back(PlatformHandleFromFILE(fp
).release());
150 ASSERT_TRUE(platform_handles
.back().is_valid());
151 fwrite(std::string(j
, '0' + i
).data(), 1, j
, fp
);
156 EXPECT_TRUE(PlatformChannelSendHandles(server_handle
.get(),
157 &platform_handles
[0],
158 platform_handles
.size()));
160 WaitReadable(client_handle
.get());
162 char buf
[100] = { 'a' };
163 scoped_ptr
<PlatformHandleVector
> received_handles
;
164 EXPECT_EQ(1, PlatformChannelRecvmsg(client_handle
.get(), buf
, sizeof(buf
),
166 EXPECT_EQ('\0', buf
[0]);
167 ASSERT_TRUE(received_handles
);
168 EXPECT_EQ(i
, received_handles
->size());
170 for (size_t j
= 0; j
< received_handles
->size(); j
++) {
171 FILE* fp
= FILEFromPlatformHandle(
172 ScopedPlatformHandle((*received_handles
)[j
]), "rb");
173 (*received_handles
)[j
] = PlatformHandle();
177 size_t bytes_read
= fread(read_buf
, 1, sizeof(read_buf
), fp
);
179 EXPECT_EQ(j
+ 1, bytes_read
);
180 EXPECT_EQ(std::string(j
+ 1, '0' + i
), std::string(read_buf
, bytes_read
));
185 TEST_F(PlatformChannelPairPosixTest
, AppendReceivedFDs
) {
186 PlatformChannelPair channel_pair
;
187 ScopedPlatformHandle server_handle
= channel_pair
.PassServerHandle().Pass();
188 ScopedPlatformHandle client_handle
= channel_pair
.PassClientHandle().Pass();
190 const std::string
file_contents("hello world");
193 base::FilePath ignored
;
194 FILE* fp
= base::CreateAndOpenTemporaryFile(&ignored
);
196 PlatformHandleVector platform_handles
;
197 platform_handles
.push_back(PlatformHandleFromFILE(fp
).release());
198 ASSERT_TRUE(platform_handles
.back().is_valid());
199 fwrite(file_contents
.data(), 1, file_contents
.size(), fp
);
203 EXPECT_TRUE(PlatformChannelSendHandles(server_handle
.get(),
204 &platform_handles
[0],
205 platform_handles
.size()));
208 WaitReadable(client_handle
.get());
210 // Start with an invalid handle in the vector.
211 scoped_ptr
<PlatformHandleVector
> handles(new PlatformHandleVector());
212 handles
->push_back(PlatformHandle());
214 char buf
[100] = { 'a' };
215 EXPECT_EQ(1, PlatformChannelRecvmsg(client_handle
.get(), buf
, sizeof(buf
),
217 EXPECT_EQ('\0', buf
[0]);
218 ASSERT_TRUE(handles
);
219 ASSERT_EQ(2u, handles
->size());
220 EXPECT_FALSE((*handles
)[0].is_valid());
221 EXPECT_TRUE((*handles
)[1].is_valid());
224 FILE* fp
= FILEFromPlatformHandle(ScopedPlatformHandle((*handles
)[1]),
226 (*handles
)[1] = PlatformHandle();
230 size_t bytes_read
= fread(read_buf
, 1, sizeof(read_buf
), fp
);
232 EXPECT_EQ(file_contents
.size(), bytes_read
);
233 EXPECT_EQ(file_contents
, std::string(read_buf
, bytes_read
));
238 } // namespace embedder