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