| 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 |