Wed, 31 Dec 2014 06:09:35 +0100
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