OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/nacl/nacl_ipc_adapter.h" | 5 #include "ppapi/proxy/handle_converter.h" |
6 | 6 |
7 #include <limits.h> | 7 #include "ipc/ipc_message.h" |
8 #include <string.h> | |
9 | |
10 #include "base/basictypes.h" | |
11 #include "base/bind.h" | |
12 #include "base/location.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 #include "base/shared_memory.h" | |
15 #include "build/build_config.h" | |
16 #include "ipc/ipc_channel.h" | |
17 #include "ipc/ipc_message_macros.h" | 8 #include "ipc/ipc_message_macros.h" |
18 #include "ipc/ipc_platform_file.h" | |
19 #include "native_client/src/trusted/desc/nacl_desc_custom.h" | |
20 #include "native_client/src/trusted/desc/nacl_desc_wrapper.h" | |
21 #include "ppapi/proxy/ppapi_messages.h" | 9 #include "ppapi/proxy/ppapi_messages.h" |
22 #include "ppapi/proxy/resource_message_params.h" | 10 #include "ppapi/proxy/resource_message_params.h" |
| 11 #include "ppapi/proxy/serialized_handle.h" |
| 12 |
| 13 namespace IPC { |
| 14 class Message; |
| 15 } |
23 | 16 |
24 namespace { | 17 namespace { |
25 | 18 |
26 enum BufferSizeStatus { | |
27 // The buffer contains a full message with no extra bytes. | |
28 MESSAGE_IS_COMPLETE, | |
29 | |
30 // The message doesn't fit and the buffer contains only some of it. | |
31 MESSAGE_IS_TRUNCATED, | |
32 | |
33 // The buffer contains a full message + extra data. | |
34 MESSAGE_HAS_EXTRA_DATA | |
35 }; | |
36 | |
37 BufferSizeStatus GetBufferStatus(const char* data, size_t len) { | |
38 if (len < sizeof(NaClIPCAdapter::NaClMessageHeader)) | |
39 return MESSAGE_IS_TRUNCATED; | |
40 | |
41 const NaClIPCAdapter::NaClMessageHeader* header = | |
42 reinterpret_cast<const NaClIPCAdapter::NaClMessageHeader*>(data); | |
43 uint32 message_size = | |
44 sizeof(NaClIPCAdapter::NaClMessageHeader) + header->payload_size; | |
45 | |
46 if (len == message_size) | |
47 return MESSAGE_IS_COMPLETE; | |
48 if (len > message_size) | |
49 return MESSAGE_HAS_EXTRA_DATA; | |
50 return MESSAGE_IS_TRUNCATED; | |
51 } | |
52 | |
53 // This object allows the NaClDesc to hold a reference to a NaClIPCAdapter and | |
54 // forward calls to it. | |
55 struct DescThunker { | |
56 explicit DescThunker(NaClIPCAdapter* adapter_param) | |
57 : adapter(adapter_param) { | |
58 } | |
59 scoped_refptr<NaClIPCAdapter> adapter; | |
60 }; | |
61 | |
62 NaClIPCAdapter* ToAdapter(void* handle) { | |
63 return static_cast<DescThunker*>(handle)->adapter.get(); | |
64 } | |
65 | |
66 // NaClDescCustom implementation. | |
67 void NaClDescCustomDestroy(void* handle) { | |
68 delete static_cast<DescThunker*>(handle); | |
69 } | |
70 | |
71 ssize_t NaClDescCustomSendMsg(void* handle, const NaClImcTypedMsgHdr* msg, | |
72 int /* flags */) { | |
73 return static_cast<ssize_t>(ToAdapter(handle)->Send(msg)); | |
74 } | |
75 | |
76 ssize_t NaClDescCustomRecvMsg(void* handle, NaClImcTypedMsgHdr* msg, | |
77 int /* flags */) { | |
78 return static_cast<ssize_t>(ToAdapter(handle)->BlockingReceive(msg)); | |
79 } | |
80 | |
81 NaClDesc* MakeNaClDescCustom(NaClIPCAdapter* adapter) { | |
82 NaClDescCustomFuncs funcs = NACL_DESC_CUSTOM_FUNCS_INITIALIZER; | |
83 funcs.Destroy = NaClDescCustomDestroy; | |
84 funcs.SendMsg = NaClDescCustomSendMsg; | |
85 funcs.RecvMsg = NaClDescCustomRecvMsg; | |
86 // NaClDescMakeCustomDesc gives us a reference on the returned NaClDesc. | |
87 return NaClDescMakeCustomDesc(new DescThunker(adapter), &funcs); | |
88 } | |
89 | |
90 void DeleteChannel(IPC::Channel* channel) { | |
91 delete channel; | |
92 } | |
93 | |
94 // TODO(dmichael): Move all this handle conversion code to ppapi/proxy. | |
95 // crbug.com/165201 | |
96 void WriteHandle(int handle_index, | 19 void WriteHandle(int handle_index, |
97 const ppapi::proxy::SerializedHandle& handle, | 20 const ppapi::proxy::SerializedHandle& handle, |
98 IPC::Message* message) { | 21 IPC::Message* message) { |
99 ppapi::proxy::SerializedHandle::WriteHeader(handle.header(), message); | 22 ppapi::proxy::SerializedHandle::WriteHeader(handle.header(), message); |
100 | 23 |
101 // Now write the handle itself in POSIX style. | 24 // Now write the handle itself in POSIX style. |
102 message->WriteBool(true); // valid == true | 25 message->WriteBool(true); // valid == true |
103 message->WriteInt(handle_index); | 26 message->WriteInt(handle_index); |
104 } | 27 } |
105 | 28 |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 void ConvertHandlesImpl(const Tuple4<A, B, C, D>& t1, Handles* handles, | 112 void ConvertHandlesImpl(const Tuple4<A, B, C, D>& t1, Handles* handles, |
190 IPC::Message* msg) { | 113 IPC::Message* msg) { |
191 int handle_index = 0; | 114 int handle_index = 0; |
192 ConvertHandlesInParam(t1.a, handles, msg, &handle_index); | 115 ConvertHandlesInParam(t1.a, handles, msg, &handle_index); |
193 ConvertHandlesInParam(t1.b, handles, msg, &handle_index); | 116 ConvertHandlesInParam(t1.b, handles, msg, &handle_index); |
194 ConvertHandlesInParam(t1.c, handles, msg, &handle_index); | 117 ConvertHandlesInParam(t1.c, handles, msg, &handle_index); |
195 ConvertHandlesInParam(t1.d, handles, msg, &handle_index); | 118 ConvertHandlesInParam(t1.d, handles, msg, &handle_index); |
196 } | 119 } |
197 | 120 |
198 template <class MessageType> | 121 template <class MessageType> |
199 class HandleConverter { | 122 class HandleConverterImpl { |
200 public: | 123 public: |
201 explicit HandleConverter(const IPC::Message* msg) | 124 explicit HandleConverterImpl(const IPC::Message* msg) |
202 : msg_(static_cast<const MessageType*>(msg)) { | 125 : msg_(static_cast<const MessageType*>(msg)) { |
203 } | 126 } |
204 bool ConvertMessage(Handles* handles, IPC::Message* out_msg) { | 127 bool ConvertMessage(Handles* handles, IPC::Message* out_msg) { |
205 typename TupleTypes<typename MessageType::Schema::Param>::ValueTuple params; | 128 typename TupleTypes<typename MessageType::Schema::Param>::ValueTuple params; |
206 if (!MessageType::Read(msg_, ¶ms)) | 129 if (!MessageType::Read(msg_, ¶ms)) |
207 return false; | 130 return false; |
208 ConvertHandlesImpl(params, handles, out_msg); | 131 ConvertHandlesImpl(params, handles, out_msg); |
209 return true; | 132 return true; |
210 } | 133 } |
211 | 134 |
(...skipping 14 matching lines...) Expand all Loading... |
226 } | 149 } |
227 // TODO(dmichael): Add ConvertSyncMessage for outgoing sync messages, if we | 150 // TODO(dmichael): Add ConvertSyncMessage for outgoing sync messages, if we |
228 // ever pass handles in one of those. | 151 // ever pass handles in one of those. |
229 | 152 |
230 private: | 153 private: |
231 const MessageType* msg_; | 154 const MessageType* msg_; |
232 }; | 155 }; |
233 | 156 |
234 } // namespace | 157 } // namespace |
235 | 158 |
236 class NaClIPCAdapter::RewrittenMessage | |
237 : public base::RefCounted<RewrittenMessage> { | |
238 public: | |
239 RewrittenMessage(); | |
240 | |
241 bool is_consumed() const { return data_read_cursor_ == data_len_; } | |
242 | |
243 void SetData(const NaClIPCAdapter::NaClMessageHeader& header, | |
244 const void* payload, size_t payload_length); | |
245 | |
246 int Read(NaClImcTypedMsgHdr* msg); | |
247 | |
248 void AddDescriptor(nacl::DescWrapper* desc) { descs_.push_back(desc); } | |
249 | |
250 size_t desc_count() const { return descs_.size(); } | |
251 | |
252 private: | |
253 friend class base::RefCounted<RewrittenMessage>; | |
254 ~RewrittenMessage() {} | |
255 | |
256 scoped_array<char> data_; | |
257 size_t data_len_; | |
258 | |
259 // Offset into data where the next read will happen. This will be equal to | |
260 // data_len_ when all data has been consumed. | |
261 size_t data_read_cursor_; | |
262 | |
263 // Wrapped descriptors for transfer to untrusted code. | |
264 ScopedVector<nacl::DescWrapper> descs_; | |
265 }; | |
266 | |
267 NaClIPCAdapter::RewrittenMessage::RewrittenMessage() | |
268 : data_len_(0), | |
269 data_read_cursor_(0) { | |
270 } | |
271 | |
272 void NaClIPCAdapter::RewrittenMessage::SetData( | |
273 const NaClIPCAdapter::NaClMessageHeader& header, | |
274 const void* payload, | |
275 size_t payload_length) { | |
276 DCHECK(!data_.get() && data_len_ == 0); | |
277 size_t header_len = sizeof(NaClIPCAdapter::NaClMessageHeader); | |
278 data_len_ = header_len + payload_length; | |
279 data_.reset(new char[data_len_]); | |
280 | |
281 memcpy(data_.get(), &header, sizeof(NaClIPCAdapter::NaClMessageHeader)); | |
282 memcpy(&data_[header_len], payload, payload_length); | |
283 } | |
284 | |
285 int NaClIPCAdapter::RewrittenMessage::Read(NaClImcTypedMsgHdr* msg) { | |
286 CHECK(data_len_ >= data_read_cursor_); | |
287 char* dest_buffer = static_cast<char*>(msg->iov[0].base); | |
288 size_t dest_buffer_size = msg->iov[0].length; | |
289 size_t bytes_to_write = std::min(dest_buffer_size, | |
290 data_len_ - data_read_cursor_); | |
291 if (bytes_to_write == 0) | |
292 return 0; | |
293 | |
294 memcpy(dest_buffer, &data_[data_read_cursor_], bytes_to_write); | |
295 data_read_cursor_ += bytes_to_write; | |
296 | |
297 // Once all data has been consumed, transfer any file descriptors. | |
298 if (is_consumed()) { | |
299 nacl_abi_size_t desc_count = static_cast<nacl_abi_size_t>(descs_.size()); | |
300 CHECK(desc_count <= msg->ndesc_length); | |
301 msg->ndesc_length = desc_count; | |
302 for (nacl_abi_size_t i = 0; i < desc_count; i++) { | |
303 // Copy the NaClDesc to the buffer and add a ref so it won't be freed | |
304 // when we clear our ScopedVector. | |
305 msg->ndescv[i] = descs_[i]->desc(); | |
306 NaClDescRef(descs_[i]->desc()); | |
307 } | |
308 descs_.clear(); | |
309 } else { | |
310 msg->ndesc_length = 0; | |
311 } | |
312 return static_cast<int>(bytes_to_write); | |
313 } | |
314 | |
315 NaClIPCAdapter::LockedData::LockedData() | |
316 : channel_closed_(false) { | |
317 } | |
318 | |
319 NaClIPCAdapter::LockedData::~LockedData() { | |
320 } | |
321 | |
322 NaClIPCAdapter::IOThreadData::IOThreadData() { | |
323 } | |
324 | |
325 NaClIPCAdapter::IOThreadData::~IOThreadData() { | |
326 } | |
327 | |
328 NaClIPCAdapter::NaClIPCAdapter(const IPC::ChannelHandle& handle, | |
329 base::TaskRunner* runner) | |
330 : lock_(), | |
331 cond_var_(&lock_), | |
332 task_runner_(runner), | |
333 locked_data_() { | |
334 io_thread_data_.channel_.reset( | |
335 new IPC::Channel(handle, IPC::Channel::MODE_SERVER, this)); | |
336 // Note, we can not PostTask for ConnectChannelOnIOThread here. If we did, | |
337 // and that task ran before this constructor completes, the reference count | |
338 // would go to 1 and then to 0 because of the Task, before we've been returned | |
339 // to the owning scoped_refptr, which is supposed to give us our first | |
340 // ref-count. | |
341 } | |
342 | |
343 NaClIPCAdapter::NaClIPCAdapter(scoped_ptr<IPC::Channel> channel, | |
344 base::TaskRunner* runner) | |
345 : lock_(), | |
346 cond_var_(&lock_), | |
347 task_runner_(runner), | |
348 locked_data_() { | |
349 io_thread_data_.channel_ = channel.Pass(); | |
350 } | |
351 | |
352 void NaClIPCAdapter::ConnectChannel() { | |
353 task_runner_->PostTask(FROM_HERE, | |
354 base::Bind(&NaClIPCAdapter::ConnectChannelOnIOThread, this)); | |
355 } | |
356 | |
357 // Note that this message is controlled by the untrusted code. So we should be | |
358 // skeptical of anything it contains and quick to give up if anything is fishy. | |
359 int NaClIPCAdapter::Send(const NaClImcTypedMsgHdr* msg) { | |
360 if (msg->iov_length != 1) | |
361 return -1; | |
362 | |
363 base::AutoLock lock(lock_); | |
364 | |
365 const char* input_data = static_cast<char*>(msg->iov[0].base); | |
366 size_t input_data_len = msg->iov[0].length; | |
367 if (input_data_len > IPC::Channel::kMaximumMessageSize) { | |
368 ClearToBeSent(); | |
369 return -1; | |
370 } | |
371 | |
372 // current_message[_len] refers to the total input data received so far. | |
373 const char* current_message; | |
374 size_t current_message_len; | |
375 bool did_append_input_data; | |
376 if (locked_data_.to_be_sent_.empty()) { | |
377 // No accumulated data, we can avoid a copy by referring to the input | |
378 // buffer (the entire message fitting in one call is the common case). | |
379 current_message = input_data; | |
380 current_message_len = input_data_len; | |
381 did_append_input_data = false; | |
382 } else { | |
383 // We've already accumulated some data, accumulate this new data and | |
384 // point to the beginning of the buffer. | |
385 | |
386 // Make sure our accumulated message size doesn't overflow our max. Since | |
387 // we know that data_len < max size (checked above) and our current | |
388 // accumulated value is also < max size, we just need to make sure that | |
389 // 2x max size can never overflow. | |
390 COMPILE_ASSERT(IPC::Channel::kMaximumMessageSize < (UINT_MAX / 2), | |
391 MaximumMessageSizeWillOverflow); | |
392 size_t new_size = locked_data_.to_be_sent_.size() + input_data_len; | |
393 if (new_size > IPC::Channel::kMaximumMessageSize) { | |
394 ClearToBeSent(); | |
395 return -1; | |
396 } | |
397 | |
398 locked_data_.to_be_sent_.append(input_data, input_data_len); | |
399 current_message = &locked_data_.to_be_sent_[0]; | |
400 current_message_len = locked_data_.to_be_sent_.size(); | |
401 did_append_input_data = true; | |
402 } | |
403 | |
404 // Check the total data we've accumulated so far to see if it contains a full | |
405 // message. | |
406 switch (GetBufferStatus(current_message, current_message_len)) { | |
407 case MESSAGE_IS_COMPLETE: { | |
408 // Got a complete message, can send it out. This will be the common case. | |
409 bool success = SendCompleteMessage(current_message, current_message_len); | |
410 ClearToBeSent(); | |
411 return success ? static_cast<int>(input_data_len) : -1; | |
412 } | |
413 case MESSAGE_IS_TRUNCATED: | |
414 // For truncated messages, just accumulate the new data (if we didn't | |
415 // already do so above) and go back to waiting for more. | |
416 if (!did_append_input_data) | |
417 locked_data_.to_be_sent_.append(input_data, input_data_len); | |
418 return static_cast<int>(input_data_len); | |
419 case MESSAGE_HAS_EXTRA_DATA: | |
420 default: | |
421 // When the plugin gives us too much data, it's an error. | |
422 ClearToBeSent(); | |
423 return -1; | |
424 } | |
425 } | |
426 | |
427 int NaClIPCAdapter::BlockingReceive(NaClImcTypedMsgHdr* msg) { | |
428 if (msg->iov_length != 1) | |
429 return -1; | |
430 | |
431 int retval = 0; | |
432 { | |
433 base::AutoLock lock(lock_); | |
434 while (locked_data_.to_be_received_.empty() && | |
435 !locked_data_.channel_closed_) | |
436 cond_var_.Wait(); | |
437 if (locked_data_.channel_closed_) { | |
438 retval = -1; | |
439 } else { | |
440 retval = LockedReceive(msg); | |
441 DCHECK(retval > 0); | |
442 } | |
443 } | |
444 cond_var_.Signal(); | |
445 return retval; | |
446 } | |
447 | |
448 void NaClIPCAdapter::CloseChannel() { | |
449 { | |
450 base::AutoLock lock(lock_); | |
451 locked_data_.channel_closed_ = true; | |
452 } | |
453 cond_var_.Signal(); | |
454 | |
455 task_runner_->PostTask(FROM_HERE, | |
456 base::Bind(&NaClIPCAdapter::CloseChannelOnIOThread, this)); | |
457 } | |
458 | |
459 NaClDesc* NaClIPCAdapter::MakeNaClDesc() { | |
460 return MakeNaClDescCustom(this); | |
461 } | |
462 | |
463 #if defined(OS_POSIX) | |
464 int NaClIPCAdapter::TakeClientFileDescriptor() { | |
465 return io_thread_data_.channel_->TakeClientFileDescriptor(); | |
466 } | |
467 #endif | |
468 | |
469 #define CASE_FOR_MESSAGE(MESSAGE_TYPE) \ | 159 #define CASE_FOR_MESSAGE(MESSAGE_TYPE) \ |
470 case MESSAGE_TYPE::ID: { \ | 160 case MESSAGE_TYPE::ID: { \ |
471 HandleConverter<MESSAGE_TYPE> extractor(&msg); \ | 161 HandleConverterImpl<MESSAGE_TYPE> extractor(&msg); \ |
472 if (!extractor.ConvertMessage(&handles, new_msg_ptr)) \ | 162 if (!extractor.ConvertMessage(handles, new_msg_ptr->get())) \ |
473 return false; \ | 163 return false; \ |
474 break; \ | 164 break; \ |
475 } | 165 } |
476 #define CASE_FOR_REPLY(MESSAGE_TYPE) \ | 166 #define CASE_FOR_REPLY(MESSAGE_TYPE) \ |
477 case MESSAGE_TYPE::ID: { \ | 167 case MESSAGE_TYPE::ID: { \ |
478 HandleConverter<MESSAGE_TYPE> extractor(&msg); \ | 168 HandleConverterImpl<MESSAGE_TYPE> extractor(&msg); \ |
479 if (!extractor.ConvertReply( \ | 169 if (!extractor.ConvertReply( \ |
480 &handles, \ | 170 handles, \ |
481 static_cast<IPC::SyncMessage*>(new_msg_ptr))) \ | 171 static_cast<IPC::SyncMessage*>(new_msg_ptr->get()))) \ |
482 return false; \ | 172 return false; \ |
483 break; \ | 173 break; \ |
484 } | 174 } |
485 | 175 |
486 bool NaClIPCAdapter::OnMessageReceived(const IPC::Message& msg) { | 176 namespace ppapi { |
487 { | 177 namespace proxy { |
488 base::AutoLock lock(lock_); | |
489 | 178 |
490 scoped_refptr<RewrittenMessage> rewritten_msg(new RewrittenMessage); | 179 class SerializedHandle; |
491 | 180 |
492 // Pointer to the "new" message we will rewrite on Windows. On posix, this | 181 HandleConverter::HandleConverter() { |
493 // isn't necessary, so it will stay NULL. | 182 } |
494 IPC::Message* new_msg_ptr = NULL; | 183 |
495 IPC::Message new_msg(msg.routing_id(), msg.type(), msg.priority()); | 184 bool HandleConverter::ConvertNativeHandlesToPosix( |
| 185 const IPC::Message& msg, |
| 186 std::vector<SerializedHandle>* handles, |
| 187 scoped_ptr<IPC::Message>* new_msg_ptr) { |
| 188 DCHECK(handles); |
| 189 DCHECK(new_msg_ptr); |
| 190 DCHECK(!new_msg_ptr->get()); |
| 191 |
| 192 // In Windows, we need to re-write the contents of the message. This is |
| 193 // because in Windows IPC code, native HANDLE values are serialized in the |
| 194 // body of the message. |
| 195 // |
| 196 // In POSIX, we only serialize an index in to a FileDescriptorSet, and the |
| 197 // actual file descriptors are sent out-of-band. So on Windows, to make a |
| 198 // message that's compatible with Windows, we need to write a new message that |
| 199 // has simple indices in the message body instead of the HANDLEs. |
| 200 // |
| 201 // NOTE: This means on Windows, new_msg_ptr's serialized contents are not |
| 202 // compatible with Windows IPC deserialization code; it is intended to be |
| 203 // passed to NaCl. |
496 #if defined(OS_WIN) | 204 #if defined(OS_WIN) |
497 new_msg_ptr = &new_msg; | 205 new_msg_ptr->reset( |
| 206 new IPC::Message(msg.routing_id(), msg.type(), msg.priority())); |
498 #else | 207 #else |
499 // Even on POSIX, we have to rewrite messages to create channels, because | 208 // Even on POSIX, we have to rewrite messages to create channels, because |
500 // these contain a handle with an invalid (place holder) descriptor. The | 209 // these contain a handle with an invalid (place holder) descriptor. The |
501 // message sending code sees this and doesn't pass the descriptor over | 210 // message sending code sees this and doesn't pass the descriptor over |
502 // correctly. | 211 // correctly. |
503 if (msg.type() == PpapiMsg_CreateNaClChannel::ID) | 212 if (msg.type() == PpapiMsg_CreateNaClChannel::ID) { |
504 new_msg_ptr = &new_msg; | 213 new_msg_ptr->reset( |
| 214 new IPC::Message(msg.routing_id(), msg.type(), msg.priority())); |
| 215 } |
505 #endif | 216 #endif |
506 | 217 |
507 Handles handles; | 218 switch (msg.type()) { |
508 switch (msg.type()) { | 219 CASE_FOR_MESSAGE(PpapiMsg_CreateNaClChannel) |
509 CASE_FOR_MESSAGE(PpapiMsg_CreateNaClChannel) | 220 CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated) |
510 CASE_FOR_MESSAGE(PpapiMsg_PPBAudio_NotifyAudioStreamCreated) | 221 CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply) |
511 CASE_FOR_MESSAGE(PpapiPluginMsg_ResourceReply) | 222 case IPC_REPLY_ID: { |
512 case IPC_REPLY_ID: { | 223 int id = IPC::SyncMessage::GetMessageId(msg); |
513 int id = IPC::SyncMessage::GetMessageId(msg); | 224 PendingSyncMsgMap::iterator iter(pending_sync_msgs_.find(id)); |
514 LockedData::PendingSyncMsgMap::iterator iter( | 225 if (iter == pending_sync_msgs_.end()) { |
515 locked_data_.pending_sync_msgs_.find(id)); | 226 NOTREACHED(); |
516 if (iter == locked_data_.pending_sync_msgs_.end()) { | 227 return false; |
517 NOTREACHED(); | |
518 return false; | |
519 } | |
520 uint32_t type = iter->second; | |
521 locked_data_.pending_sync_msgs_.erase(iter); | |
522 switch (type) { | |
523 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer) | |
524 CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateNaCl) | |
525 CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall) | |
526 default: | |
527 // Do nothing for messages we don't know. | |
528 break; | |
529 } | |
530 break; | |
531 } | 228 } |
532 default: | 229 uint32_t type = iter->second; |
533 // Do nothing for messages we don't know. | 230 pending_sync_msgs_.erase(iter); |
534 break; | 231 switch (type) { |
| 232 CASE_FOR_REPLY(PpapiHostMsg_PPBGraphics3D_GetTransferBuffer) |
| 233 CASE_FOR_REPLY(PpapiHostMsg_PPBImageData_CreateNaCl) |
| 234 CASE_FOR_REPLY(PpapiHostMsg_ResourceSyncCall) |
| 235 default: |
| 236 // Do nothing for messages we don't know. |
| 237 break; |
| 238 } |
| 239 break; |
535 } | 240 } |
536 // Now add any descriptors we found to rewritten_msg. |handles| is usually | 241 default: |
537 // empty, unless we read a message containing a FD or handle. | 242 // Do nothing for messages we don't know. |
538 nacl::DescWrapperFactory factory; | 243 break; |
539 for (Handles::const_iterator iter = handles.begin(); | |
540 iter != handles.end(); | |
541 ++iter) { | |
542 scoped_ptr<nacl::DescWrapper> nacl_desc; | |
543 switch (iter->type()) { | |
544 case ppapi::proxy::SerializedHandle::SHARED_MEMORY: { | |
545 const base::SharedMemoryHandle& shm_handle = iter->shmem(); | |
546 uint32_t size = iter->size(); | |
547 nacl_desc.reset(factory.ImportShmHandle( | |
548 #if defined(OS_WIN) | |
549 reinterpret_cast<const NaClHandle>(shm_handle), | |
550 #else | |
551 shm_handle.fd, | |
552 #endif | |
553 static_cast<size_t>(size))); | |
554 break; | |
555 } | |
556 case ppapi::proxy::SerializedHandle::SOCKET: { | |
557 nacl_desc.reset(factory.ImportSyncSocketHandle( | |
558 #if defined(OS_WIN) | |
559 reinterpret_cast<const NaClHandle>(iter->descriptor()) | |
560 #else | |
561 iter->descriptor().fd | |
562 #endif | |
563 )); | |
564 break; | |
565 } | |
566 case ppapi::proxy::SerializedHandle::CHANNEL_HANDLE: { | |
567 // Check that this came from a PpapiMsg_CreateNaClChannel message. | |
568 // This code here is only appropriate for that message. | |
569 DCHECK(msg.type() == PpapiMsg_CreateNaClChannel::ID); | |
570 IPC::ChannelHandle channel_handle = | |
571 IPC::Channel::GenerateVerifiedChannelID("nacl"); | |
572 scoped_refptr<NaClIPCAdapter> ipc_adapter( | |
573 new NaClIPCAdapter(channel_handle, task_runner_)); | |
574 ipc_adapter->ConnectChannel(); | |
575 #if defined(OS_POSIX) | |
576 channel_handle.socket = base::FileDescriptor( | |
577 ipc_adapter->TakeClientFileDescriptor(), true); | |
578 #endif | |
579 nacl_desc.reset(factory.MakeGeneric(ipc_adapter->MakeNaClDesc())); | |
580 // Send back a message that the channel was created. | |
581 scoped_ptr<IPC::Message> response( | |
582 new PpapiHostMsg_ChannelCreated(channel_handle)); | |
583 task_runner_->PostTask(FROM_HERE, | |
584 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this, | |
585 base::Passed(&response))); | |
586 break; | |
587 } | |
588 case ppapi::proxy::SerializedHandle::FILE: | |
589 // TODO(raymes): Handle file handles for NaCl. | |
590 NOTIMPLEMENTED(); | |
591 break; | |
592 case ppapi::proxy::SerializedHandle::INVALID: { | |
593 // Nothing to do. TODO(dmichael): Should we log this? Or is it | |
594 // sometimes okay to pass an INVALID handle? | |
595 break; | |
596 } | |
597 // No default, so the compiler will warn us if new types get added. | |
598 } | |
599 if (nacl_desc.get()) | |
600 rewritten_msg->AddDescriptor(nacl_desc.release()); | |
601 } | |
602 if (new_msg_ptr && !handles.empty()) | |
603 SaveMessage(*new_msg_ptr, rewritten_msg.get()); | |
604 else | |
605 SaveMessage(msg, rewritten_msg.get()); | |
606 } | 244 } |
607 cond_var_.Signal(); | |
608 return true; | 245 return true; |
609 } | 246 } |
610 | 247 |
611 void NaClIPCAdapter::OnChannelConnected(int32 peer_pid) { | 248 void HandleConverter::RegisterSyncMessageForReply(const IPC::Message& msg) { |
| 249 DCHECK(msg.is_sync()); |
| 250 |
| 251 int msg_id = IPC::SyncMessage::GetMessageId(msg); |
| 252 DCHECK(pending_sync_msgs_.find(msg_id) == pending_sync_msgs_.end()); |
| 253 |
| 254 pending_sync_msgs_[msg_id] = msg.type(); |
612 } | 255 } |
613 | 256 |
614 void NaClIPCAdapter::OnChannelError() { | 257 } // namespace proxy |
615 CloseChannel(); | 258 } // namespace ppapi |
616 } | |
617 | |
618 NaClIPCAdapter::~NaClIPCAdapter() { | |
619 // Make sure the channel is deleted on the IO thread. | |
620 task_runner_->PostTask(FROM_HERE, | |
621 base::Bind(&DeleteChannel, io_thread_data_.channel_.release())); | |
622 } | |
623 | |
624 int NaClIPCAdapter::LockedReceive(NaClImcTypedMsgHdr* msg) { | |
625 lock_.AssertAcquired(); | |
626 | |
627 if (locked_data_.to_be_received_.empty()) | |
628 return 0; | |
629 scoped_refptr<RewrittenMessage> current = | |
630 locked_data_.to_be_received_.front(); | |
631 | |
632 int retval = current->Read(msg); | |
633 | |
634 // When a message is entirely consumed, remove if from the waiting queue. | |
635 if (current->is_consumed()) | |
636 locked_data_.to_be_received_.pop(); | |
637 | |
638 return retval; | |
639 } | |
640 | |
641 bool NaClIPCAdapter::SendCompleteMessage(const char* buffer, | |
642 size_t buffer_len) { | |
643 // The message will have already been validated, so we know it's large enough | |
644 // for our header. | |
645 const NaClMessageHeader* header = | |
646 reinterpret_cast<const NaClMessageHeader*>(buffer); | |
647 | |
648 // Length of the message not including the body. The data passed to us by the | |
649 // plugin should match that in the message header. This should have already | |
650 // been validated by GetBufferStatus. | |
651 int body_len = static_cast<int>(buffer_len - sizeof(NaClMessageHeader)); | |
652 DCHECK(body_len == static_cast<int>(header->payload_size)); | |
653 | |
654 // We actually discard the flags and only copy the ones we care about. This | |
655 // is just because message doesn't have a constructor that takes raw flags. | |
656 scoped_ptr<IPC::Message> msg( | |
657 new IPC::Message(header->routing, header->type, | |
658 IPC::Message::PRIORITY_NORMAL)); | |
659 if (header->flags & IPC::Message::SYNC_BIT) | |
660 msg->set_sync(); | |
661 if (header->flags & IPC::Message::REPLY_BIT) | |
662 msg->set_reply(); | |
663 if (header->flags & IPC::Message::REPLY_ERROR_BIT) | |
664 msg->set_reply_error(); | |
665 if (header->flags & IPC::Message::UNBLOCK_BIT) | |
666 msg->set_unblock(true); | |
667 | |
668 msg->WriteBytes(&buffer[sizeof(NaClMessageHeader)], body_len); | |
669 | |
670 // Technically we didn't have to do any of the previous work in the lock. But | |
671 // sometimes our buffer will point to the to_be_sent_ string which is | |
672 // protected by the lock, and it's messier to factor Send() such that it can | |
673 // unlock for us. Holding the lock for the message construction, which is | |
674 // just some memcpys, shouldn't be a big deal. | |
675 lock_.AssertAcquired(); | |
676 if (locked_data_.channel_closed_) | |
677 return false; // TODO(brettw) clean up handles here when we add support! | |
678 | |
679 // Store the type of all sync messages so that later we can translate the | |
680 // reply if necessary. | |
681 if (msg->is_sync()) { | |
682 int id = IPC::SyncMessage::GetMessageId(*msg); | |
683 locked_data_.pending_sync_msgs_[id] = msg->type(); | |
684 } | |
685 // Actual send must be done on the I/O thread. | |
686 task_runner_->PostTask(FROM_HERE, | |
687 base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this, | |
688 base::Passed(&msg))); | |
689 return true; | |
690 } | |
691 | |
692 void NaClIPCAdapter::ClearToBeSent() { | |
693 lock_.AssertAcquired(); | |
694 | |
695 // Don't let the string keep its buffer behind our back. | |
696 std::string empty; | |
697 locked_data_.to_be_sent_.swap(empty); | |
698 } | |
699 | |
700 void NaClIPCAdapter::ConnectChannelOnIOThread() { | |
701 if (!io_thread_data_.channel_->Connect()) | |
702 NOTREACHED(); | |
703 } | |
704 | |
705 void NaClIPCAdapter::CloseChannelOnIOThread() { | |
706 io_thread_data_.channel_->Close(); | |
707 } | |
708 | |
709 void NaClIPCAdapter::SendMessageOnIOThread(scoped_ptr<IPC::Message> message) { | |
710 io_thread_data_.channel_->Send(message.release()); | |
711 } | |
712 | |
713 void NaClIPCAdapter::SaveMessage(const IPC::Message& msg, | |
714 RewrittenMessage* rewritten_msg) { | |
715 lock_.AssertAcquired(); | |
716 // There is some padding in this structure (the "padding" member is 16 | |
717 // bits but this then gets padded to 32 bits). We want to be sure not to | |
718 // leak data to the untrusted plugin, so zero everything out first. | |
719 NaClMessageHeader header; | |
720 memset(&header, 0, sizeof(NaClMessageHeader)); | |
721 | |
722 header.payload_size = static_cast<uint32>(msg.payload_size()); | |
723 header.routing = msg.routing_id(); | |
724 header.type = msg.type(); | |
725 header.flags = msg.flags(); | |
726 header.num_fds = static_cast<int>(rewritten_msg->desc_count()); | |
727 | |
728 rewritten_msg->SetData(header, msg.payload(), msg.payload_size()); | |
729 locked_data_.to_be_received_.push(rewritten_msg); | |
730 } | |
731 | |
OLD | NEW |