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

Side by Side Diff: ipc/ipc_channel_nacl.cc

Issue 10174048: PPAPI/NaCl: Speculative implementation for ipc_channel_nacl.cc (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge, fix link errors Created 8 years, 6 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') | ipc/ipc_channel_proxy.h » ('j') | 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>
8 #include <stddef.h>
9 #include <sys/nacl_imc_api.h>
10 #include <sys/nacl_syscalls.h>
11 #include <sys/types.h>
12
13 #include <algorithm>
14
15 #include "base/bind.h"
7 #include "base/file_util.h" 16 #include "base/file_util.h"
8 #include "base/logging.h" 17 #include "base/logging.h"
9 18 #include "base/message_loop_proxy.h"
10 // This file is currently a stub to get us linking. 19 #include "base/process_util.h"
11 // TODO(brettw) implement this. 20 #include "base/synchronization/lock.h"
21 #include "base/task_runner_util.h"
22 #include "base/threading/simple_thread.h"
23 #include "ipc/file_descriptor_set_posix.h"
24 #include "ipc/ipc_logging.h"
12 25
13 namespace IPC { 26 namespace IPC {
27 namespace {
28
29 scoped_ptr<std::vector<char> > ReadDataOnReaderThread(int pipe) {
30 DCHECK(pipe >= 0);
31
32 if (pipe < 0)
33 return scoped_ptr<std::vector<char> >();
34
35 scoped_ptr<std::vector<char> > buffer(
36 new std::vector<char>(Channel::kReadBufferSize));
37 struct NaClImcMsgHdr msg = {0};
38 struct NaClImcMsgIoVec iov = {&buffer->at(0), buffer->size()};
39 msg.iov = &iov;
40 msg.iov_length = 1;
41
42 int bytes_read = imc_recvmsg(pipe, &msg, 0);
43
44 if (bytes_read <= 0) {
45 // NaClIPCAdapter::BlockingReceive returns -1 when the pipe closes (either
46 // due to error or for regular shutdown).
47 return scoped_ptr<std::vector<char> >();
48 }
49 DCHECK(bytes_read);
50 buffer->resize(bytes_read);
51 return buffer.Pass();
52 }
53
54 } // namespace
55
56 class Channel::ChannelImpl::ReaderThreadRunner
57 : public base::DelegateSimpleThread::Delegate {
58 public:
59 // |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
61 // have read data. The callback is passed a buffer of
62 // data that was read.
63 // |failure_callback|: A callback we invoke when we have a failure reading
64 // from |pipe|.
65 // |main_message_loop|: A proxy for the main thread, where we will invoke the
66 // above callbacks.
67 ReaderThreadRunner(
68 int pipe,
69 base::Callback<void (scoped_ptr<std::vector<char> >)> data_read_callback,
70 base::Callback<void ()> failure_callback,
71 base::MessageLoopProxy* main_message_loop);
72
73 // DelegateSimpleThread implementation. Reads data from the pipe in a loop
74 // until either we are told to quit or a read fails.
75 virtual void Run() OVERRIDE;
76
77 private:
78 int pipe_;
79 base::Callback<void (scoped_ptr<std::vector<char> >)> data_read_callback_;
80 base::Callback<void ()> failure_callback_;
81 base::MessageLoopProxy* main_message_loop_;
82
83 DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner);
84 };
85
86 Channel::ChannelImpl::ReaderThreadRunner::ReaderThreadRunner(
87 int pipe,
88 base::Callback<void (scoped_ptr<std::vector<char> >)> data_read_callback,
89 base::Callback<void ()> failure_callback,
90 base::MessageLoopProxy* main_message_loop)
91 : pipe_(pipe),
92 data_read_callback_(data_read_callback),
93 failure_callback_(failure_callback),
94 main_message_loop_(main_message_loop) {
95 }
96
97 void Channel::ChannelImpl::ReaderThreadRunner::Run() {
98 while (true) {
99 scoped_ptr<std::vector<char> > buffer(ReadDataOnReaderThread(pipe_));
100 if (buffer.get()) {
101 main_message_loop_->PostTask(FROM_HERE,
102 base::Bind(data_read_callback_, base::Passed(buffer.Pass())));
103 } else {
104 main_message_loop_->PostTask(FROM_HERE, failure_callback_);
105 // Because the read failed, we know we're going to quit. Don't bother
106 // trying to read again.
107 return;
108 }
109 }
110 }
14 111
15 Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle& channel_handle, 112 Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle& channel_handle,
16 Mode mode, 113 Mode mode,
17 Listener* listener) 114 Listener* listener)
18 : ChannelReader(listener) { 115 : ChannelReader(listener),
116 mode_(mode),
117 waiting_connect_(true),
118 pipe_(-1),
119 pipe_name_(channel_handle.name),
120 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
121 if (!CreatePipe(channel_handle)) {
122 // The pipe may have been closed already.
123 const char *modestr = (mode_ & MODE_SERVER_FLAG) ? "server" : "client";
124 LOG(WARNING) << "Unable to create pipe named \"" << channel_handle.name
125 << "\" in " << modestr << " mode";
126 }
127 reader_thread_runner_.reset(
128 new ReaderThreadRunner(
129 pipe_,
130 base::Bind(&Channel::ChannelImpl::DidRecvMsg,
131 weak_ptr_factory_.GetWeakPtr()),
132 base::Bind(&Channel::ChannelImpl::ReadDidFail,
133 weak_ptr_factory_.GetWeakPtr()),
134 base::MessageLoopProxy::current()));
135 reader_thread_.reset(
136 new base::DelegateSimpleThread(reader_thread_runner_.get(),
137 "ipc_channel_nacl reader thread"));
19 } 138 }
20 139
21 Channel::ChannelImpl::~ChannelImpl() { 140 Channel::ChannelImpl::~ChannelImpl() {
22 Close(); 141 Close();
23 } 142 }
24 143
25 bool Channel::ChannelImpl::Connect() { 144 bool Channel::ChannelImpl::Connect() {
26 NOTIMPLEMENTED(); 145 if (pipe_ == -1) {
27 return false; 146 DLOG(INFO) << "Channel creation failed: " << pipe_name_;
147 return false;
148 }
149
150 reader_thread_->Start();
151 waiting_connect_ = false;
152 // If there were any messages queued before connection, send them.
153 ProcessOutgoingMessages();
28 } 154 }
29 155
30 void Channel::ChannelImpl::Close() { 156 void Channel::ChannelImpl::Close() {
31 NOTIMPLEMENTED(); 157 // For now, we assume that at shutdown, the reader thread will be woken with
158 // a failure (see NaClIPCAdapter::BlockingRead and CloseChannel). Or... we
159 // might simply be killed with no chance to clean up anyway :-).
160 // If untrusted code tries to close the channel prior to shutdown, it's likely
161 // to hang.
162 // TODO(dmichael): Can we do anything smarter here to make sure the reader
163 // thread wakes up and quits?
164 reader_thread_->Join();
165 close(pipe_);
166 pipe_ = -1;
167 reader_thread_runner_.reset();
168 reader_thread_.reset();
169 read_queue_.clear();
170 output_queue_.clear();
32 } 171 }
33 172
34 bool Channel::ChannelImpl::Send(Message* message) { 173 bool Channel::ChannelImpl::Send(Message* message) {
35 NOTIMPLEMENTED(); 174 DVLOG(2) << "sending message @" << message << " on channel @" << this
175 << " with type " << message->type();
176 scoped_ptr<Message> message_ptr(message);
177
178 #ifdef IPC_MESSAGE_LOG_ENABLED
179 Logging::GetInstance()->OnSendMessage(message, "");
180 #endif // IPC_MESSAGE_LOG_ENABLED
181
182 output_queue_.push_back(linked_ptr<Message>(message));
183 if (!waiting_connect_)
184 return ProcessOutgoingMessages();
185
186 return true;
36 } 187 }
37 188
38 int Channel::ChannelImpl::GetClientFileDescriptor() const { 189 void Channel::ChannelImpl::DidRecvMsg(scoped_ptr<std::vector<char> > buffer) {
39 NOTIMPLEMENTED(); 190 // Close sets the pipe to -1. It's possible we'll get a buffer sent to us from
40 return -1; 191 // the reader thread after Close is called. If so, we ignore it.
192 if (pipe_ == -1)
193 return;
194
195 read_queue_.push_back(linked_ptr<std::vector<char> >(buffer.release()));
41 } 196 }
42 197
43 int Channel::ChannelImpl::TakeClientFileDescriptor() { 198 void Channel::ChannelImpl::ReadDidFail() {
44 NOTIMPLEMENTED(); 199 Close();
45 return -1;
46 } 200 }
47 201
48 bool Channel::ChannelImpl::AcceptsConnections() const { 202 bool Channel::ChannelImpl::CreatePipe(
49 NOTIMPLEMENTED(); 203 const IPC::ChannelHandle& channel_handle) {
50 return false; 204 DCHECK(pipe_ == -1);
205
206 // There's one possible case in NaCl:
207 // 1) It's a channel wrapping a pipe that is given to us.
208 // We don't support these:
209 // 2) It's for a named channel.
210 // 3) It's for a client that we implement ourself.
211 // 4) It's the initial IPC channel.
212
213 if (channel_handle.socket.fd == -1) {
214 NOTIMPLEMENTED();
215 return false;
216 }
217 pipe_ = channel_handle.socket.fd;
218 return true;
51 } 219 }
52 220
53 bool Channel::ChannelImpl::HasAcceptedConnection() const { 221 bool Channel::ChannelImpl::ProcessOutgoingMessages() {
54 NOTIMPLEMENTED(); 222 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
55 return false; 223 // no connection?
224 if (output_queue_.empty())
225 return true;
226
227 if (pipe_ == -1)
228 return false;
229
230 // Write out all the messages. The trusted implementation is guaranteed to not
231 // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg.
232 while (!output_queue_.empty()) {
233 linked_ptr<Message> msg = output_queue_.front();
234 output_queue_.pop_front();
235
236 struct NaClImcMsgHdr msgh = {0};
237 struct NaClImcMsgIoVec iov = {const_cast<void*>(msg->data()), msg->size()};
238 msgh.iov = &iov;
239 msgh.iov_length = 1;
240 ssize_t bytes_written = imc_sendmsg(pipe_, &msgh, 0);
241
242 if (bytes_written < 0) {
243 // The trusted side should only ever give us an error of EPIPE. We
244 // should never be interrupted, nor should we get EAGAIN.
245 DCHECK(errno == EPIPE);
246 Close();
247 PLOG(ERROR) << "pipe_ error on "
248 << pipe_
249 << " Currently writing message of size: "
250 << msg->size();
251 return false;
252 }
253
254 // Message sent OK!
255 DVLOG(2) << "sent message @" << msg.get() << " with type " << msg->type()
256 << " on fd " << pipe_;
257 }
258 return true;
56 } 259 }
57 260
58 bool Channel::ChannelImpl::GetClientEuid(uid_t* client_euid) const { 261 Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData(
59 NOTIMPLEMENTED(); 262 char* buffer,
60 return false; 263 int buffer_len,
61 } 264 int* bytes_read) {
62 265 *bytes_read = 0;
63 void Channel::ChannelImpl::ResetToAcceptingConnectionState() { 266 if (pipe_ == -1)
64 NOTIMPLEMENTED(); 267 return READ_FAILED;
65 } 268 if (read_queue_.empty())
66 269 return READ_PENDING;
67 Channel::ChannelImpl::ReadState 270 while (!read_queue_.empty() && *bytes_read < buffer_len) {
68 Channel::ChannelImpl::ReadData(char* buffer, 271 linked_ptr<std::vector<char> > vec(read_queue_.front());
69 int buffer_len, 272 int bytes_to_read = buffer_len - *bytes_read;
70 int* bytes_read) { 273 if (vec->size() <= bytes_to_read) {
71 return Channel::ChannelImpl::ReadState(); 274 // We can read and discard the entire vector.
275 std::copy(vec->begin(), vec->end(), buffer + *bytes_read);
276 *bytes_read += vec->size();
277 read_queue_.pop_front();
278 } else {
279 // Read all the bytes we can and discard them from the front of the
280 // vector. (This can be slowish, since erase has to move the back of the
281 // vector to the front, but it's hopefully a temporary hack and it keeps
282 // the code simple).
283 std::copy(vec->begin(), vec->begin() + bytes_to_read,
284 buffer + *bytes_read);
285 vec->erase(vec->begin(), vec->begin() + bytes_to_read);
286 *bytes_read += bytes_to_read;
287 }
288 }
289 return READ_SUCCEEDED;
72 } 290 }
73 291
74 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { 292 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) {
75 return false; 293 return true;
76 } 294 }
77 295
78 bool Channel::ChannelImpl::DidEmptyInputBuffers() { 296 bool Channel::ChannelImpl::DidEmptyInputBuffers() {
79 return false; 297 return true;
80 } 298 }
81 299
82 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { 300 void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) {
83 } 301 // The trusted side IPC::Channel should handle the "hello" handshake; we
84 302 // should not receive the "Hello" message.
85 // static 303 NOTREACHED();
86 bool Channel::ChannelImpl::IsNamedServerInitialized(
87 const std::string& channel_id) {
88 return false; //file_util::PathExists(FilePath(channel_id));
89 } 304 }
90 305
91 //------------------------------------------------------------------------------ 306 //------------------------------------------------------------------------------
92 // Channel's methods simply call through to ChannelImpl. 307 // Channel's methods simply call through to ChannelImpl.
93 308
94 Channel::Channel(const IPC::ChannelHandle& channel_handle, 309 Channel::Channel(const IPC::ChannelHandle& channel_handle,
95 Mode mode, 310 Mode mode,
96 Listener* listener) 311 Listener* listener)
97 : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) { 312 : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) {
98 } 313 }
99 314
100 Channel::~Channel() { 315 Channel::~Channel() {
101 delete channel_impl_; 316 delete channel_impl_;
102 } 317 }
103 318
104 bool Channel::Connect() { 319 bool Channel::Connect() {
105 return channel_impl_->Connect(); 320 return channel_impl_->Connect();
106 } 321 }
107 322
108 void Channel::Close() { 323 void Channel::Close() {
109 channel_impl_->Close(); 324 channel_impl_->Close();
110 } 325 }
111 326
112 void Channel::set_listener(Listener* listener) { 327 void Channel::set_listener(Listener* listener) {
113 channel_impl_->set_listener(listener); 328 channel_impl_->set_listener(listener);
114 } 329 }
115 330
331 base::ProcessId Channel::peer_pid() const {
332 // This shouldn't actually get used in the untrusted side of the proxy, and we
333 // don't have the real pid anyway.
334 return -1;
335 }
336
116 bool Channel::Send(Message* message) { 337 bool Channel::Send(Message* message) {
117 return channel_impl_->Send(message); 338 return channel_impl_->Send(message);
118 } 339 }
119 340
120 int Channel::GetClientFileDescriptor() const {
121 return channel_impl_->GetClientFileDescriptor();
122 }
123
124 int Channel::TakeClientFileDescriptor() {
125 return channel_impl_->TakeClientFileDescriptor();
126 }
127
128 bool Channel::AcceptsConnections() const {
129 return channel_impl_->AcceptsConnections();
130 }
131
132 bool Channel::HasAcceptedConnection() const {
133 return channel_impl_->HasAcceptedConnection();
134 }
135
136 bool Channel::GetClientEuid(uid_t* client_euid) const {
137 return channel_impl_->GetClientEuid(client_euid);
138 }
139
140 void Channel::ResetToAcceptingConnectionState() {
141 channel_impl_->ResetToAcceptingConnectionState();
142 }
143
144 base::ProcessId Channel::peer_pid() const { return 0; }
145
146 // static 341 // static
147 bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
148 return ChannelImpl::IsNamedServerInitialized(channel_id);
149 }
150
151 // static
152 std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) { 342 std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) {
153 // A random name is sufficient validation on posix systems, so we don't need 343 // A random name is sufficient validation on posix systems, so we don't need
154 // an additional shared secret. 344 // an additional shared secret.
155 std::string id = prefix; 345 std::string id = prefix;
156 if (!id.empty()) 346 if (!id.empty())
157 id.append("."); 347 id.append(".");
158 348
159 return id.append(GenerateUniqueRandomChannelID()); 349 return id.append(GenerateUniqueRandomChannelID());
160 } 350 }
161 351
162 } // namespace IPC 352 } // namespace IPC
OLDNEW
« no previous file with comments | « ipc/ipc_channel_nacl.h ('k') | ipc/ipc_channel_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698