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