OLD | NEW |
| (Empty) |
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 | |
5 #include "chrome/nacl/nacl_ipc_adapter.h" | |
6 | |
7 #include <string.h> | |
8 | |
9 #include "base/memory/scoped_ptr.h" | |
10 #include "base/message_loop.h" | |
11 #include "base/message_loop/message_loop_proxy.h" | |
12 #include "base/threading/platform_thread.h" | |
13 #include "base/threading/simple_thread.h" | |
14 #include "ipc/ipc_test_sink.h" | |
15 #include "native_client/src/trusted/desc/nacl_desc_custom.h" | |
16 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h" | |
17 #include "ppapi/c/ppb_file_io.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 | |
20 namespace { | |
21 | |
22 class NaClIPCAdapterTest : public testing::Test { | |
23 public: | |
24 NaClIPCAdapterTest() {} | |
25 | |
26 // testing::Test implementation. | |
27 virtual void SetUp() OVERRIDE { | |
28 sink_ = new IPC::TestSink; | |
29 | |
30 // Takes ownership of the sink_ pointer. Note we provide the current message | |
31 // loop instead of using a real IO thread. This should work OK since we do | |
32 // not need real IPC for the tests. | |
33 adapter_ = new NaClIPCAdapter(scoped_ptr<IPC::Channel>(sink_), | |
34 base::MessageLoopProxy::current().get()); | |
35 } | |
36 virtual void TearDown() OVERRIDE { | |
37 sink_ = NULL; // This pointer is actually owned by the IPCAdapter. | |
38 adapter_ = NULL; | |
39 // The adapter destructor has to post a task to destroy the Channel on the | |
40 // IO thread. For the purposes of the test, we just need to make sure that | |
41 // task gets run, or it will appear as a leak. | |
42 message_loop_.RunUntilIdle(); | |
43 } | |
44 | |
45 protected: | |
46 int BlockingReceive(void* buf, size_t buf_size) { | |
47 NaClImcMsgIoVec iov = {buf, buf_size}; | |
48 NaClImcTypedMsgHdr msg = {&iov, 1}; | |
49 return adapter_->BlockingReceive(&msg); | |
50 } | |
51 | |
52 int Send(void* buf, size_t buf_size) { | |
53 NaClImcMsgIoVec iov = {buf, buf_size}; | |
54 NaClImcTypedMsgHdr msg = {&iov, 1}; | |
55 return adapter_->Send(&msg); | |
56 } | |
57 | |
58 base::MessageLoop message_loop_; | |
59 | |
60 scoped_refptr<NaClIPCAdapter> adapter_; | |
61 | |
62 // Messages sent from nacl to the adapter end up here. Note that we create | |
63 // this pointer and pass ownership of it to the IPC adapter, who will keep | |
64 // it alive as long as the adapter is alive. This means that when the | |
65 // adapter goes away, this pointer will become invalid. | |
66 // | |
67 // In real life the adapter needs to take ownership so the channel can be | |
68 // destroyed on the right thread. | |
69 IPC::TestSink* sink_; | |
70 }; | |
71 | |
72 } // namespace | |
73 | |
74 // Tests a simple message getting rewritten sent from native code to NaCl. | |
75 TEST_F(NaClIPCAdapterTest, SimpleReceiveRewriting) { | |
76 int routing_id = 0x89898989; | |
77 uint32 type = 0x55555555; | |
78 IPC::Message input(routing_id, type, IPC::Message::PRIORITY_NORMAL); | |
79 uint32 flags = input.flags(); | |
80 | |
81 int value = 0x12345678; | |
82 input.WriteInt(value); | |
83 adapter_->OnMessageReceived(input); | |
84 | |
85 // Buffer just need to be big enough for our message with one int. | |
86 const int kBufSize = 64; | |
87 char buf[kBufSize]; | |
88 | |
89 int bytes_read = BlockingReceive(buf, kBufSize); | |
90 EXPECT_EQ(sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int), | |
91 static_cast<size_t>(bytes_read)); | |
92 | |
93 const NaClIPCAdapter::NaClMessageHeader* output_header = | |
94 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(buf); | |
95 EXPECT_EQ(sizeof(int), output_header->payload_size); | |
96 EXPECT_EQ(routing_id, output_header->routing); | |
97 EXPECT_EQ(type, output_header->type); | |
98 EXPECT_EQ(flags, output_header->flags); | |
99 EXPECT_EQ(0u, output_header->num_fds); | |
100 EXPECT_EQ(0u, output_header->pad); | |
101 | |
102 // Validate the payload. | |
103 EXPECT_EQ(value, | |
104 *reinterpret_cast<const int*>(&buf[ | |
105 sizeof(NaClIPCAdapter::NaClMessageHeader)])); | |
106 } | |
107 | |
108 // Tests a simple message getting rewritten sent from NaCl to native code. | |
109 TEST_F(NaClIPCAdapterTest, SendRewriting) { | |
110 int routing_id = 0x89898989; | |
111 uint32 type = 0x55555555; | |
112 int value = 0x12345678; | |
113 | |
114 // Send a message with one int inside it. | |
115 const int buf_size = sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int); | |
116 char buf[buf_size] = {0}; | |
117 | |
118 NaClIPCAdapter::NaClMessageHeader* header = | |
119 reinterpret_cast<NaClIPCAdapter::NaClMessageHeader*>(buf); | |
120 header->payload_size = sizeof(int); | |
121 header->routing = routing_id; | |
122 header->type = type; | |
123 header->flags = 0; | |
124 header->num_fds = 0; | |
125 *reinterpret_cast<int*>( | |
126 &buf[sizeof(NaClIPCAdapter::NaClMessageHeader)]) = value; | |
127 | |
128 int result = Send(buf, buf_size); | |
129 EXPECT_EQ(buf_size, result); | |
130 | |
131 // Check that the message came out the other end in the test sink | |
132 // (messages are posted, so we have to pump). | |
133 message_loop_.RunUntilIdle(); | |
134 ASSERT_EQ(1u, sink_->message_count()); | |
135 const IPC::Message* msg = sink_->GetMessageAt(0); | |
136 | |
137 EXPECT_EQ(sizeof(int), msg->payload_size()); | |
138 EXPECT_EQ(header->routing, msg->routing_id()); | |
139 EXPECT_EQ(header->type, msg->type()); | |
140 | |
141 // Now test the partial send case. We should be able to break the message | |
142 // into two parts and it should still work. | |
143 sink_->ClearMessages(); | |
144 int first_chunk_size = 7; | |
145 result = Send(buf, first_chunk_size); | |
146 EXPECT_EQ(first_chunk_size, result); | |
147 | |
148 // First partial send should not have made any messages. | |
149 message_loop_.RunUntilIdle(); | |
150 ASSERT_EQ(0u, sink_->message_count()); | |
151 | |
152 // Second partial send should do the same. | |
153 int second_chunk_size = 2; | |
154 result = Send(&buf[first_chunk_size], second_chunk_size); | |
155 EXPECT_EQ(second_chunk_size, result); | |
156 message_loop_.RunUntilIdle(); | |
157 ASSERT_EQ(0u, sink_->message_count()); | |
158 | |
159 // Send the rest of the message in a third chunk. | |
160 int third_chunk_size = buf_size - first_chunk_size - second_chunk_size; | |
161 result = Send(&buf[first_chunk_size + second_chunk_size], | |
162 third_chunk_size); | |
163 EXPECT_EQ(third_chunk_size, result); | |
164 | |
165 // Last send should have generated one message. | |
166 message_loop_.RunUntilIdle(); | |
167 ASSERT_EQ(1u, sink_->message_count()); | |
168 msg = sink_->GetMessageAt(0); | |
169 EXPECT_EQ(sizeof(int), msg->payload_size()); | |
170 EXPECT_EQ(header->routing, msg->routing_id()); | |
171 EXPECT_EQ(header->type, msg->type()); | |
172 } | |
173 | |
174 // Tests when a buffer is too small to receive the entire message. | |
175 TEST_F(NaClIPCAdapterTest, PartialReceive) { | |
176 int routing_id_1 = 0x89898989; | |
177 uint32 type_1 = 0x55555555; | |
178 IPC::Message input_1(routing_id_1, type_1, IPC::Message::PRIORITY_NORMAL); | |
179 int value_1 = 0x12121212; | |
180 input_1.WriteInt(value_1); | |
181 adapter_->OnMessageReceived(input_1); | |
182 | |
183 int routing_id_2 = 0x90909090; | |
184 uint32 type_2 = 0x66666666; | |
185 IPC::Message input_2(routing_id_2, type_2, IPC::Message::PRIORITY_NORMAL); | |
186 int value_2 = 0x23232323; | |
187 input_2.WriteInt(value_2); | |
188 adapter_->OnMessageReceived(input_2); | |
189 | |
190 const int kBufSize = 64; | |
191 char buf[kBufSize]; | |
192 | |
193 // Read part of the first message. | |
194 int bytes_requested = 7; | |
195 int bytes_read = BlockingReceive(buf, bytes_requested); | |
196 ASSERT_EQ(bytes_requested, bytes_read); | |
197 | |
198 // Read the rest, this should give us the rest of the first message only. | |
199 bytes_read += BlockingReceive(&buf[bytes_requested], | |
200 kBufSize - bytes_requested); | |
201 EXPECT_EQ(sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int), | |
202 static_cast<size_t>(bytes_read)); | |
203 | |
204 // Make sure we got the right message. | |
205 const NaClIPCAdapter::NaClMessageHeader* output_header = | |
206 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(buf); | |
207 EXPECT_EQ(sizeof(int), output_header->payload_size); | |
208 EXPECT_EQ(routing_id_1, output_header->routing); | |
209 EXPECT_EQ(type_1, output_header->type); | |
210 | |
211 // Read the second message to make sure we went on to it. | |
212 bytes_read = BlockingReceive(buf, kBufSize); | |
213 EXPECT_EQ(sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int), | |
214 static_cast<size_t>(bytes_read)); | |
215 output_header = | |
216 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(buf); | |
217 EXPECT_EQ(sizeof(int), output_header->payload_size); | |
218 EXPECT_EQ(routing_id_2, output_header->routing); | |
219 EXPECT_EQ(type_2, output_header->type); | |
220 } | |
221 | |
222 // Tests sending messages that are too large. We test sends that are too | |
223 // small implicitly here and in the success case because in that case it | |
224 // succeeds and buffers the data. | |
225 TEST_F(NaClIPCAdapterTest, SendOverflow) { | |
226 int routing_id = 0x89898989; | |
227 uint32 type = 0x55555555; | |
228 int value = 0x12345678; | |
229 | |
230 // Make a message with one int inside it. Reserve some extra space so | |
231 // we can test what happens when we send too much data. | |
232 const int buf_size = sizeof(NaClIPCAdapter::NaClMessageHeader) + sizeof(int); | |
233 const int big_buf_size = buf_size + 4; | |
234 char buf[big_buf_size] = {0}; | |
235 | |
236 NaClIPCAdapter::NaClMessageHeader* header = | |
237 reinterpret_cast<NaClIPCAdapter::NaClMessageHeader*>(buf); | |
238 header->payload_size = sizeof(int); | |
239 header->routing = routing_id; | |
240 header->type = type; | |
241 header->flags = 0; | |
242 header->num_fds = 0; | |
243 *reinterpret_cast<int*>( | |
244 &buf[sizeof(NaClIPCAdapter::NaClMessageHeader)]) = value; | |
245 | |
246 // Send too much data and make sure that the send fails. | |
247 int result = Send(buf, big_buf_size); | |
248 EXPECT_EQ(-1, result); | |
249 message_loop_.RunUntilIdle(); | |
250 ASSERT_EQ(0u, sink_->message_count()); | |
251 | |
252 // Send too much data in two chunks and make sure that the send fails. | |
253 int first_chunk_size = 7; | |
254 result = Send(buf, first_chunk_size); | |
255 EXPECT_EQ(first_chunk_size, result); | |
256 | |
257 // First partial send should not have made any messages. | |
258 message_loop_.RunUntilIdle(); | |
259 ASSERT_EQ(0u, sink_->message_count()); | |
260 | |
261 int second_chunk_size = big_buf_size - first_chunk_size; | |
262 result = Send(&buf[first_chunk_size], second_chunk_size); | |
263 EXPECT_EQ(-1, result); | |
264 message_loop_.RunUntilIdle(); | |
265 ASSERT_EQ(0u, sink_->message_count()); | |
266 } | |
267 | |
268 // Tests that when the IPC channel reports an error, that waiting reads are | |
269 // unblocked and return a -1 error code. | |
270 TEST_F(NaClIPCAdapterTest, ReadWithChannelError) { | |
271 // Have a background thread that waits a bit and calls the channel error | |
272 // handler. This should wake up any waiting threads and immediately return | |
273 // -1. There is an inherent race condition in that we can't be sure if the | |
274 // other thread is actually waiting when this happens. This is OK, since the | |
275 // behavior (which we also explicitly test later) is to return -1 if the | |
276 // channel has already had an error when you start waiting. | |
277 class MyThread : public base::SimpleThread { | |
278 public: | |
279 explicit MyThread(NaClIPCAdapter* adapter) | |
280 : SimpleThread("NaClIPCAdapterThread"), | |
281 adapter_(adapter) {} | |
282 virtual void Run() OVERRIDE { | |
283 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); | |
284 adapter_->OnChannelError(); | |
285 } | |
286 private: | |
287 scoped_refptr<NaClIPCAdapter> adapter_; | |
288 }; | |
289 MyThread thread(adapter_.get()); | |
290 | |
291 // IMPORTANT: do not return early from here down (including ASSERT_*) because | |
292 // the thread needs to joined or it will assert. | |
293 thread.Start(); | |
294 | |
295 // Request data. This will normally (modulo races) block until data is | |
296 // received or there is an error, and the thread above will wake us up | |
297 // after 1s. | |
298 const int kBufSize = 64; | |
299 char buf[kBufSize]; | |
300 int result = BlockingReceive(buf, kBufSize); | |
301 EXPECT_EQ(-1, result); | |
302 | |
303 // Test the "previously had an error" case. BlockingReceive should return | |
304 // immediately if there was an error. | |
305 result = BlockingReceive(buf, kBufSize); | |
306 EXPECT_EQ(-1, result); | |
307 | |
308 thread.Join(); | |
309 } | |
310 | |
311 // Tests that TranslatePepperFileOpenFlags translates pepper read/write open | |
312 // flags into NaCl open flags correctly. | |
313 TEST_F(NaClIPCAdapterTest, TranslatePepperFileReadWriteOpenFlags) { | |
314 EXPECT_EQ(NACL_ABI_O_RDONLY, | |
315 TranslatePepperFileReadWriteOpenFlagsForTesting(PP_FILEOPENFLAG_READ)); | |
316 EXPECT_EQ(NACL_ABI_O_WRONLY, | |
317 TranslatePepperFileReadWriteOpenFlagsForTesting(PP_FILEOPENFLAG_WRITE)); | |
318 EXPECT_EQ(NACL_ABI_O_RDWR, | |
319 TranslatePepperFileReadWriteOpenFlagsForTesting( | |
320 PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE)); | |
321 | |
322 // The flags other than PP_FILEOPENFLAG_READ and PP_FILEOPENFLAG_WRITE are | |
323 // discared. | |
324 EXPECT_EQ(NACL_ABI_O_WRONLY, | |
325 TranslatePepperFileReadWriteOpenFlagsForTesting( | |
326 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE)); | |
327 EXPECT_EQ(NACL_ABI_O_WRONLY, | |
328 TranslatePepperFileReadWriteOpenFlagsForTesting( | |
329 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_TRUNCATE)); | |
330 EXPECT_EQ(NACL_ABI_O_WRONLY, | |
331 TranslatePepperFileReadWriteOpenFlagsForTesting( | |
332 PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_EXCLUSIVE)); | |
333 | |
334 // If neither of PP_FILEOPENFLAG_READ and PP_FILEOPENFLAG_WRITE is set, falls | |
335 // back NACL_ABI_O_READONLY | |
336 EXPECT_EQ(NACL_ABI_O_RDONLY, | |
337 TranslatePepperFileReadWriteOpenFlagsForTesting(PP_FILEOPENFLAG_CREATE)); | |
338 EXPECT_EQ(NACL_ABI_O_RDONLY, | |
339 TranslatePepperFileReadWriteOpenFlagsForTesting( | |
340 PP_FILEOPENFLAG_TRUNCATE)); | |
341 EXPECT_EQ(NACL_ABI_O_RDONLY, | |
342 TranslatePepperFileReadWriteOpenFlagsForTesting( | |
343 PP_FILEOPENFLAG_EXCLUSIVE)); | |
344 } | |
OLD | NEW |