Password manager internals page: Rephrase the page explanation
[chromium-blink-merge.git] / ipc / ipc_channel_nacl.cc
blob0928ba633057a48cde02aacdb6123b4aee840bd6
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"
7 #include <errno.h>
8 #include <stddef.h>
9 #include <sys/types.h>
11 #include <algorithm>
13 #include "base/bind.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/synchronization/lock.h"
17 #include "base/task_runner_util.h"
18 #include "base/threading/simple_thread.h"
19 #include "ipc/file_descriptor_set_posix.h"
20 #include "ipc/ipc_listener.h"
21 #include "ipc/ipc_logging.h"
22 #include "native_client/src/public/imc_syscalls.h"
23 #include "native_client/src/public/imc_types.h"
25 namespace IPC {
27 struct MessageContents {
28 std::vector<char> data;
29 std::vector<int> fds;
32 namespace {
34 bool ReadDataOnReaderThread(int pipe, MessageContents* contents) {
35 DCHECK(pipe >= 0);
36 if (pipe < 0)
37 return false;
39 contents->data.resize(Channel::kReadBufferSize);
40 contents->fds.resize(FileDescriptorSet::kMaxDescriptorsPerMessage);
42 NaClAbiNaClImcMsgIoVec iov = { &contents->data[0], contents->data.size() };
43 NaClAbiNaClImcMsgHdr msg = {
44 &iov, 1, &contents->fds[0], contents->fds.size()
47 int bytes_read = imc_recvmsg(pipe, &msg, 0);
49 if (bytes_read <= 0) {
50 // NaClIPCAdapter::BlockingReceive returns -1 when the pipe closes (either
51 // due to error or for regular shutdown).
52 contents->data.clear();
53 contents->fds.clear();
54 return false;
56 DCHECK(bytes_read);
57 // Resize the buffers down to the number of bytes and fds we actually read.
58 contents->data.resize(bytes_read);
59 contents->fds.resize(msg.desc_length);
60 return true;
63 } // namespace
65 class ChannelNacl::ReaderThreadRunner
66 : public base::DelegateSimpleThread::Delegate {
67 public:
68 // |pipe|: A file descriptor from which we will read using imc_recvmsg.
69 // |data_read_callback|: A callback we invoke (on the main thread) when we
70 // have read data.
71 // |failure_callback|: A callback we invoke when we have a failure reading
72 // from |pipe|.
73 // |main_message_loop|: A proxy for the main thread, where we will invoke the
74 // above callbacks.
75 ReaderThreadRunner(
76 int pipe,
77 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback,
78 base::Callback<void ()> failure_callback,
79 scoped_refptr<base::MessageLoopProxy> main_message_loop);
81 // DelegateSimpleThread implementation. Reads data from the pipe in a loop
82 // until either we are told to quit or a read fails.
83 virtual void Run() OVERRIDE;
85 private:
86 int pipe_;
87 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback_;
88 base::Callback<void ()> failure_callback_;
89 scoped_refptr<base::MessageLoopProxy> main_message_loop_;
91 DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner);
94 ChannelNacl::ReaderThreadRunner::ReaderThreadRunner(
95 int pipe,
96 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback,
97 base::Callback<void ()> failure_callback,
98 scoped_refptr<base::MessageLoopProxy> main_message_loop)
99 : pipe_(pipe),
100 data_read_callback_(data_read_callback),
101 failure_callback_(failure_callback),
102 main_message_loop_(main_message_loop) {
105 void ChannelNacl::ReaderThreadRunner::Run() {
106 while (true) {
107 scoped_ptr<MessageContents> msg_contents(new MessageContents);
108 bool success = ReadDataOnReaderThread(pipe_, msg_contents.get());
109 if (success) {
110 main_message_loop_->PostTask(FROM_HERE,
111 base::Bind(data_read_callback_, base::Passed(&msg_contents)));
112 } else {
113 main_message_loop_->PostTask(FROM_HERE, failure_callback_);
114 // Because the read failed, we know we're going to quit. Don't bother
115 // trying to read again.
116 return;
121 ChannelNacl::ChannelNacl(const IPC::ChannelHandle& channel_handle,
122 Mode mode,
123 Listener* listener)
124 : ChannelReader(listener),
125 mode_(mode),
126 waiting_connect_(true),
127 pipe_(-1),
128 pipe_name_(channel_handle.name),
129 weak_ptr_factory_(this) {
130 if (!CreatePipe(channel_handle)) {
131 // The pipe may have been closed already.
132 const char *modestr = (mode_ & MODE_SERVER_FLAG) ? "server" : "client";
133 LOG(WARNING) << "Unable to create pipe named \"" << channel_handle.name
134 << "\" in " << modestr << " mode";
138 ChannelNacl::~ChannelNacl() {
139 Close();
142 base::ProcessId ChannelNacl::GetPeerPID() const {
143 // This shouldn't actually get used in the untrusted side of the proxy, and we
144 // don't have the real pid anyway.
145 return -1;
148 bool ChannelNacl::Connect() {
149 if (pipe_ == -1) {
150 DLOG(WARNING) << "Channel creation failed: " << pipe_name_;
151 return false;
154 // Note that Connect is called on the "Channel" thread (i.e., the same thread
155 // where Channel::Send will be called, and the same thread that should receive
156 // messages). The constructor might be invoked on another thread (see
157 // ChannelProxy for an example of that). Therefore, we must wait until Connect
158 // is called to decide which MessageLoopProxy to pass to ReaderThreadRunner.
159 reader_thread_runner_.reset(
160 new ReaderThreadRunner(
161 pipe_,
162 base::Bind(&ChannelNacl::DidRecvMsg,
163 weak_ptr_factory_.GetWeakPtr()),
164 base::Bind(&ChannelNacl::ReadDidFail,
165 weak_ptr_factory_.GetWeakPtr()),
166 base::MessageLoopProxy::current()));
167 reader_thread_.reset(
168 new base::DelegateSimpleThread(reader_thread_runner_.get(),
169 "ipc_channel_nacl reader thread"));
170 reader_thread_->Start();
171 waiting_connect_ = false;
172 // If there were any messages queued before connection, send them.
173 ProcessOutgoingMessages();
174 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
175 base::Bind(&ChannelNacl::CallOnChannelConnected,
176 weak_ptr_factory_.GetWeakPtr()));
178 return true;
181 void ChannelNacl::Close() {
182 // For now, we assume that at shutdown, the reader thread will be woken with
183 // a failure (see NaClIPCAdapter::BlockingRead and CloseChannel). Or... we
184 // might simply be killed with no chance to clean up anyway :-).
185 // If untrusted code tries to close the channel prior to shutdown, it's likely
186 // to hang.
187 // TODO(dmichael): Can we do anything smarter here to make sure the reader
188 // thread wakes up and quits?
189 reader_thread_->Join();
190 close(pipe_);
191 pipe_ = -1;
192 reader_thread_runner_.reset();
193 reader_thread_.reset();
194 read_queue_.clear();
195 output_queue_.clear();
198 bool ChannelNacl::Send(Message* message) {
199 DVLOG(2) << "sending message @" << message << " on channel @" << this
200 << " with type " << message->type();
201 scoped_ptr<Message> message_ptr(message);
203 #ifdef IPC_MESSAGE_LOG_ENABLED
204 Logging::GetInstance()->OnSendMessage(message_ptr.get(), "");
205 #endif // IPC_MESSAGE_LOG_ENABLED
207 message->TraceMessageBegin();
208 output_queue_.push_back(linked_ptr<Message>(message_ptr.release()));
209 if (!waiting_connect_)
210 return ProcessOutgoingMessages();
212 return true;
215 void ChannelNacl::DidRecvMsg(scoped_ptr<MessageContents> contents) {
216 // Close sets the pipe to -1. It's possible we'll get a buffer sent to us from
217 // the reader thread after Close is called. If so, we ignore it.
218 if (pipe_ == -1)
219 return;
221 linked_ptr<std::vector<char> > data(new std::vector<char>);
222 data->swap(contents->data);
223 read_queue_.push_back(data);
225 input_fds_.insert(input_fds_.end(),
226 contents->fds.begin(), contents->fds.end());
227 contents->fds.clear();
229 // In POSIX, we would be told when there are bytes to read by implementing
230 // OnFileCanReadWithoutBlocking in MessageLoopForIO::Watcher. In NaCl, we
231 // instead know at this point because the reader thread posted some data to
232 // us.
233 ProcessIncomingMessages();
236 void ChannelNacl::ReadDidFail() {
237 Close();
240 bool ChannelNacl::CreatePipe(
241 const IPC::ChannelHandle& channel_handle) {
242 DCHECK(pipe_ == -1);
244 // There's one possible case in NaCl:
245 // 1) It's a channel wrapping a pipe that is given to us.
246 // We don't support these:
247 // 2) It's for a named channel.
248 // 3) It's for a client that we implement ourself.
249 // 4) It's the initial IPC channel.
251 if (channel_handle.socket.fd == -1) {
252 NOTIMPLEMENTED();
253 return false;
255 pipe_ = channel_handle.socket.fd;
256 return true;
259 bool ChannelNacl::ProcessOutgoingMessages() {
260 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
261 // no connection?
262 if (output_queue_.empty())
263 return true;
265 if (pipe_ == -1)
266 return false;
268 // Write out all the messages. The trusted implementation is guaranteed to not
269 // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg.
270 while (!output_queue_.empty()) {
271 linked_ptr<Message> msg = output_queue_.front();
272 output_queue_.pop_front();
274 int fds[FileDescriptorSet::kMaxDescriptorsPerMessage];
275 const size_t num_fds = msg->file_descriptor_set()->size();
276 DCHECK(num_fds <= FileDescriptorSet::kMaxDescriptorsPerMessage);
277 msg->file_descriptor_set()->GetDescriptors(fds);
279 NaClAbiNaClImcMsgIoVec iov = {
280 const_cast<void*>(msg->data()), msg->size()
282 NaClAbiNaClImcMsgHdr msgh = { &iov, 1, fds, num_fds };
283 ssize_t bytes_written = imc_sendmsg(pipe_, &msgh, 0);
285 DCHECK(bytes_written); // The trusted side shouldn't return 0.
286 if (bytes_written < 0) {
287 // The trusted side should only ever give us an error of EPIPE. We
288 // should never be interrupted, nor should we get EAGAIN.
289 DCHECK(errno == EPIPE);
290 Close();
291 PLOG(ERROR) << "pipe_ error on "
292 << pipe_
293 << " Currently writing message of size: "
294 << msg->size();
295 return false;
296 } else {
297 msg->file_descriptor_set()->CommitAll();
300 // Message sent OK!
301 DVLOG(2) << "sent message @" << msg.get() << " with type " << msg->type()
302 << " on fd " << pipe_;
304 return true;
307 void ChannelNacl::CallOnChannelConnected() {
308 listener()->OnChannelConnected(GetPeerPID());
311 ChannelNacl::ReadState ChannelNacl::ReadData(
312 char* buffer,
313 int buffer_len,
314 int* bytes_read) {
315 *bytes_read = 0;
316 if (pipe_ == -1)
317 return READ_FAILED;
318 if (read_queue_.empty())
319 return READ_PENDING;
320 while (!read_queue_.empty() && *bytes_read < buffer_len) {
321 linked_ptr<std::vector<char> > vec(read_queue_.front());
322 size_t bytes_to_read = buffer_len - *bytes_read;
323 if (vec->size() <= bytes_to_read) {
324 // We can read and discard the entire vector.
325 std::copy(vec->begin(), vec->end(), buffer + *bytes_read);
326 *bytes_read += vec->size();
327 read_queue_.pop_front();
328 } else {
329 // Read all the bytes we can and discard them from the front of the
330 // vector. (This can be slowish, since erase has to move the back of the
331 // vector to the front, but it's hopefully a temporary hack and it keeps
332 // the code simple).
333 std::copy(vec->begin(), vec->begin() + bytes_to_read,
334 buffer + *bytes_read);
335 vec->erase(vec->begin(), vec->begin() + bytes_to_read);
336 *bytes_read += bytes_to_read;
339 return READ_SUCCEEDED;
342 bool ChannelNacl::WillDispatchInputMessage(Message* msg) {
343 uint16 header_fds = msg->header()->num_fds;
344 CHECK(header_fds == input_fds_.size());
345 if (header_fds == 0)
346 return true; // Nothing to do.
348 // The shenaniganery below with &foo.front() requires input_fds_ to have
349 // contiguous underlying storage (such as a simple array or a std::vector).
350 // This is why the header warns not to make input_fds_ a deque<>.
351 msg->file_descriptor_set()->SetDescriptors(&input_fds_.front(),
352 header_fds);
353 input_fds_.clear();
354 return true;
357 bool ChannelNacl::DidEmptyInputBuffers() {
358 // When the input data buffer is empty, the fds should be too.
359 return input_fds_.empty();
362 void ChannelNacl::HandleInternalMessage(const Message& msg) {
363 // The trusted side IPC::Channel should handle the "hello" handshake; we
364 // should not receive the "Hello" message.
365 NOTREACHED();
368 // Channel's methods
370 // static
371 scoped_ptr<Channel> Channel::Create(
372 const IPC::ChannelHandle &channel_handle, Mode mode, Listener* listener) {
373 return scoped_ptr<Channel>(
374 new ChannelNacl(channel_handle, mode, listener));
377 } // namespace IPC