OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "ipc/ipc_channel_nacl.h" | 5 #include "ipc/ipc_channel_nacl.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 #include <sys/nacl_imc_api.h> | 9 #include <sys/nacl_imc_api.h> |
10 #include <sys/nacl_syscalls.h> | 10 #include <sys/nacl_syscalls.h> |
11 #include <sys/types.h> | 11 #include <sys/types.h> |
12 | 12 |
13 #include <algorithm> | 13 #include <algorithm> |
14 | 14 |
15 #include "base/bind.h" | 15 #include "base/bind.h" |
16 #include "base/file_util.h" | 16 #include "base/file_util.h" |
17 #include "base/logging.h" | 17 #include "base/logging.h" |
18 #include "base/message_loop_proxy.h" | 18 #include "base/message_loop_proxy.h" |
19 #include "base/process_util.h" | 19 #include "base/process_util.h" |
20 #include "base/synchronization/lock.h" | 20 #include "base/synchronization/lock.h" |
21 #include "base/task_runner_util.h" | 21 #include "base/task_runner_util.h" |
22 #include "base/threading/simple_thread.h" | 22 #include "base/threading/simple_thread.h" |
23 #include "ipc/file_descriptor_set_posix.h" | 23 #include "ipc/file_descriptor_set_posix.h" |
24 #include "ipc/ipc_logging.h" | 24 #include "ipc/ipc_logging.h" |
25 | 25 |
26 namespace IPC { | 26 namespace IPC { |
27 | |
28 struct MessageContents { | |
29 std::vector<char> data; | |
30 std::vector<int> fds; | |
31 }; | |
32 | |
27 namespace { | 33 namespace { |
28 | 34 |
29 scoped_ptr<std::vector<char> > ReadDataOnReaderThread(int pipe) { | 35 bool ReadDataOnReaderThread(int pipe, MessageContents* contents) { |
30 DCHECK(pipe >= 0); | 36 DCHECK(pipe >= 0); |
37 if (pipe < 0) | |
38 return false; | |
31 | 39 |
32 if (pipe < 0) | 40 contents->data.resize(Channel::kReadBufferSize); |
33 return scoped_ptr<std::vector<char> >(); | 41 contents->fds.resize(FileDescriptorSet::kMaxDescriptorsPerMessage); |
34 | 42 |
35 scoped_ptr<std::vector<char> > buffer( | 43 NaClImcMsgIoVec iov = { &contents->data[0], contents->data.size() }; |
36 new std::vector<char>(Channel::kReadBufferSize)); | 44 NaClImcMsgHdr msg = { &iov, 1, &contents->fds[0], contents->fds.size() }; |
37 struct NaClImcMsgHdr msg = {0}; | |
38 struct NaClImcMsgIoVec iov = {&buffer->at(0), buffer->size()}; | |
39 msg.iov = &iov; | |
40 msg.iov_length = 1; | |
41 | 45 |
42 int bytes_read = imc_recvmsg(pipe, &msg, 0); | 46 int bytes_read = imc_recvmsg(pipe, &msg, 0); |
43 | 47 |
44 if (bytes_read <= 0) { | 48 if (bytes_read <= 0) { |
45 // NaClIPCAdapter::BlockingReceive returns -1 when the pipe closes (either | 49 // NaClIPCAdapter::BlockingReceive returns -1 when the pipe closes (either |
46 // due to error or for regular shutdown). | 50 // due to error or for regular shutdown). |
47 return scoped_ptr<std::vector<char> >(); | 51 return false; |
brettw
2012/07/10 05:04:07
I might feel a little better if you cleared out th
| |
48 } | 52 } |
49 DCHECK(bytes_read); | 53 DCHECK(bytes_read); |
50 buffer->resize(bytes_read); | 54 // Resize the buffers down to the number of bytes and fds we actually read. |
51 return buffer.Pass(); | 55 contents->data.resize(bytes_read); |
56 contents->fds.resize(msg.desc_length); | |
57 return true; | |
52 } | 58 } |
53 | 59 |
54 } // namespace | 60 } // namespace |
55 | 61 |
56 class Channel::ChannelImpl::ReaderThreadRunner | 62 class Channel::ChannelImpl::ReaderThreadRunner |
57 : public base::DelegateSimpleThread::Delegate { | 63 : public base::DelegateSimpleThread::Delegate { |
58 public: | 64 public: |
59 // |pipe|: A file descriptor from which we will read using imc_recvmsg. | 65 // |pipe|: A file descriptor from which we will read using imc_recvmsg. |
60 // |data_read_callback|: A callback we invoke (on the main thread) when we | 66 // |data_read_callback|: A callback we invoke (on the main thread) when we |
61 // have read data. The callback is passed a buffer of | 67 // have read data. |
62 // data that was read. | |
63 // |failure_callback|: A callback we invoke when we have a failure reading | 68 // |failure_callback|: A callback we invoke when we have a failure reading |
64 // from |pipe|. | 69 // from |pipe|. |
65 // |main_message_loop|: A proxy for the main thread, where we will invoke the | 70 // |main_message_loop|: A proxy for the main thread, where we will invoke the |
66 // above callbacks. | 71 // above callbacks. |
67 ReaderThreadRunner( | 72 ReaderThreadRunner( |
68 int pipe, | 73 int pipe, |
69 base::Callback<void (scoped_ptr<std::vector<char> >)> data_read_callback, | 74 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback, |
70 base::Callback<void ()> failure_callback, | 75 base::Callback<void ()> failure_callback, |
71 base::MessageLoopProxy* main_message_loop); | 76 scoped_refptr<base::MessageLoopProxy> main_message_loop); |
72 | 77 |
73 // DelegateSimpleThread implementation. Reads data from the pipe in a loop | 78 // DelegateSimpleThread implementation. Reads data from the pipe in a loop |
74 // until either we are told to quit or a read fails. | 79 // until either we are told to quit or a read fails. |
75 virtual void Run() OVERRIDE; | 80 virtual void Run() OVERRIDE; |
76 | 81 |
77 private: | 82 private: |
78 int pipe_; | 83 int pipe_; |
79 base::Callback<void (scoped_ptr<std::vector<char> >)> data_read_callback_; | 84 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback_; |
80 base::Callback<void ()> failure_callback_; | 85 base::Callback<void ()> failure_callback_; |
81 scoped_refptr<base::MessageLoopProxy> main_message_loop_; | 86 scoped_refptr<base::MessageLoopProxy> main_message_loop_; |
82 | 87 |
83 DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner); | 88 DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner); |
84 }; | 89 }; |
85 | 90 |
86 Channel::ChannelImpl::ReaderThreadRunner::ReaderThreadRunner( | 91 Channel::ChannelImpl::ReaderThreadRunner::ReaderThreadRunner( |
87 int pipe, | 92 int pipe, |
88 base::Callback<void (scoped_ptr<std::vector<char> >)> data_read_callback, | 93 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback, |
89 base::Callback<void ()> failure_callback, | 94 base::Callback<void ()> failure_callback, |
90 base::MessageLoopProxy* main_message_loop) | 95 scoped_refptr<base::MessageLoopProxy> main_message_loop) |
91 : pipe_(pipe), | 96 : pipe_(pipe), |
92 data_read_callback_(data_read_callback), | 97 data_read_callback_(data_read_callback), |
93 failure_callback_(failure_callback), | 98 failure_callback_(failure_callback), |
94 main_message_loop_(main_message_loop) { | 99 main_message_loop_(main_message_loop) { |
95 } | 100 } |
96 | 101 |
97 void Channel::ChannelImpl::ReaderThreadRunner::Run() { | 102 void Channel::ChannelImpl::ReaderThreadRunner::Run() { |
98 while (true) { | 103 while (true) { |
99 scoped_ptr<std::vector<char> > buffer(ReadDataOnReaderThread(pipe_)); | 104 scoped_ptr<MessageContents> msg_contents(new MessageContents); |
100 if (buffer.get()) { | 105 bool success = ReadDataOnReaderThread(pipe_, msg_contents.get()); |
106 if (success) { | |
101 main_message_loop_->PostTask(FROM_HERE, | 107 main_message_loop_->PostTask(FROM_HERE, |
102 base::Bind(data_read_callback_, base::Passed(buffer.Pass()))); | 108 base::Bind(data_read_callback_, base::Passed(msg_contents.Pass()))); |
103 } else { | 109 } else { |
104 main_message_loop_->PostTask(FROM_HERE, failure_callback_); | 110 main_message_loop_->PostTask(FROM_HERE, failure_callback_); |
105 // Because the read failed, we know we're going to quit. Don't bother | 111 // Because the read failed, we know we're going to quit. Don't bother |
106 // trying to read again. | 112 // trying to read again. |
107 return; | 113 return; |
108 } | 114 } |
109 } | 115 } |
110 } | 116 } |
111 | 117 |
112 Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle& channel_handle, | 118 Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle& channel_handle, |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
180 Logging::GetInstance()->OnSendMessage(message_ptr.get(), ""); | 186 Logging::GetInstance()->OnSendMessage(message_ptr.get(), ""); |
181 #endif // IPC_MESSAGE_LOG_ENABLED | 187 #endif // IPC_MESSAGE_LOG_ENABLED |
182 | 188 |
183 output_queue_.push_back(linked_ptr<Message>(message_ptr.release())); | 189 output_queue_.push_back(linked_ptr<Message>(message_ptr.release())); |
184 if (!waiting_connect_) | 190 if (!waiting_connect_) |
185 return ProcessOutgoingMessages(); | 191 return ProcessOutgoingMessages(); |
186 | 192 |
187 return true; | 193 return true; |
188 } | 194 } |
189 | 195 |
190 void Channel::ChannelImpl::DidRecvMsg(scoped_ptr<std::vector<char> > buffer) { | 196 void Channel::ChannelImpl::DidRecvMsg(scoped_ptr<MessageContents> contents) { |
191 // Close sets the pipe to -1. It's possible we'll get a buffer sent to us from | 197 // Close sets the pipe to -1. It's possible we'll get a buffer sent to us from |
192 // the reader thread after Close is called. If so, we ignore it. | 198 // the reader thread after Close is called. If so, we ignore it. |
193 if (pipe_ == -1) | 199 if (pipe_ == -1) |
194 return; | 200 return; |
195 | 201 |
196 read_queue_.push_back(linked_ptr<std::vector<char> >(buffer.release())); | 202 linked_ptr<std::vector<char> > data(new std::vector<char>); |
203 data->swap(contents->data); | |
204 read_queue_.push_back(data); | |
205 | |
206 input_fds_.insert(input_fds_.end(), | |
207 contents->fds.begin(), contents->fds.end()); | |
208 contents->fds.clear(); | |
197 | 209 |
198 // In POSIX, we would be told when there are bytes to read by implementing | 210 // In POSIX, we would be told when there are bytes to read by implementing |
199 // OnFileCanReadWithoutBlocking in MessageLoopForIO::Watcher. In NaCl, we | 211 // OnFileCanReadWithoutBlocking in MessageLoopForIO::Watcher. In NaCl, we |
200 // instead know at this point because the reader thread posted some data to | 212 // instead know at this point because the reader thread posted some data to |
201 // us. | 213 // us. |
202 ProcessIncomingMessages(); | 214 ProcessIncomingMessages(); |
203 } | 215 } |
204 | 216 |
205 void Channel::ChannelImpl::ReadDidFail() { | 217 void Channel::ChannelImpl::ReadDidFail() { |
206 Close(); | 218 Close(); |
(...skipping 26 matching lines...) Expand all Loading... | |
233 | 245 |
234 if (pipe_ == -1) | 246 if (pipe_ == -1) |
235 return false; | 247 return false; |
236 | 248 |
237 // Write out all the messages. The trusted implementation is guaranteed to not | 249 // Write out all the messages. The trusted implementation is guaranteed to not |
238 // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg. | 250 // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg. |
239 while (!output_queue_.empty()) { | 251 while (!output_queue_.empty()) { |
240 linked_ptr<Message> msg = output_queue_.front(); | 252 linked_ptr<Message> msg = output_queue_.front(); |
241 output_queue_.pop_front(); | 253 output_queue_.pop_front(); |
242 | 254 |
243 struct NaClImcMsgHdr msgh = {0}; | 255 int fds[FileDescriptorSet::kMaxDescriptorsPerMessage]; |
244 struct NaClImcMsgIoVec iov = {const_cast<void*>(msg->data()), msg->size()}; | 256 const int num_fds = msg->file_descriptor_set()->size(); |
245 msgh.iov = &iov; | 257 DCHECK(num_fds < FileDescriptorSet::kMaxDescriptorsPerMessage); |
Mark Seaborn
2012/07/10 15:26:44
Nit: shouldn't this be '<='?
| |
246 msgh.iov_length = 1; | 258 msg->file_descriptor_set()->GetDescriptors(fds); |
259 | |
260 NaClImcMsgIoVec iov = { const_cast<void*>(msg->data()), msg->size() }; | |
261 NaClImcMsgHdr msgh = { &iov, 1, fds, num_fds }; | |
247 ssize_t bytes_written = imc_sendmsg(pipe_, &msgh, 0); | 262 ssize_t bytes_written = imc_sendmsg(pipe_, &msgh, 0); |
248 | 263 |
264 DCHECK(bytes_written); // The trusted side shouldn't return 0. | |
249 if (bytes_written < 0) { | 265 if (bytes_written < 0) { |
250 // The trusted side should only ever give us an error of EPIPE. We | 266 // The trusted side should only ever give us an error of EPIPE. We |
251 // should never be interrupted, nor should we get EAGAIN. | 267 // should never be interrupted, nor should we get EAGAIN. |
252 DCHECK(errno == EPIPE); | 268 DCHECK(errno == EPIPE); |
253 Close(); | 269 Close(); |
254 PLOG(ERROR) << "pipe_ error on " | 270 PLOG(ERROR) << "pipe_ error on " |
255 << pipe_ | 271 << pipe_ |
256 << " Currently writing message of size: " | 272 << " Currently writing message of size: " |
257 << msg->size(); | 273 << msg->size(); |
258 return false; | 274 return false; |
275 } else { | |
276 msg->file_descriptor_set()->CommitAll(); | |
259 } | 277 } |
260 | 278 |
261 // Message sent OK! | 279 // Message sent OK! |
262 DVLOG(2) << "sent message @" << msg.get() << " with type " << msg->type() | 280 DVLOG(2) << "sent message @" << msg.get() << " with type " << msg->type() |
263 << " on fd " << pipe_; | 281 << " on fd " << pipe_; |
264 } | 282 } |
265 return true; | 283 return true; |
266 } | 284 } |
267 | 285 |
268 Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( | 286 Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( |
(...skipping 21 matching lines...) Expand all Loading... | |
290 std::copy(vec->begin(), vec->begin() + bytes_to_read, | 308 std::copy(vec->begin(), vec->begin() + bytes_to_read, |
291 buffer + *bytes_read); | 309 buffer + *bytes_read); |
292 vec->erase(vec->begin(), vec->begin() + bytes_to_read); | 310 vec->erase(vec->begin(), vec->begin() + bytes_to_read); |
293 *bytes_read += bytes_to_read; | 311 *bytes_read += bytes_to_read; |
294 } | 312 } |
295 } | 313 } |
296 return READ_SUCCEEDED; | 314 return READ_SUCCEEDED; |
297 } | 315 } |
298 | 316 |
299 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { | 317 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { |
318 uint16 header_fds = msg->header()->num_fds; | |
319 CHECK(header_fds == input_fds_.size()); | |
320 if (header_fds == 0) | |
321 return true; // Nothing to do. | |
322 | |
323 // The shenaniganery below with &foo.front() requires input_fds_ to have | |
324 // contiguous underlying storage (such as a simple array or a std::vector). | |
325 // This is why the header warns not to make input_fds_ a deque<>. | |
326 msg->file_descriptor_set()->SetDescriptors(&input_fds_.front(), | |
327 header_fds); | |
328 input_fds_.clear(); | |
300 return true; | 329 return true; |
301 } | 330 } |
302 | 331 |
303 bool Channel::ChannelImpl::DidEmptyInputBuffers() { | 332 bool Channel::ChannelImpl::DidEmptyInputBuffers() { |
304 return true; | 333 // When the input data buffer is empty, the fds should be too. |
334 return input_fds_.empty(); | |
305 } | 335 } |
306 | 336 |
307 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { | 337 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { |
308 // The trusted side IPC::Channel should handle the "hello" handshake; we | 338 // The trusted side IPC::Channel should handle the "hello" handshake; we |
309 // should not receive the "Hello" message. | 339 // should not receive the "Hello" message. |
310 NOTREACHED(); | 340 NOTREACHED(); |
311 } | 341 } |
312 | 342 |
313 //------------------------------------------------------------------------------ | 343 //------------------------------------------------------------------------------ |
314 // Channel's methods simply call through to ChannelImpl. | 344 // Channel's methods simply call through to ChannelImpl. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
350 // A random name is sufficient validation on posix systems, so we don't need | 380 // A random name is sufficient validation on posix systems, so we don't need |
351 // an additional shared secret. | 381 // an additional shared secret. |
352 std::string id = prefix; | 382 std::string id = prefix; |
353 if (!id.empty()) | 383 if (!id.empty()) |
354 id.append("."); | 384 id.append("."); |
355 | 385 |
356 return id.append(GenerateUniqueRandomChannelID()); | 386 return id.append(GenerateUniqueRandomChannelID()); |
357 } | 387 } |
358 | 388 |
359 } // namespace IPC | 389 } // namespace IPC |
OLD | NEW |