Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(630)

Side by Side Diff: ipc/ipc_channel_nacl.cc

Issue 10750005: PPAPI/NaCl: Support Handle passing in ipc_channel_nacl (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add a DCHECK for number of FDs Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ipc/ipc_channel_nacl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « ipc/ipc_channel_nacl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698