1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/chrome/common/ipc_channel_proxy.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,302 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/message_loop.h" 1.9 +#include "base/thread.h" 1.10 +#include "chrome/common/ipc_channel_proxy.h" 1.11 +#include "chrome/common/ipc_logging.h" 1.12 +#include "chrome/common/ipc_message_utils.h" 1.13 + 1.14 +namespace IPC { 1.15 + 1.16 +//----------------------------------------------------------------------------- 1.17 + 1.18 +ChannelProxy::Context::Context(Channel::Listener* listener, 1.19 + MessageFilter* filter, 1.20 + MessageLoop* ipc_message_loop) 1.21 + : listener_message_loop_(MessageLoop::current()), 1.22 + listener_(listener), 1.23 + ipc_message_loop_(ipc_message_loop), 1.24 + channel_(NULL), 1.25 + peer_pid_(0), 1.26 + channel_connected_called_(false) { 1.27 + if (filter) 1.28 + filters_.push_back(filter); 1.29 +} 1.30 + 1.31 +void ChannelProxy::Context::CreateChannel(const std::wstring& id, 1.32 + const Channel::Mode& mode) { 1.33 + DCHECK(channel_ == NULL); 1.34 + channel_id_ = id; 1.35 + channel_ = new Channel(id, mode, this); 1.36 +} 1.37 + 1.38 +bool ChannelProxy::Context::TryFilters(const Message& message) { 1.39 +#ifdef IPC_MESSAGE_LOG_ENABLED 1.40 + Logging* logger = Logging::current(); 1.41 + if (logger->Enabled()) 1.42 + logger->OnPreDispatchMessage(message); 1.43 +#endif 1.44 + 1.45 + for (size_t i = 0; i < filters_.size(); ++i) { 1.46 + if (filters_[i]->OnMessageReceived(message)) { 1.47 +#ifdef IPC_MESSAGE_LOG_ENABLED 1.48 + if (logger->Enabled()) 1.49 + logger->OnPostDispatchMessage(message, channel_id_); 1.50 +#endif 1.51 + return true; 1.52 + } 1.53 + } 1.54 + return false; 1.55 +} 1.56 + 1.57 +// Called on the IPC::Channel thread 1.58 +void ChannelProxy::Context::OnMessageReceived(const Message& message) { 1.59 + // First give a chance to the filters to process this message. 1.60 + if (!TryFilters(message)) 1.61 + OnMessageReceivedNoFilter(message); 1.62 +} 1.63 + 1.64 +// Called on the IPC::Channel thread 1.65 +void ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) { 1.66 + // NOTE: This code relies on the listener's message loop not going away while 1.67 + // this thread is active. That should be a reasonable assumption, but it 1.68 + // feels risky. We may want to invent some more indirect way of referring to 1.69 + // a MessageLoop if this becomes a problem. 1.70 + listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( 1.71 + this, &Context::OnDispatchMessage, message)); 1.72 +} 1.73 + 1.74 +// Called on the IPC::Channel thread 1.75 +void ChannelProxy::Context::OnChannelConnected(int32_t peer_pid) { 1.76 + peer_pid_ = peer_pid; 1.77 + for (size_t i = 0; i < filters_.size(); ++i) 1.78 + filters_[i]->OnChannelConnected(peer_pid); 1.79 + 1.80 + // See above comment about using listener_message_loop_ here. 1.81 + listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( 1.82 + this, &Context::OnDispatchConnected)); 1.83 +} 1.84 + 1.85 +// Called on the IPC::Channel thread 1.86 +void ChannelProxy::Context::OnChannelError() { 1.87 + for (size_t i = 0; i < filters_.size(); ++i) 1.88 + filters_[i]->OnChannelError(); 1.89 + 1.90 + // See above comment about using listener_message_loop_ here. 1.91 + listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( 1.92 + this, &Context::OnDispatchError)); 1.93 +} 1.94 + 1.95 +// Called on the IPC::Channel thread 1.96 +void ChannelProxy::Context::OnChannelOpened() { 1.97 + DCHECK(channel_ != NULL); 1.98 + 1.99 + // Assume a reference to ourselves on behalf of this thread. This reference 1.100 + // will be released when we are closed. 1.101 + AddRef(); 1.102 + 1.103 + if (!channel_->Connect()) { 1.104 + OnChannelError(); 1.105 + return; 1.106 + } 1.107 + 1.108 + for (size_t i = 0; i < filters_.size(); ++i) 1.109 + filters_[i]->OnFilterAdded(channel_); 1.110 +} 1.111 + 1.112 +// Called on the IPC::Channel thread 1.113 +void ChannelProxy::Context::OnChannelClosed() { 1.114 + // It's okay for IPC::ChannelProxy::Close to be called more than once, which 1.115 + // would result in this branch being taken. 1.116 + if (!channel_) 1.117 + return; 1.118 + 1.119 + for (size_t i = 0; i < filters_.size(); ++i) { 1.120 + filters_[i]->OnChannelClosing(); 1.121 + filters_[i]->OnFilterRemoved(); 1.122 + } 1.123 + 1.124 + // We don't need the filters anymore. 1.125 + filters_.clear(); 1.126 + 1.127 + delete channel_; 1.128 + channel_ = NULL; 1.129 + 1.130 + // Balance with the reference taken during startup. This may result in 1.131 + // self-destruction. 1.132 + Release(); 1.133 +} 1.134 + 1.135 +// Called on the IPC::Channel thread 1.136 +void ChannelProxy::Context::OnSendMessage(Message* message) { 1.137 + if (!channel_->Send(message)) 1.138 + OnChannelError(); 1.139 +} 1.140 + 1.141 +// Called on the IPC::Channel thread 1.142 +void ChannelProxy::Context::OnAddFilter(MessageFilter* filter) { 1.143 + filters_.push_back(filter); 1.144 + 1.145 + // If the channel has already been created, then we need to send this message 1.146 + // so that the filter gets access to the Channel. 1.147 + if (channel_) 1.148 + filter->OnFilterAdded(channel_); 1.149 + 1.150 + // Balances the AddRef in ChannelProxy::AddFilter. 1.151 + filter->Release(); 1.152 +} 1.153 + 1.154 +// Called on the IPC::Channel thread 1.155 +void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) { 1.156 + for (size_t i = 0; i < filters_.size(); ++i) { 1.157 + if (filters_[i].get() == filter) { 1.158 + filter->OnFilterRemoved(); 1.159 + filters_.erase(filters_.begin() + i); 1.160 + return; 1.161 + } 1.162 + } 1.163 + 1.164 + NOTREACHED() << "filter to be removed not found"; 1.165 +} 1.166 + 1.167 +// Called on the listener's thread 1.168 +void ChannelProxy::Context::OnDispatchMessage(const Message& message) { 1.169 + if (!listener_) 1.170 + return; 1.171 + 1.172 + OnDispatchConnected(); 1.173 + 1.174 +#ifdef IPC_MESSAGE_LOG_ENABLED 1.175 + Logging* logger = Logging::current(); 1.176 + if (message.type() == IPC_LOGGING_ID) { 1.177 + logger->OnReceivedLoggingMessage(message); 1.178 + return; 1.179 + } 1.180 + 1.181 + if (logger->Enabled()) 1.182 + logger->OnPreDispatchMessage(message); 1.183 +#endif 1.184 + 1.185 + listener_->OnMessageReceived(message); 1.186 + 1.187 +#ifdef IPC_MESSAGE_LOG_ENABLED 1.188 + if (logger->Enabled()) 1.189 + logger->OnPostDispatchMessage(message, channel_id_); 1.190 +#endif 1.191 +} 1.192 + 1.193 +// Called on the listener's thread 1.194 +void ChannelProxy::Context::OnDispatchConnected() { 1.195 + if (channel_connected_called_) 1.196 + return; 1.197 + 1.198 + channel_connected_called_ = true; 1.199 + if (listener_) 1.200 + listener_->OnChannelConnected(peer_pid_); 1.201 +} 1.202 + 1.203 +// Called on the listener's thread 1.204 +void ChannelProxy::Context::OnDispatchError() { 1.205 + if (listener_) 1.206 + listener_->OnChannelError(); 1.207 +} 1.208 + 1.209 +//----------------------------------------------------------------------------- 1.210 + 1.211 +ChannelProxy::ChannelProxy(const std::wstring& channel_id, Channel::Mode mode, 1.212 + Channel::Listener* listener, MessageFilter* filter, 1.213 + MessageLoop* ipc_thread) 1.214 + : context_(new Context(listener, filter, ipc_thread)) { 1.215 + Init(channel_id, mode, ipc_thread, true); 1.216 +} 1.217 + 1.218 +ChannelProxy::ChannelProxy(const std::wstring& channel_id, Channel::Mode mode, 1.219 + MessageLoop* ipc_thread, Context* context, 1.220 + bool create_pipe_now) 1.221 + : context_(context) { 1.222 + Init(channel_id, mode, ipc_thread, create_pipe_now); 1.223 +} 1.224 + 1.225 +void ChannelProxy::Init(const std::wstring& channel_id, Channel::Mode mode, 1.226 + MessageLoop* ipc_thread_loop, bool create_pipe_now) { 1.227 + if (create_pipe_now) { 1.228 + // Create the channel immediately. This effectively sets up the 1.229 + // low-level pipe so that the client can connect. Without creating 1.230 + // the pipe immediately, it is possible for a listener to attempt 1.231 + // to connect and get an error since the pipe doesn't exist yet. 1.232 + context_->CreateChannel(channel_id, mode); 1.233 + } else { 1.234 +#if defined(OS_POSIX) 1.235 + // TODO(playmobil): On POSIX, IPC::Channel uses a socketpair(), one side of 1.236 + // which needs to be mapped into the child process' address space. 1.237 + // To know the value of the client side FD we need to have already 1.238 + // created a socketpair which currently occurs in IPC::Channel's 1.239 + // constructor. 1.240 + // If we lazilly construct the IPC::Channel then the caller has no way 1.241 + // of knowing the FD #. 1.242 + // 1.243 + // We can solve this either by having the Channel's creation launch the 1.244 + // subprocess itself or by creating the socketpair() externally. 1.245 + NOTIMPLEMENTED(); 1.246 +#endif // defined(OS_POSIX) 1.247 + context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 1.248 + context_.get(), &Context::CreateChannel, channel_id, mode)); 1.249 + } 1.250 + 1.251 + // complete initialization on the background thread 1.252 + context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 1.253 + context_.get(), &Context::OnChannelOpened)); 1.254 +} 1.255 + 1.256 +void ChannelProxy::Close() { 1.257 + // Clear the backpointer to the listener so that any pending calls to 1.258 + // Context::OnDispatchMessage or OnDispatchError will be ignored. It is 1.259 + // possible that the channel could be closed while it is receiving messages! 1.260 + context_->Clear(); 1.261 + 1.262 + if (context_->ipc_message_loop()) { 1.263 + context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 1.264 + context_.get(), &Context::OnChannelClosed)); 1.265 + } 1.266 +} 1.267 + 1.268 +bool ChannelProxy::Send(Message* message) { 1.269 +#ifdef IPC_MESSAGE_LOG_ENABLED 1.270 + Logging::current()->OnSendMessage(message, context_->channel_id()); 1.271 +#endif 1.272 + 1.273 + context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 1.274 + context_.get(), &Context::OnSendMessage, message)); 1.275 + return true; 1.276 +} 1.277 + 1.278 +void ChannelProxy::AddFilter(MessageFilter* filter) { 1.279 + // We want to addref the filter to prevent it from 1.280 + // being destroyed before the OnAddFilter call is invoked. 1.281 + filter->AddRef(); 1.282 + context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 1.283 + context_.get(), &Context::OnAddFilter, filter)); 1.284 +} 1.285 + 1.286 +void ChannelProxy::RemoveFilter(MessageFilter* filter) { 1.287 + context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( 1.288 + context_.get(), &Context::OnRemoveFilter, filter)); 1.289 +} 1.290 + 1.291 +#if defined(OS_POSIX) 1.292 +// See the TODO regarding lazy initialization of the channel in 1.293 +// ChannelProxy::Init(). 1.294 +// We assume that IPC::Channel::GetClientFileDescriptorMapping() is thread-safe. 1.295 +void ChannelProxy::GetClientFileDescriptorMapping(int *src_fd, 1.296 + int *dest_fd) const { 1.297 + Channel *channel = context_.get()->channel_; 1.298 + DCHECK(channel); // Channel must have been created first. 1.299 + channel->GetClientFileDescriptorMapping(src_fd, dest_fd); 1.300 +} 1.301 +#endif 1.302 + 1.303 +//----------------------------------------------------------------------------- 1.304 + 1.305 +} // namespace IPC