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

Side by Side Diff: ipc/ipc_channel_nacl.cc

Issue 310293002: Make IPC::Channel polymorphic (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Another attempt to fix build breakage Created 6 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_posix.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> 7 #include <errno.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 #include <sys/types.h> 9 #include <sys/types.h>
10 10
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 } 55 }
56 DCHECK(bytes_read); 56 DCHECK(bytes_read);
57 // Resize the buffers down to the number of bytes and fds we actually read. 57 // Resize the buffers down to the number of bytes and fds we actually read.
58 contents->data.resize(bytes_read); 58 contents->data.resize(bytes_read);
59 contents->fds.resize(msg.desc_length); 59 contents->fds.resize(msg.desc_length);
60 return true; 60 return true;
61 } 61 }
62 62
63 } // namespace 63 } // namespace
64 64
65 class Channel::ChannelImpl::ReaderThreadRunner 65 class ChannelNacl::ReaderThreadRunner
66 : public base::DelegateSimpleThread::Delegate { 66 : public base::DelegateSimpleThread::Delegate {
67 public: 67 public:
68 // |pipe|: A file descriptor from which we will read using imc_recvmsg. 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 69 // |data_read_callback|: A callback we invoke (on the main thread) when we
70 // have read data. 70 // have read data.
71 // |failure_callback|: A callback we invoke when we have a failure reading 71 // |failure_callback|: A callback we invoke when we have a failure reading
72 // from |pipe|. 72 // from |pipe|.
73 // |main_message_loop|: A proxy for the main thread, where we will invoke the 73 // |main_message_loop|: A proxy for the main thread, where we will invoke the
74 // above callbacks. 74 // above callbacks.
75 ReaderThreadRunner( 75 ReaderThreadRunner(
76 int pipe, 76 int pipe,
77 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback, 77 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback,
78 base::Callback<void ()> failure_callback, 78 base::Callback<void ()> failure_callback,
79 scoped_refptr<base::MessageLoopProxy> main_message_loop); 79 scoped_refptr<base::MessageLoopProxy> main_message_loop);
80 80
81 // DelegateSimpleThread implementation. Reads data from the pipe in a loop 81 // DelegateSimpleThread implementation. Reads data from the pipe in a loop
82 // until either we are told to quit or a read fails. 82 // until either we are told to quit or a read fails.
83 virtual void Run() OVERRIDE; 83 virtual void Run() OVERRIDE;
84 84
85 private: 85 private:
86 int pipe_; 86 int pipe_;
87 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback_; 87 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback_;
88 base::Callback<void ()> failure_callback_; 88 base::Callback<void ()> failure_callback_;
89 scoped_refptr<base::MessageLoopProxy> main_message_loop_; 89 scoped_refptr<base::MessageLoopProxy> main_message_loop_;
90 90
91 DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner); 91 DISALLOW_COPY_AND_ASSIGN(ReaderThreadRunner);
92 }; 92 };
93 93
94 Channel::ChannelImpl::ReaderThreadRunner::ReaderThreadRunner( 94 ChannelNacl::ReaderThreadRunner::ReaderThreadRunner(
95 int pipe, 95 int pipe,
96 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback, 96 base::Callback<void (scoped_ptr<MessageContents>)> data_read_callback,
97 base::Callback<void ()> failure_callback, 97 base::Callback<void ()> failure_callback,
98 scoped_refptr<base::MessageLoopProxy> main_message_loop) 98 scoped_refptr<base::MessageLoopProxy> main_message_loop)
99 : pipe_(pipe), 99 : pipe_(pipe),
100 data_read_callback_(data_read_callback), 100 data_read_callback_(data_read_callback),
101 failure_callback_(failure_callback), 101 failure_callback_(failure_callback),
102 main_message_loop_(main_message_loop) { 102 main_message_loop_(main_message_loop) {
103 } 103 }
104 104
105 void Channel::ChannelImpl::ReaderThreadRunner::Run() { 105 void ChannelNacl::ReaderThreadRunner::Run() {
106 while (true) { 106 while (true) {
107 scoped_ptr<MessageContents> msg_contents(new MessageContents); 107 scoped_ptr<MessageContents> msg_contents(new MessageContents);
108 bool success = ReadDataOnReaderThread(pipe_, msg_contents.get()); 108 bool success = ReadDataOnReaderThread(pipe_, msg_contents.get());
109 if (success) { 109 if (success) {
110 main_message_loop_->PostTask(FROM_HERE, 110 main_message_loop_->PostTask(FROM_HERE,
111 base::Bind(data_read_callback_, base::Passed(&msg_contents))); 111 base::Bind(data_read_callback_, base::Passed(&msg_contents)));
112 } else { 112 } else {
113 main_message_loop_->PostTask(FROM_HERE, failure_callback_); 113 main_message_loop_->PostTask(FROM_HERE, failure_callback_);
114 // Because the read failed, we know we're going to quit. Don't bother 114 // Because the read failed, we know we're going to quit. Don't bother
115 // trying to read again. 115 // trying to read again.
116 return; 116 return;
117 } 117 }
118 } 118 }
119 } 119 }
120 120
121 Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle& channel_handle, 121 ChannelNacl::ChannelNacl(const IPC::ChannelHandle& channel_handle,
122 Mode mode, 122 Mode mode,
123 Listener* listener) 123 Listener* listener)
124 : ChannelReader(listener), 124 : ChannelReader(listener),
125 mode_(mode), 125 mode_(mode),
126 waiting_connect_(true), 126 waiting_connect_(true),
127 pipe_(-1), 127 pipe_(-1),
128 pipe_name_(channel_handle.name), 128 pipe_name_(channel_handle.name),
129 weak_ptr_factory_(this) { 129 weak_ptr_factory_(this) {
130 if (!CreatePipe(channel_handle)) { 130 if (!CreatePipe(channel_handle)) {
131 // The pipe may have been closed already. 131 // The pipe may have been closed already.
132 const char *modestr = (mode_ & MODE_SERVER_FLAG) ? "server" : "client"; 132 const char *modestr = (mode_ & MODE_SERVER_FLAG) ? "server" : "client";
133 LOG(WARNING) << "Unable to create pipe named \"" << channel_handle.name 133 LOG(WARNING) << "Unable to create pipe named \"" << channel_handle.name
134 << "\" in " << modestr << " mode"; 134 << "\" in " << modestr << " mode";
135 } 135 }
136 } 136 }
137 137
138 Channel::ChannelImpl::~ChannelImpl() { 138 ChannelNacl::~ChannelNacl() {
139 Close(); 139 Close();
140 } 140 }
141 141
142 base::ProcessId Channel::ChannelImpl::peer_pid() const { 142 base::ProcessId ChannelNacl::GetPeerPID() const {
143 // This shouldn't actually get used in the untrusted side of the proxy, and we 143 // This shouldn't actually get used in the untrusted side of the proxy, and we
144 // don't have the real pid anyway. 144 // don't have the real pid anyway.
145 return -1; 145 return -1;
146 } 146 }
147 147
148 bool Channel::ChannelImpl::Connect() { 148 bool ChannelNacl::Connect() {
149 if (pipe_ == -1) { 149 if (pipe_ == -1) {
150 DLOG(WARNING) << "Channel creation failed: " << pipe_name_; 150 DLOG(WARNING) << "Channel creation failed: " << pipe_name_;
151 return false; 151 return false;
152 } 152 }
153 153
154 // Note that Connect is called on the "Channel" thread (i.e., the same thread 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 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 156 // messages). The constructor might be invoked on another thread (see
157 // ChannelProxy for an example of that). Therefore, we must wait until Connect 157 // ChannelProxy for an example of that). Therefore, we must wait until Connect
158 // is called to decide which MessageLoopProxy to pass to ReaderThreadRunner. 158 // is called to decide which MessageLoopProxy to pass to ReaderThreadRunner.
159 reader_thread_runner_.reset( 159 reader_thread_runner_.reset(
160 new ReaderThreadRunner( 160 new ReaderThreadRunner(
161 pipe_, 161 pipe_,
162 base::Bind(&Channel::ChannelImpl::DidRecvMsg, 162 base::Bind(&ChannelNacl::DidRecvMsg,
163 weak_ptr_factory_.GetWeakPtr()), 163 weak_ptr_factory_.GetWeakPtr()),
164 base::Bind(&Channel::ChannelImpl::ReadDidFail, 164 base::Bind(&ChannelNacl::ReadDidFail,
165 weak_ptr_factory_.GetWeakPtr()), 165 weak_ptr_factory_.GetWeakPtr()),
166 base::MessageLoopProxy::current())); 166 base::MessageLoopProxy::current()));
167 reader_thread_.reset( 167 reader_thread_.reset(
168 new base::DelegateSimpleThread(reader_thread_runner_.get(), 168 new base::DelegateSimpleThread(reader_thread_runner_.get(),
169 "ipc_channel_nacl reader thread")); 169 "ipc_channel_nacl reader thread"));
170 reader_thread_->Start(); 170 reader_thread_->Start();
171 waiting_connect_ = false; 171 waiting_connect_ = false;
172 // If there were any messages queued before connection, send them. 172 // If there were any messages queued before connection, send them.
173 ProcessOutgoingMessages(); 173 ProcessOutgoingMessages();
174 base::MessageLoopProxy::current()->PostTask(FROM_HERE, 174 base::MessageLoopProxy::current()->PostTask(FROM_HERE,
175 base::Bind(&Channel::ChannelImpl::CallOnChannelConnected, 175 base::Bind(&ChannelNacl::CallOnChannelConnected,
176 weak_ptr_factory_.GetWeakPtr())); 176 weak_ptr_factory_.GetWeakPtr()));
177 177
178 return true; 178 return true;
179 } 179 }
180 180
181 void Channel::ChannelImpl::Close() { 181 void ChannelNacl::Close() {
182 // For now, we assume that at shutdown, the reader thread will be woken with 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 183 // a failure (see NaClIPCAdapter::BlockingRead and CloseChannel). Or... we
184 // might simply be killed with no chance to clean up anyway :-). 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 185 // If untrusted code tries to close the channel prior to shutdown, it's likely
186 // to hang. 186 // to hang.
187 // TODO(dmichael): Can we do anything smarter here to make sure the reader 187 // TODO(dmichael): Can we do anything smarter here to make sure the reader
188 // thread wakes up and quits? 188 // thread wakes up and quits?
189 reader_thread_->Join(); 189 reader_thread_->Join();
190 close(pipe_); 190 close(pipe_);
191 pipe_ = -1; 191 pipe_ = -1;
192 reader_thread_runner_.reset(); 192 reader_thread_runner_.reset();
193 reader_thread_.reset(); 193 reader_thread_.reset();
194 read_queue_.clear(); 194 read_queue_.clear();
195 output_queue_.clear(); 195 output_queue_.clear();
196 } 196 }
197 197
198 bool Channel::ChannelImpl::Send(Message* message) { 198 bool ChannelNacl::Send(Message* message) {
199 DVLOG(2) << "sending message @" << message << " on channel @" << this 199 DVLOG(2) << "sending message @" << message << " on channel @" << this
200 << " with type " << message->type(); 200 << " with type " << message->type();
201 scoped_ptr<Message> message_ptr(message); 201 scoped_ptr<Message> message_ptr(message);
202 202
203 #ifdef IPC_MESSAGE_LOG_ENABLED 203 #ifdef IPC_MESSAGE_LOG_ENABLED
204 Logging::GetInstance()->OnSendMessage(message_ptr.get(), ""); 204 Logging::GetInstance()->OnSendMessage(message_ptr.get(), "");
205 #endif // IPC_MESSAGE_LOG_ENABLED 205 #endif // IPC_MESSAGE_LOG_ENABLED
206 206
207 message->TraceMessageBegin(); 207 message->TraceMessageBegin();
208 output_queue_.push_back(linked_ptr<Message>(message_ptr.release())); 208 output_queue_.push_back(linked_ptr<Message>(message_ptr.release()));
209 if (!waiting_connect_) 209 if (!waiting_connect_)
210 return ProcessOutgoingMessages(); 210 return ProcessOutgoingMessages();
211 211
212 return true; 212 return true;
213 } 213 }
214 214
215 void Channel::ChannelImpl::DidRecvMsg(scoped_ptr<MessageContents> contents) { 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 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. 217 // the reader thread after Close is called. If so, we ignore it.
218 if (pipe_ == -1) 218 if (pipe_ == -1)
219 return; 219 return;
220 220
221 linked_ptr<std::vector<char> > data(new std::vector<char>); 221 linked_ptr<std::vector<char> > data(new std::vector<char>);
222 data->swap(contents->data); 222 data->swap(contents->data);
223 read_queue_.push_back(data); 223 read_queue_.push_back(data);
224 224
225 input_fds_.insert(input_fds_.end(), 225 input_fds_.insert(input_fds_.end(),
226 contents->fds.begin(), contents->fds.end()); 226 contents->fds.begin(), contents->fds.end());
227 contents->fds.clear(); 227 contents->fds.clear();
228 228
229 // In POSIX, we would be told when there are bytes to read by implementing 229 // In POSIX, we would be told when there are bytes to read by implementing
230 // OnFileCanReadWithoutBlocking in MessageLoopForIO::Watcher. In NaCl, we 230 // OnFileCanReadWithoutBlocking in MessageLoopForIO::Watcher. In NaCl, we
231 // instead know at this point because the reader thread posted some data to 231 // instead know at this point because the reader thread posted some data to
232 // us. 232 // us.
233 ProcessIncomingMessages(); 233 ProcessIncomingMessages();
234 } 234 }
235 235
236 void Channel::ChannelImpl::ReadDidFail() { 236 void ChannelNacl::ReadDidFail() {
237 Close(); 237 Close();
238 } 238 }
239 239
240 bool Channel::ChannelImpl::CreatePipe( 240 bool ChannelNacl::CreatePipe(
241 const IPC::ChannelHandle& channel_handle) { 241 const IPC::ChannelHandle& channel_handle) {
242 DCHECK(pipe_ == -1); 242 DCHECK(pipe_ == -1);
243 243
244 // There's one possible case in NaCl: 244 // There's one possible case in NaCl:
245 // 1) It's a channel wrapping a pipe that is given to us. 245 // 1) It's a channel wrapping a pipe that is given to us.
246 // We don't support these: 246 // We don't support these:
247 // 2) It's for a named channel. 247 // 2) It's for a named channel.
248 // 3) It's for a client that we implement ourself. 248 // 3) It's for a client that we implement ourself.
249 // 4) It's the initial IPC channel. 249 // 4) It's the initial IPC channel.
250 250
251 if (channel_handle.socket.fd == -1) { 251 if (channel_handle.socket.fd == -1) {
252 NOTIMPLEMENTED(); 252 NOTIMPLEMENTED();
253 return false; 253 return false;
254 } 254 }
255 pipe_ = channel_handle.socket.fd; 255 pipe_ = channel_handle.socket.fd;
256 return true; 256 return true;
257 } 257 }
258 258
259 bool Channel::ChannelImpl::ProcessOutgoingMessages() { 259 bool ChannelNacl::ProcessOutgoingMessages() {
260 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's 260 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
261 // no connection? 261 // no connection?
262 if (output_queue_.empty()) 262 if (output_queue_.empty())
263 return true; 263 return true;
264 264
265 if (pipe_ == -1) 265 if (pipe_ == -1)
266 return false; 266 return false;
267 267
268 // Write out all the messages. The trusted implementation is guaranteed to not 268 // Write out all the messages. The trusted implementation is guaranteed to not
269 // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg. 269 // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg.
(...skipping 27 matching lines...) Expand all
297 msg->file_descriptor_set()->CommitAll(); 297 msg->file_descriptor_set()->CommitAll();
298 } 298 }
299 299
300 // Message sent OK! 300 // Message sent OK!
301 DVLOG(2) << "sent message @" << msg.get() << " with type " << msg->type() 301 DVLOG(2) << "sent message @" << msg.get() << " with type " << msg->type()
302 << " on fd " << pipe_; 302 << " on fd " << pipe_;
303 } 303 }
304 return true; 304 return true;
305 } 305 }
306 306
307 void Channel::ChannelImpl::CallOnChannelConnected() { 307 void ChannelNacl::CallOnChannelConnected() {
308 listener()->OnChannelConnected(peer_pid()); 308 listener()->OnChannelConnected(GetPeerPID());
309 } 309 }
310 310
311 Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( 311 ChannelNacl::ReadState ChannelNacl::ReadData(
312 char* buffer, 312 char* buffer,
313 int buffer_len, 313 int buffer_len,
314 int* bytes_read) { 314 int* bytes_read) {
315 *bytes_read = 0; 315 *bytes_read = 0;
316 if (pipe_ == -1) 316 if (pipe_ == -1)
317 return READ_FAILED; 317 return READ_FAILED;
318 if (read_queue_.empty()) 318 if (read_queue_.empty())
319 return READ_PENDING; 319 return READ_PENDING;
320 while (!read_queue_.empty() && *bytes_read < buffer_len) { 320 while (!read_queue_.empty() && *bytes_read < buffer_len) {
321 linked_ptr<std::vector<char> > vec(read_queue_.front()); 321 linked_ptr<std::vector<char> > vec(read_queue_.front());
(...skipping 10 matching lines...) Expand all
332 // the code simple). 332 // the code simple).
333 std::copy(vec->begin(), vec->begin() + bytes_to_read, 333 std::copy(vec->begin(), vec->begin() + bytes_to_read,
334 buffer + *bytes_read); 334 buffer + *bytes_read);
335 vec->erase(vec->begin(), vec->begin() + bytes_to_read); 335 vec->erase(vec->begin(), vec->begin() + bytes_to_read);
336 *bytes_read += bytes_to_read; 336 *bytes_read += bytes_to_read;
337 } 337 }
338 } 338 }
339 return READ_SUCCEEDED; 339 return READ_SUCCEEDED;
340 } 340 }
341 341
342 bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { 342 bool ChannelNacl::WillDispatchInputMessage(Message* msg) {
343 uint16 header_fds = msg->header()->num_fds; 343 uint16 header_fds = msg->header()->num_fds;
344 CHECK(header_fds == input_fds_.size()); 344 CHECK(header_fds == input_fds_.size());
345 if (header_fds == 0) 345 if (header_fds == 0)
346 return true; // Nothing to do. 346 return true; // Nothing to do.
347 347
348 // The shenaniganery below with &foo.front() requires input_fds_ to have 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). 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<>. 350 // This is why the header warns not to make input_fds_ a deque<>.
351 msg->file_descriptor_set()->SetDescriptors(&input_fds_.front(), 351 msg->file_descriptor_set()->SetDescriptors(&input_fds_.front(),
352 header_fds); 352 header_fds);
353 input_fds_.clear(); 353 input_fds_.clear();
354 return true; 354 return true;
355 } 355 }
356 356
357 bool Channel::ChannelImpl::DidEmptyInputBuffers() { 357 bool ChannelNacl::DidEmptyInputBuffers() {
358 // When the input data buffer is empty, the fds should be too. 358 // When the input data buffer is empty, the fds should be too.
359 return input_fds_.empty(); 359 return input_fds_.empty();
360 } 360 }
361 361
362 void Channel::ChannelImpl::HandleInternalMessage(const Message& msg) { 362 void ChannelNacl::HandleInternalMessage(const Message& msg) {
363 // The trusted side IPC::Channel should handle the "hello" handshake; we 363 // The trusted side IPC::Channel should handle the "hello" handshake; we
364 // should not receive the "Hello" message. 364 // should not receive the "Hello" message.
365 NOTREACHED(); 365 NOTREACHED();
366 } 366 }
367 367
368 //------------------------------------------------------------------------------ 368 // Channel's methods
369 // Channel's methods simply call through to ChannelImpl.
370 369
371 Channel::Channel(const IPC::ChannelHandle& channel_handle, 370 // static
372 Mode mode, 371 scoped_ptr<Channel> Channel::Create(
373 Listener* listener) 372 const IPC::ChannelHandle &channel_handle, Mode mode, Listener* listener) {
374 : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) { 373 return scoped_ptr<Channel>(
375 } 374 new ChannelNacl(channel_handle, mode, listener));
376
377 Channel::~Channel() {
378 delete channel_impl_;
379 }
380
381 bool Channel::Connect() {
382 return channel_impl_->Connect();
383 }
384
385 void Channel::Close() {
386 channel_impl_->Close();
387 }
388
389 base::ProcessId Channel::peer_pid() const {
390 return channel_impl_->peer_pid();
391 }
392
393 bool Channel::Send(Message* message) {
394 return channel_impl_->Send(message);
395 } 375 }
396 376
397 } // namespace IPC 377 } // namespace IPC
OLDNEW
« no previous file with comments | « ipc/ipc_channel_nacl.h ('k') | ipc/ipc_channel_posix.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698