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

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