• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "base/bind.h"
6 #include "base/compiler_specific.h"
7 #include "base/debug/trace_event.h"
8 #include "base/location.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "ipc/ipc_channel_proxy.h"
14 #include "ipc/ipc_listener.h"
15 #include "ipc/ipc_logging.h"
16 #include "ipc/ipc_message_macros.h"
17 #include "ipc/ipc_message_utils.h"
18 
19 namespace IPC {
20 
21 //------------------------------------------------------------------------------
22 
MessageFilter()23 ChannelProxy::MessageFilter::MessageFilter() {}
24 
OnFilterAdded(Channel * channel)25 void ChannelProxy::MessageFilter::OnFilterAdded(Channel* channel) {}
26 
OnFilterRemoved()27 void ChannelProxy::MessageFilter::OnFilterRemoved() {}
28 
OnChannelConnected(int32 peer_pid)29 void ChannelProxy::MessageFilter::OnChannelConnected(int32 peer_pid) {}
30 
OnChannelError()31 void ChannelProxy::MessageFilter::OnChannelError() {}
32 
OnChannelClosing()33 void ChannelProxy::MessageFilter::OnChannelClosing() {}
34 
OnMessageReceived(const Message & message)35 bool ChannelProxy::MessageFilter::OnMessageReceived(const Message& message) {
36   return false;
37 }
38 
~MessageFilter()39 ChannelProxy::MessageFilter::~MessageFilter() {}
40 
41 //------------------------------------------------------------------------------
42 
Context(Listener * listener,base::SingleThreadTaskRunner * ipc_task_runner)43 ChannelProxy::Context::Context(Listener* listener,
44                                base::SingleThreadTaskRunner* ipc_task_runner)
45     : listener_task_runner_(base::ThreadTaskRunnerHandle::Get()),
46       listener_(listener),
47       ipc_task_runner_(ipc_task_runner),
48       channel_connected_called_(false),
49       peer_pid_(base::kNullProcessId) {
50   DCHECK(ipc_task_runner_.get());
51 }
52 
~Context()53 ChannelProxy::Context::~Context() {
54 }
55 
ClearIPCTaskRunner()56 void ChannelProxy::Context::ClearIPCTaskRunner() {
57   ipc_task_runner_ = NULL;
58 }
59 
CreateChannel(const IPC::ChannelHandle & handle,const Channel::Mode & mode)60 void ChannelProxy::Context::CreateChannel(const IPC::ChannelHandle& handle,
61                                           const Channel::Mode& mode) {
62   DCHECK(channel_.get() == NULL);
63   channel_id_ = handle.name;
64   channel_.reset(new Channel(handle, mode, this));
65 }
66 
TryFilters(const Message & message)67 bool ChannelProxy::Context::TryFilters(const Message& message) {
68 #ifdef IPC_MESSAGE_LOG_ENABLED
69   Logging* logger = Logging::GetInstance();
70   if (logger->Enabled())
71     logger->OnPreDispatchMessage(message);
72 #endif
73 
74   for (size_t i = 0; i < filters_.size(); ++i) {
75     if (filters_[i]->OnMessageReceived(message)) {
76 #ifdef IPC_MESSAGE_LOG_ENABLED
77       if (logger->Enabled())
78         logger->OnPostDispatchMessage(message, channel_id_);
79 #endif
80       return true;
81     }
82   }
83   return false;
84 }
85 
86 // Called on the IPC::Channel thread
OnMessageReceived(const Message & message)87 bool ChannelProxy::Context::OnMessageReceived(const Message& message) {
88   // First give a chance to the filters to process this message.
89   if (!TryFilters(message))
90     OnMessageReceivedNoFilter(message);
91   return true;
92 }
93 
94 // Called on the IPC::Channel thread
OnMessageReceivedNoFilter(const Message & message)95 bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
96   // NOTE: This code relies on the listener's message loop not going away while
97   // this thread is active.  That should be a reasonable assumption, but it
98   // feels risky.  We may want to invent some more indirect way of referring to
99   // a MessageLoop if this becomes a problem.
100   listener_task_runner_->PostTask(
101       FROM_HERE, base::Bind(&Context::OnDispatchMessage, this, message));
102   return true;
103 }
104 
105 // Called on the IPC::Channel thread
OnChannelConnected(int32 peer_pid)106 void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) {
107   // Add any pending filters.  This avoids a race condition where someone
108   // creates a ChannelProxy, calls AddFilter, and then right after starts the
109   // peer process.  The IO thread could receive a message before the task to add
110   // the filter is run on the IO thread.
111   OnAddFilter();
112 
113   // We cache off the peer_pid so it can be safely accessed from both threads.
114   peer_pid_ = channel_->peer_pid();
115   for (size_t i = 0; i < filters_.size(); ++i)
116     filters_[i]->OnChannelConnected(peer_pid);
117 
118   // See above comment about using listener_task_runner_ here.
119   listener_task_runner_->PostTask(
120       FROM_HERE, base::Bind(&Context::OnDispatchConnected, this));
121 }
122 
123 // Called on the IPC::Channel thread
OnChannelError()124 void ChannelProxy::Context::OnChannelError() {
125   for (size_t i = 0; i < filters_.size(); ++i)
126     filters_[i]->OnChannelError();
127 
128   // See above comment about using listener_task_runner_ here.
129   listener_task_runner_->PostTask(
130       FROM_HERE, base::Bind(&Context::OnDispatchError, this));
131 }
132 
133 // Called on the IPC::Channel thread
OnChannelOpened()134 void ChannelProxy::Context::OnChannelOpened() {
135   DCHECK(channel_ != NULL);
136 
137   // Assume a reference to ourselves on behalf of this thread.  This reference
138   // will be released when we are closed.
139   AddRef();
140 
141   if (!channel_->Connect()) {
142     OnChannelError();
143     return;
144   }
145 
146   for (size_t i = 0; i < filters_.size(); ++i)
147     filters_[i]->OnFilterAdded(channel_.get());
148 }
149 
150 // Called on the IPC::Channel thread
OnChannelClosed()151 void ChannelProxy::Context::OnChannelClosed() {
152   // It's okay for IPC::ChannelProxy::Close to be called more than once, which
153   // would result in this branch being taken.
154   if (!channel_.get())
155     return;
156 
157   for (size_t i = 0; i < filters_.size(); ++i) {
158     filters_[i]->OnChannelClosing();
159     filters_[i]->OnFilterRemoved();
160   }
161 
162   // We don't need the filters anymore.
163   filters_.clear();
164 
165   channel_.reset();
166 
167   // Balance with the reference taken during startup.  This may result in
168   // self-destruction.
169   Release();
170 }
171 
Clear()172 void ChannelProxy::Context::Clear() {
173   listener_ = NULL;
174 }
175 
176 // Called on the IPC::Channel thread
OnSendMessage(scoped_ptr<Message> message)177 void ChannelProxy::Context::OnSendMessage(scoped_ptr<Message> message) {
178   if (!channel_.get()) {
179     OnChannelClosed();
180     return;
181   }
182   if (!channel_->Send(message.release()))
183     OnChannelError();
184 }
185 
186 // Called on the IPC::Channel thread
OnAddFilter()187 void ChannelProxy::Context::OnAddFilter() {
188   std::vector<scoped_refptr<MessageFilter> > new_filters;
189   {
190     base::AutoLock auto_lock(pending_filters_lock_);
191     new_filters.swap(pending_filters_);
192   }
193 
194   for (size_t i = 0; i < new_filters.size(); ++i) {
195     filters_.push_back(new_filters[i]);
196 
197     // If the channel has already been created, then we need to send this
198     // message so that the filter gets access to the Channel.
199     if (channel_.get())
200       new_filters[i]->OnFilterAdded(channel_.get());
201     // Ditto for if the channel has been connected.
202     if (peer_pid_)
203       new_filters[i]->OnChannelConnected(peer_pid_);
204   }
205 }
206 
207 // Called on the IPC::Channel thread
OnRemoveFilter(MessageFilter * filter)208 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
209   if (!channel_.get())
210     return;  // The filters have already been deleted.
211 
212   for (size_t i = 0; i < filters_.size(); ++i) {
213     if (filters_[i].get() == filter) {
214       filter->OnFilterRemoved();
215       filters_.erase(filters_.begin() + i);
216       return;
217     }
218   }
219 
220   NOTREACHED() << "filter to be removed not found";
221 }
222 
223 // Called on the listener's thread
AddFilter(MessageFilter * filter)224 void ChannelProxy::Context::AddFilter(MessageFilter* filter) {
225   base::AutoLock auto_lock(pending_filters_lock_);
226   pending_filters_.push_back(make_scoped_refptr(filter));
227   ipc_task_runner_->PostTask(
228       FROM_HERE, base::Bind(&Context::OnAddFilter, this));
229 }
230 
231 // Called on the listener's thread
OnDispatchMessage(const Message & message)232 void ChannelProxy::Context::OnDispatchMessage(const Message& message) {
233 #ifdef IPC_MESSAGE_LOG_ENABLED
234   Logging* logger = Logging::GetInstance();
235   std::string name;
236   logger->GetMessageText(message.type(), &name, &message, NULL);
237   TRACE_EVENT1("task", "ChannelProxy::Context::OnDispatchMessage",
238                "name", name);
239 #else
240   TRACE_EVENT2("task", "ChannelProxy::Context::OnDispatchMessage",
241                "class", IPC_MESSAGE_ID_CLASS(message.type()),
242                "line", IPC_MESSAGE_ID_LINE(message.type()));
243 #endif
244 
245   if (!listener_)
246     return;
247 
248   OnDispatchConnected();
249 
250 #ifdef IPC_MESSAGE_LOG_ENABLED
251   if (message.type() == IPC_LOGGING_ID) {
252     logger->OnReceivedLoggingMessage(message);
253     return;
254   }
255 
256   if (logger->Enabled())
257     logger->OnPreDispatchMessage(message);
258 #endif
259 
260   listener_->OnMessageReceived(message);
261 
262 #ifdef IPC_MESSAGE_LOG_ENABLED
263   if (logger->Enabled())
264     logger->OnPostDispatchMessage(message, channel_id_);
265 #endif
266 }
267 
268 // Called on the listener's thread
OnDispatchConnected()269 void ChannelProxy::Context::OnDispatchConnected() {
270   if (channel_connected_called_)
271     return;
272 
273   channel_connected_called_ = true;
274   if (listener_)
275     listener_->OnChannelConnected(peer_pid_);
276 }
277 
278 // Called on the listener's thread
OnDispatchError()279 void ChannelProxy::Context::OnDispatchError() {
280   if (listener_)
281     listener_->OnChannelError();
282 }
283 
284 //-----------------------------------------------------------------------------
285 
ChannelProxy(const IPC::ChannelHandle & channel_handle,Channel::Mode mode,Listener * listener,base::SingleThreadTaskRunner * ipc_task_runner)286 ChannelProxy::ChannelProxy(const IPC::ChannelHandle& channel_handle,
287                            Channel::Mode mode,
288                            Listener* listener,
289                            base::SingleThreadTaskRunner* ipc_task_runner)
290     : context_(new Context(listener, ipc_task_runner)),
291       did_init_(false) {
292   Init(channel_handle, mode, true);
293 }
294 
ChannelProxy(Context * context)295 ChannelProxy::ChannelProxy(Context* context)
296     : context_(context),
297       did_init_(false) {
298 }
299 
~ChannelProxy()300 ChannelProxy::~ChannelProxy() {
301   DCHECK(CalledOnValidThread());
302 
303   Close();
304 }
305 
Init(const IPC::ChannelHandle & channel_handle,Channel::Mode mode,bool create_pipe_now)306 void ChannelProxy::Init(const IPC::ChannelHandle& channel_handle,
307                         Channel::Mode mode,
308                         bool create_pipe_now) {
309   DCHECK(CalledOnValidThread());
310   DCHECK(!did_init_);
311 #if defined(OS_POSIX)
312   // When we are creating a server on POSIX, we need its file descriptor
313   // to be created immediately so that it can be accessed and passed
314   // to other processes. Forcing it to be created immediately avoids
315   // race conditions that may otherwise arise.
316   if (mode & Channel::MODE_SERVER_FLAG) {
317     create_pipe_now = true;
318   }
319 #endif  // defined(OS_POSIX)
320 
321   if (create_pipe_now) {
322     // Create the channel immediately.  This effectively sets up the
323     // low-level pipe so that the client can connect.  Without creating
324     // the pipe immediately, it is possible for a listener to attempt
325     // to connect and get an error since the pipe doesn't exist yet.
326     context_->CreateChannel(channel_handle, mode);
327   } else {
328     context_->ipc_task_runner()->PostTask(
329         FROM_HERE, base::Bind(&Context::CreateChannel, context_.get(),
330                               channel_handle, mode));
331   }
332 
333   // complete initialization on the background thread
334   context_->ipc_task_runner()->PostTask(
335       FROM_HERE, base::Bind(&Context::OnChannelOpened, context_.get()));
336 
337   did_init_ = true;
338 }
339 
Close()340 void ChannelProxy::Close() {
341   DCHECK(CalledOnValidThread());
342 
343   // Clear the backpointer to the listener so that any pending calls to
344   // Context::OnDispatchMessage or OnDispatchError will be ignored.  It is
345   // possible that the channel could be closed while it is receiving messages!
346   context_->Clear();
347 
348   if (context_->ipc_task_runner()) {
349     context_->ipc_task_runner()->PostTask(
350         FROM_HERE, base::Bind(&Context::OnChannelClosed, context_.get()));
351   }
352 }
353 
Send(Message * message)354 bool ChannelProxy::Send(Message* message) {
355   DCHECK(did_init_);
356 
357   // TODO(alexeypa): add DCHECK(CalledOnValidThread()) here. Currently there are
358   // tests that call Send() from a wrong thread. See http://crbug.com/163523.
359 
360 #ifdef IPC_MESSAGE_LOG_ENABLED
361   Logging::GetInstance()->OnSendMessage(message, context_->channel_id());
362 #endif
363 
364   context_->ipc_task_runner()->PostTask(
365       FROM_HERE,
366       base::Bind(&ChannelProxy::Context::OnSendMessage,
367                  context_, base::Passed(scoped_ptr<Message>(message))));
368   return true;
369 }
370 
AddFilter(MessageFilter * filter)371 void ChannelProxy::AddFilter(MessageFilter* filter) {
372   DCHECK(CalledOnValidThread());
373 
374   context_->AddFilter(filter);
375 }
376 
RemoveFilter(MessageFilter * filter)377 void ChannelProxy::RemoveFilter(MessageFilter* filter) {
378   DCHECK(CalledOnValidThread());
379 
380   context_->ipc_task_runner()->PostTask(
381       FROM_HERE, base::Bind(&Context::OnRemoveFilter, context_.get(),
382                             make_scoped_refptr(filter)));
383 }
384 
ClearIPCTaskRunner()385 void ChannelProxy::ClearIPCTaskRunner() {
386   DCHECK(CalledOnValidThread());
387 
388   context()->ClearIPCTaskRunner();
389 }
390 
391 #if defined(OS_POSIX) && !defined(OS_NACL)
392 // See the TODO regarding lazy initialization of the channel in
393 // ChannelProxy::Init().
GetClientFileDescriptor()394 int ChannelProxy::GetClientFileDescriptor() {
395   DCHECK(CalledOnValidThread());
396 
397   Channel* channel = context_.get()->channel_.get();
398   // Channel must have been created first.
399   DCHECK(channel) << context_.get()->channel_id_;
400   return channel->GetClientFileDescriptor();
401 }
402 
TakeClientFileDescriptor()403 int ChannelProxy::TakeClientFileDescriptor() {
404   DCHECK(CalledOnValidThread());
405 
406   Channel* channel = context_.get()->channel_.get();
407   // Channel must have been created first.
408   DCHECK(channel) << context_.get()->channel_id_;
409   return channel->TakeClientFileDescriptor();
410 }
411 
GetPeerEuid(uid_t * peer_euid) const412 bool ChannelProxy::GetPeerEuid(uid_t* peer_euid) const {
413   DCHECK(CalledOnValidThread());
414 
415   Channel* channel = context_.get()->channel_.get();
416   // Channel must have been created first.
417   DCHECK(channel) << context_.get()->channel_id_;
418   return channel->GetPeerEuid(peer_euid);
419 }
420 #endif
421 
422 //-----------------------------------------------------------------------------
423 
424 }  // namespace IPC
425