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.
5 #include "ipc/ipc_channel_nacl.h"
10 #include <sys/types.h>
14 #include "base/bind.h"
15 #include "base/logging.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/synchronization/lock.h"
18 #include "base/task_runner_util.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "base/threading/simple_thread.h"
21 #include "ipc/ipc_listener.h"
22 #include "ipc/ipc_logging.h"
23 #include "ipc/ipc_message_attachment_set.h"
24 #include "native_client/src/public/imc_syscalls.h"
25 #include "native_client/src/public/imc_types.h"
29 struct MessageContents
{
30 std::vector
<char> data
;
36 bool ReadDataOnReaderThread(int pipe
, MessageContents
* contents
) {
41 contents
->data
.resize(Channel::kReadBufferSize
);
42 contents
->fds
.resize(NACL_ABI_IMC_DESC_MAX
);
44 NaClAbiNaClImcMsgIoVec iov
= { &contents
->data
[0], contents
->data
.size() };
45 NaClAbiNaClImcMsgHdr msg
= {
46 &iov
, 1, &contents
->fds
[0], contents
->fds
.size()
49 int bytes_read
= imc_recvmsg(pipe
, &msg
, 0);
51 if (bytes_read
<= 0) {
52 // NaClIPCAdapter::BlockingReceive returns -1 when the pipe closes (either
53 // due to error or for regular shutdown).
54 contents
->data
.clear();
55 contents
->fds
.clear();
59 // Resize the buffers down to the number of bytes and fds we actually read.
60 contents
->data
.resize(bytes_read
);
61 contents
->fds
.resize(msg
.desc_length
);
67 class ChannelNacl::ReaderThreadRunner
68 : public base::DelegateSimpleThread::Delegate
{
70 // |pipe|: A file descriptor from which we will read using imc_recvmsg.
71 // |data_read_callback|: A callback we invoke (on the main thread) when we
73 // |failure_callback|: A callback we invoke when we have a failure reading
75 // |main_message_loop|: A proxy for the main thread, where we will invoke the
79 base::Callback
<void(scoped_ptr
<MessageContents
>)> data_read_callback
,
80 base::Callback
<void()> failure_callback
,
81 scoped_refptr
<base::SingleThreadTaskRunner
> main_task_runner
);
83 // DelegateSimpleThread implementation. Reads data from the pipe in a loop
84 // until either we are told to quit or a read fails.
89 base::Callback
<void (scoped_ptr
<MessageContents
>)> data_read_callback_
;
90 base::Callback
<void ()> failure_callback_
;
91 scoped_refptr
<base::SingleThreadTaskRunner
> main_task_runner_
;
93 DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner
);
96 ChannelNacl::ReaderThreadRunner::ReaderThreadRunner(
98 base::Callback
<void(scoped_ptr
<MessageContents
>)> data_read_callback
,
99 base::Callback
<void()> failure_callback
,
100 scoped_refptr
<base::SingleThreadTaskRunner
> main_task_runner
)
102 data_read_callback_(data_read_callback
),
103 failure_callback_(failure_callback
),
104 main_task_runner_(main_task_runner
) {
107 void ChannelNacl::ReaderThreadRunner::Run() {
109 scoped_ptr
<MessageContents
> msg_contents(new MessageContents
);
110 bool success
= ReadDataOnReaderThread(pipe_
, msg_contents
.get());
112 main_task_runner_
->PostTask(
114 base::Bind(data_read_callback_
, base::Passed(&msg_contents
)));
116 main_task_runner_
->PostTask(FROM_HERE
, failure_callback_
);
117 // Because the read failed, we know we're going to quit. Don't bother
118 // trying to read again.
124 ChannelNacl::ChannelNacl(const IPC::ChannelHandle
& channel_handle
,
127 AttachmentBroker
* broker
)
128 : ChannelReader(listener
),
130 waiting_connect_(true),
132 pipe_name_(channel_handle
.name
),
133 weak_ptr_factory_(this),
135 if (!CreatePipe(channel_handle
)) {
136 // The pipe may have been closed already.
137 const char *modestr
= (mode_
& MODE_SERVER_FLAG
) ? "server" : "client";
138 LOG(WARNING
) << "Unable to create pipe named \"" << channel_handle
.name
139 << "\" in " << modestr
<< " mode";
143 ChannelNacl::~ChannelNacl() {
147 base::ProcessId
ChannelNacl::GetPeerPID() const {
148 // This shouldn't actually get used in the untrusted side of the proxy, and we
149 // don't have the real pid anyway.
153 base::ProcessId
ChannelNacl::GetSelfPID() const {
157 bool ChannelNacl::Connect() {
159 DLOG(WARNING
) << "Channel creation failed: " << pipe_name_
;
163 // Note that Connect is called on the "Channel" thread (i.e., the same thread
164 // where Channel::Send will be called, and the same thread that should receive
165 // messages). The constructor might be invoked on another thread (see
166 // ChannelProxy for an example of that). Therefore, we must wait until Connect
167 // is called to decide which SingleThreadTaskRunner to pass to
168 // ReaderThreadRunner.
169 reader_thread_runner_
.reset(new ReaderThreadRunner(
171 base::Bind(&ChannelNacl::DidRecvMsg
, weak_ptr_factory_
.GetWeakPtr()),
172 base::Bind(&ChannelNacl::ReadDidFail
, weak_ptr_factory_
.GetWeakPtr()),
173 base::ThreadTaskRunnerHandle::Get()));
174 reader_thread_
.reset(
175 new base::DelegateSimpleThread(reader_thread_runner_
.get(),
176 "ipc_channel_nacl reader thread"));
177 reader_thread_
->Start();
178 waiting_connect_
= false;
179 // If there were any messages queued before connection, send them.
180 ProcessOutgoingMessages();
181 base::ThreadTaskRunnerHandle::Get()->PostTask(
182 FROM_HERE
, base::Bind(&ChannelNacl::CallOnChannelConnected
,
183 weak_ptr_factory_
.GetWeakPtr()));
188 void ChannelNacl::Close() {
189 // For now, we assume that at shutdown, the reader thread will be woken with
190 // a failure (see NaClIPCAdapter::BlockingRead and CloseChannel). Or... we
191 // might simply be killed with no chance to clean up anyway :-).
192 // If untrusted code tries to close the channel prior to shutdown, it's likely
194 // TODO(dmichael): Can we do anything smarter here to make sure the reader
195 // thread wakes up and quits?
196 reader_thread_
->Join();
199 reader_thread_runner_
.reset();
200 reader_thread_
.reset();
202 output_queue_
.clear();
205 bool ChannelNacl::Send(Message
* message
) {
206 DCHECK(!message
->HasAttachments());
207 DVLOG(2) << "sending message @" << message
<< " on channel @" << this
208 << " with type " << message
->type();
209 scoped_ptr
<Message
> message_ptr(message
);
211 #ifdef IPC_MESSAGE_LOG_ENABLED
212 Logging::GetInstance()->OnSendMessage(message_ptr
.get(), "");
213 #endif // IPC_MESSAGE_LOG_ENABLED
215 TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"),
217 message
->header()->flags
,
218 TRACE_EVENT_FLAG_FLOW_OUT
);
219 output_queue_
.push_back(linked_ptr
<Message
>(message_ptr
.release()));
220 if (!waiting_connect_
)
221 return ProcessOutgoingMessages();
226 AttachmentBroker
* ChannelNacl::GetAttachmentBroker() {
230 void ChannelNacl::DidRecvMsg(scoped_ptr
<MessageContents
> contents
) {
231 // Close sets the pipe to -1. It's possible we'll get a buffer sent to us from
232 // the reader thread after Close is called. If so, we ignore it.
236 linked_ptr
<std::vector
<char> > data(new std::vector
<char>);
237 data
->swap(contents
->data
);
238 read_queue_
.push_back(data
);
240 input_fds_
.insert(input_fds_
.end(),
241 contents
->fds
.begin(), contents
->fds
.end());
242 contents
->fds
.clear();
244 // In POSIX, we would be told when there are bytes to read by implementing
245 // OnFileCanReadWithoutBlocking in MessageLoopForIO::Watcher. In NaCl, we
246 // instead know at this point because the reader thread posted some data to
248 ProcessIncomingMessages();
251 void ChannelNacl::ReadDidFail() {
255 bool ChannelNacl::CreatePipe(
256 const IPC::ChannelHandle
& channel_handle
) {
259 // There's one possible case in NaCl:
260 // 1) It's a channel wrapping a pipe that is given to us.
261 // We don't support these:
262 // 2) It's for a named channel.
263 // 3) It's for a client that we implement ourself.
264 // 4) It's the initial IPC channel.
266 if (channel_handle
.socket
.fd
== -1) {
270 pipe_
= channel_handle
.socket
.fd
;
274 bool ChannelNacl::ProcessOutgoingMessages() {
275 DCHECK(!waiting_connect_
); // Why are we trying to send messages if there's
277 if (output_queue_
.empty())
283 // Write out all the messages. The trusted implementation is guaranteed to not
284 // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg.
285 while (!output_queue_
.empty()) {
286 linked_ptr
<Message
> msg
= output_queue_
.front();
287 output_queue_
.pop_front();
289 int fds
[MessageAttachmentSet::kMaxDescriptorsPerMessage
];
290 const size_t num_fds
= msg
->attachment_set()->size();
291 DCHECK(num_fds
<= MessageAttachmentSet::kMaxDescriptorsPerMessage
);
292 msg
->attachment_set()->PeekDescriptors(fds
);
294 NaClAbiNaClImcMsgIoVec iov
= {
295 const_cast<void*>(msg
->data()), msg
->size()
297 NaClAbiNaClImcMsgHdr msgh
= { &iov
, 1, fds
, num_fds
};
298 ssize_t bytes_written
= imc_sendmsg(pipe_
, &msgh
, 0);
300 DCHECK(bytes_written
); // The trusted side shouldn't return 0.
301 if (bytes_written
< 0) {
302 // The trusted side should only ever give us an error of EPIPE. We
303 // should never be interrupted, nor should we get EAGAIN.
304 DCHECK(errno
== EPIPE
);
306 PLOG(ERROR
) << "pipe_ error on "
308 << " Currently writing message of size: "
312 msg
->attachment_set()->CommitAll();
316 DVLOG(2) << "sent message @" << msg
.get() << " with type " << msg
->type()
317 << " on fd " << pipe_
;
322 void ChannelNacl::CallOnChannelConnected() {
323 listener()->OnChannelConnected(GetPeerPID());
326 ChannelNacl::ReadState
ChannelNacl::ReadData(
333 if (read_queue_
.empty())
335 while (!read_queue_
.empty() && *bytes_read
< buffer_len
) {
336 linked_ptr
<std::vector
<char> > vec(read_queue_
.front());
337 size_t bytes_to_read
= buffer_len
- *bytes_read
;
338 if (vec
->size() <= bytes_to_read
) {
339 // We can read and discard the entire vector.
340 std::copy(vec
->begin(), vec
->end(), buffer
+ *bytes_read
);
341 *bytes_read
+= vec
->size();
342 read_queue_
.pop_front();
344 // Read all the bytes we can and discard them from the front of the
345 // vector. (This can be slowish, since erase has to move the back of the
346 // vector to the front, but it's hopefully a temporary hack and it keeps
348 std::copy(vec
->begin(), vec
->begin() + bytes_to_read
,
349 buffer
+ *bytes_read
);
350 vec
->erase(vec
->begin(), vec
->begin() + bytes_to_read
);
351 *bytes_read
+= bytes_to_read
;
354 return READ_SUCCEEDED
;
357 bool ChannelNacl::ShouldDispatchInputMessage(Message
* msg
) {
361 bool ChannelNacl::GetNonBrokeredAttachments(Message
* msg
) {
362 uint16_t header_fds
= msg
->header()->num_fds
;
363 CHECK(header_fds
== input_fds_
.size());
365 return true; // Nothing to do.
367 // The shenaniganery below with &foo.front() requires input_fds_ to have
368 // contiguous underlying storage (such as a simple array or a std::vector).
369 // This is why the header warns not to make input_fds_ a deque<>.
370 msg
->attachment_set()->AddDescriptorsToOwn(&input_fds_
.front(), header_fds
);
375 bool ChannelNacl::DidEmptyInputBuffers() {
376 // When the input data buffer is empty, the fds should be too.
377 return input_fds_
.empty();
380 void ChannelNacl::HandleInternalMessage(const Message
& msg
) {
381 // The trusted side IPC::Channel should handle the "hello" handshake; we
382 // should not receive the "Hello" message.
386 base::ProcessId
ChannelNacl::GetSenderPID() {
387 // The untrusted side of the IPC::Channel should never have to worry about
388 // sender's process id.
389 return base::kNullProcessId
;
392 bool ChannelNacl::IsAttachmentBrokerEndpoint() {
393 return is_attachment_broker_endpoint();
399 scoped_ptr
<Channel
> Channel::Create(const IPC::ChannelHandle
& channel_handle
,
402 AttachmentBroker
* broker
) {
403 return scoped_ptr
<Channel
>(
404 new ChannelNacl(channel_handle
, mode
, listener
, broker
));