ipc/chromium/src/chrome/common/ipc_channel_proxy.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2006-2008 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.
     5 #include "base/message_loop.h"
     6 #include "base/thread.h"
     7 #include "chrome/common/ipc_channel_proxy.h"
     8 #include "chrome/common/ipc_logging.h"
     9 #include "chrome/common/ipc_message_utils.h"
    11 namespace IPC {
    13 //-----------------------------------------------------------------------------
    15 ChannelProxy::Context::Context(Channel::Listener* listener,
    16                                MessageFilter* filter,
    17                                MessageLoop* ipc_message_loop)
    18     : listener_message_loop_(MessageLoop::current()),
    19       listener_(listener),
    20       ipc_message_loop_(ipc_message_loop),
    21       channel_(NULL),
    22       peer_pid_(0),
    23       channel_connected_called_(false) {
    24   if (filter)
    25     filters_.push_back(filter);
    26 }
    28 void ChannelProxy::Context::CreateChannel(const std::wstring& id,
    29                                           const Channel::Mode& mode) {
    30   DCHECK(channel_ == NULL);
    31   channel_id_ = id;
    32   channel_ = new Channel(id, mode, this);
    33 }
    35 bool ChannelProxy::Context::TryFilters(const Message& message) {
    36 #ifdef IPC_MESSAGE_LOG_ENABLED
    37   Logging* logger = Logging::current();
    38   if (logger->Enabled())
    39     logger->OnPreDispatchMessage(message);
    40 #endif
    42   for (size_t i = 0; i < filters_.size(); ++i) {
    43     if (filters_[i]->OnMessageReceived(message)) {
    44 #ifdef IPC_MESSAGE_LOG_ENABLED
    45       if (logger->Enabled())
    46         logger->OnPostDispatchMessage(message, channel_id_);
    47 #endif
    48       return true;
    49     }
    50   }
    51   return false;
    52 }
    54 // Called on the IPC::Channel thread
    55 void ChannelProxy::Context::OnMessageReceived(const Message& message) {
    56   // First give a chance to the filters to process this message.
    57   if (!TryFilters(message))
    58     OnMessageReceivedNoFilter(message);
    59 }
    61 // Called on the IPC::Channel thread
    62 void ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
    63   // NOTE: This code relies on the listener's message loop not going away while
    64   // this thread is active.  That should be a reasonable assumption, but it
    65   // feels risky.  We may want to invent some more indirect way of referring to
    66   // a MessageLoop if this becomes a problem.
    67   listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
    68       this, &Context::OnDispatchMessage, message));
    69 }
    71 // Called on the IPC::Channel thread
    72 void ChannelProxy::Context::OnChannelConnected(int32_t peer_pid) {
    73   peer_pid_ = peer_pid;
    74   for (size_t i = 0; i < filters_.size(); ++i)
    75     filters_[i]->OnChannelConnected(peer_pid);
    77   // See above comment about using listener_message_loop_ here.
    78   listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
    79       this, &Context::OnDispatchConnected));
    80 }
    82 // Called on the IPC::Channel thread
    83 void ChannelProxy::Context::OnChannelError() {
    84   for (size_t i = 0; i < filters_.size(); ++i)
    85     filters_[i]->OnChannelError();
    87   // See above comment about using listener_message_loop_ here.
    88   listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
    89       this, &Context::OnDispatchError));
    90 }
    92 // Called on the IPC::Channel thread
    93 void ChannelProxy::Context::OnChannelOpened() {
    94   DCHECK(channel_ != NULL);
    96   // Assume a reference to ourselves on behalf of this thread.  This reference
    97   // will be released when we are closed.
    98   AddRef();
   100   if (!channel_->Connect()) {
   101     OnChannelError();
   102     return;
   103   }
   105   for (size_t i = 0; i < filters_.size(); ++i)
   106     filters_[i]->OnFilterAdded(channel_);
   107 }
   109 // Called on the IPC::Channel thread
   110 void ChannelProxy::Context::OnChannelClosed() {
   111   // It's okay for IPC::ChannelProxy::Close to be called more than once, which
   112   // would result in this branch being taken.
   113   if (!channel_)
   114     return;
   116   for (size_t i = 0; i < filters_.size(); ++i) {
   117     filters_[i]->OnChannelClosing();
   118     filters_[i]->OnFilterRemoved();
   119   }
   121   // We don't need the filters anymore.
   122   filters_.clear();
   124   delete channel_;
   125   channel_ = NULL;
   127   // Balance with the reference taken during startup.  This may result in
   128   // self-destruction.
   129   Release();
   130 }
   132 // Called on the IPC::Channel thread
   133 void ChannelProxy::Context::OnSendMessage(Message* message) {
   134   if (!channel_->Send(message))
   135     OnChannelError();
   136 }
   138 // Called on the IPC::Channel thread
   139 void ChannelProxy::Context::OnAddFilter(MessageFilter* filter) {
   140   filters_.push_back(filter);
   142   // If the channel has already been created, then we need to send this message
   143   // so that the filter gets access to the Channel.
   144   if (channel_)
   145     filter->OnFilterAdded(channel_);
   147   // Balances the AddRef in ChannelProxy::AddFilter.
   148   filter->Release();
   149 }
   151 // Called on the IPC::Channel thread
   152 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
   153   for (size_t i = 0; i < filters_.size(); ++i) {
   154     if (filters_[i].get() == filter) {
   155       filter->OnFilterRemoved();
   156       filters_.erase(filters_.begin() + i);
   157       return;
   158     }
   159   }
   161   NOTREACHED() << "filter to be removed not found";
   162 }
   164 // Called on the listener's thread
   165 void ChannelProxy::Context::OnDispatchMessage(const Message& message) {
   166   if (!listener_)
   167     return;
   169   OnDispatchConnected();
   171 #ifdef IPC_MESSAGE_LOG_ENABLED
   172   Logging* logger = Logging::current();
   173   if (message.type() == IPC_LOGGING_ID) {
   174     logger->OnReceivedLoggingMessage(message);
   175     return;
   176   }
   178   if (logger->Enabled())
   179     logger->OnPreDispatchMessage(message);
   180 #endif
   182   listener_->OnMessageReceived(message);
   184 #ifdef IPC_MESSAGE_LOG_ENABLED
   185   if (logger->Enabled())
   186     logger->OnPostDispatchMessage(message, channel_id_);
   187 #endif
   188 }
   190 // Called on the listener's thread
   191 void ChannelProxy::Context::OnDispatchConnected() {
   192   if (channel_connected_called_)
   193     return;
   195   channel_connected_called_ = true;
   196   if (listener_)
   197     listener_->OnChannelConnected(peer_pid_);
   198 }
   200 // Called on the listener's thread
   201 void ChannelProxy::Context::OnDispatchError() {
   202   if (listener_)
   203     listener_->OnChannelError();
   204 }
   206 //-----------------------------------------------------------------------------
   208 ChannelProxy::ChannelProxy(const std::wstring& channel_id, Channel::Mode mode,
   209                            Channel::Listener* listener, MessageFilter* filter,
   210                            MessageLoop* ipc_thread)
   211     : context_(new Context(listener, filter, ipc_thread)) {
   212   Init(channel_id, mode, ipc_thread, true);
   213 }
   215 ChannelProxy::ChannelProxy(const std::wstring& channel_id, Channel::Mode mode,
   216                            MessageLoop* ipc_thread, Context* context,
   217                            bool create_pipe_now)
   218     : context_(context) {
   219   Init(channel_id, mode, ipc_thread, create_pipe_now);
   220 }
   222 void ChannelProxy::Init(const std::wstring& channel_id, Channel::Mode mode,
   223                         MessageLoop* ipc_thread_loop, bool create_pipe_now) {
   224   if (create_pipe_now) {
   225     // Create the channel immediately.  This effectively sets up the
   226     // low-level pipe so that the client can connect.  Without creating
   227     // the pipe immediately, it is possible for a listener to attempt
   228     // to connect and get an error since the pipe doesn't exist yet.
   229     context_->CreateChannel(channel_id, mode);
   230   } else {
   231 #if defined(OS_POSIX)
   232     // TODO(playmobil): On POSIX, IPC::Channel uses a socketpair(), one side of
   233     // which needs to be mapped into the child process' address space.
   234     // To know the value of the client side FD we need to have already
   235     // created a socketpair which currently occurs in IPC::Channel's
   236     // constructor.
   237     // If we lazilly construct the IPC::Channel then the caller has no way
   238     // of knowing the FD #.
   239     //
   240     // We can solve this either by having the Channel's creation launch the
   241     // subprocess itself or by creating the socketpair() externally.
   242     NOTIMPLEMENTED();
   243 #endif  // defined(OS_POSIX)
   244     context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
   245         context_.get(), &Context::CreateChannel, channel_id, mode));
   246   }
   248   // complete initialization on the background thread
   249   context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
   250       context_.get(), &Context::OnChannelOpened));
   251 }
   253 void ChannelProxy::Close() {
   254   // Clear the backpointer to the listener so that any pending calls to
   255   // Context::OnDispatchMessage or OnDispatchError will be ignored.  It is
   256   // possible that the channel could be closed while it is receiving messages!
   257   context_->Clear();
   259   if (context_->ipc_message_loop()) {
   260     context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
   261         context_.get(), &Context::OnChannelClosed));
   262   }
   263 }
   265 bool ChannelProxy::Send(Message* message) {
   266 #ifdef IPC_MESSAGE_LOG_ENABLED
   267   Logging::current()->OnSendMessage(message, context_->channel_id());
   268 #endif
   270   context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
   271       context_.get(), &Context::OnSendMessage, message));
   272   return true;
   273 }
   275 void ChannelProxy::AddFilter(MessageFilter* filter) {
   276   // We want to addref the filter to prevent it from
   277   // being destroyed before the OnAddFilter call is invoked.
   278   filter->AddRef();
   279   context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
   280       context_.get(), &Context::OnAddFilter, filter));
   281 }
   283 void ChannelProxy::RemoveFilter(MessageFilter* filter) {
   284   context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
   285       context_.get(), &Context::OnRemoveFilter, filter));
   286 }
   288 #if defined(OS_POSIX)
   289 // See the TODO regarding lazy initialization of the channel in
   290 // ChannelProxy::Init().
   291 // We assume that IPC::Channel::GetClientFileDescriptorMapping() is thread-safe.
   292 void ChannelProxy::GetClientFileDescriptorMapping(int *src_fd,
   293                                                   int *dest_fd) const {
   294   Channel *channel = context_.get()->channel_;
   295   DCHECK(channel); // Channel must have been created first.
   296   channel->GetClientFileDescriptorMapping(src_fd, dest_fd);
   297 }
   298 #endif
   300 //-----------------------------------------------------------------------------
   302 }  // namespace IPC

mercurial