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.
4 :
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"
10 :
11 : namespace IPC {
12 :
13 : //-----------------------------------------------------------------------------
14 :
15 0 : ChannelProxy::Context::Context(Channel::Listener* listener,
16 : MessageFilter* filter,
17 : MessageLoop* ipc_message_loop)
18 0 : : listener_message_loop_(MessageLoop::current()),
19 : listener_(listener),
20 : ipc_message_loop_(ipc_message_loop),
21 : channel_(NULL),
22 : peer_pid_(0),
23 0 : channel_connected_called_(false) {
24 0 : if (filter)
25 0 : filters_.push_back(filter);
26 0 : }
27 :
28 0 : void ChannelProxy::Context::CreateChannel(const std::wstring& id,
29 : const Channel::Mode& mode) {
30 0 : DCHECK(channel_ == NULL);
31 0 : channel_id_ = id;
32 0 : channel_ = new Channel(id, mode, this);
33 0 : }
34 :
35 0 : bool ChannelProxy::Context::TryFilters(const Message& message) {
36 : #ifdef IPC_MESSAGE_LOG_ENABLED
37 0 : Logging* logger = Logging::current();
38 0 : if (logger->Enabled())
39 0 : logger->OnPreDispatchMessage(message);
40 : #endif
41 :
42 0 : for (size_t i = 0; i < filters_.size(); ++i) {
43 0 : if (filters_[i]->OnMessageReceived(message)) {
44 : #ifdef IPC_MESSAGE_LOG_ENABLED
45 0 : if (logger->Enabled())
46 0 : logger->OnPostDispatchMessage(message, channel_id_);
47 : #endif
48 0 : return true;
49 : }
50 : }
51 0 : return false;
52 : }
53 :
54 : // Called on the IPC::Channel thread
55 0 : void ChannelProxy::Context::OnMessageReceived(const Message& message) {
56 : // First give a chance to the filters to process this message.
57 0 : if (!TryFilters(message))
58 0 : OnMessageReceivedNoFilter(message);
59 0 : }
60 :
61 : // Called on the IPC::Channel thread
62 0 : 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 0 : this, &Context::OnDispatchMessage, message));
69 0 : }
70 :
71 : // Called on the IPC::Channel thread
72 0 : void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) {
73 0 : peer_pid_ = peer_pid;
74 0 : for (size_t i = 0; i < filters_.size(); ++i)
75 0 : filters_[i]->OnChannelConnected(peer_pid);
76 :
77 : // See above comment about using listener_message_loop_ here.
78 : listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
79 0 : this, &Context::OnDispatchConnected));
80 0 : }
81 :
82 : // Called on the IPC::Channel thread
83 0 : void ChannelProxy::Context::OnChannelError() {
84 0 : for (size_t i = 0; i < filters_.size(); ++i)
85 0 : filters_[i]->OnChannelError();
86 :
87 : // See above comment about using listener_message_loop_ here.
88 : listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
89 0 : this, &Context::OnDispatchError));
90 0 : }
91 :
92 : // Called on the IPC::Channel thread
93 0 : void ChannelProxy::Context::OnChannelOpened() {
94 0 : DCHECK(channel_ != NULL);
95 :
96 : // Assume a reference to ourselves on behalf of this thread. This reference
97 : // will be released when we are closed.
98 0 : AddRef();
99 :
100 0 : if (!channel_->Connect()) {
101 0 : OnChannelError();
102 0 : return;
103 : }
104 :
105 0 : for (size_t i = 0; i < filters_.size(); ++i)
106 0 : filters_[i]->OnFilterAdded(channel_);
107 : }
108 :
109 : // Called on the IPC::Channel thread
110 0 : 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 0 : if (!channel_)
114 0 : return;
115 :
116 0 : for (size_t i = 0; i < filters_.size(); ++i) {
117 0 : filters_[i]->OnChannelClosing();
118 0 : filters_[i]->OnFilterRemoved();
119 : }
120 :
121 : // We don't need the filters anymore.
122 0 : filters_.clear();
123 :
124 0 : delete channel_;
125 0 : channel_ = NULL;
126 :
127 : // Balance with the reference taken during startup. This may result in
128 : // self-destruction.
129 0 : Release();
130 : }
131 :
132 : // Called on the IPC::Channel thread
133 0 : void ChannelProxy::Context::OnSendMessage(Message* message) {
134 0 : if (!channel_->Send(message))
135 0 : OnChannelError();
136 0 : }
137 :
138 : // Called on the IPC::Channel thread
139 0 : void ChannelProxy::Context::OnAddFilter(MessageFilter* filter) {
140 0 : filters_.push_back(filter);
141 :
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 0 : if (channel_)
145 0 : filter->OnFilterAdded(channel_);
146 :
147 : // Balances the AddRef in ChannelProxy::AddFilter.
148 0 : filter->Release();
149 0 : }
150 :
151 : // Called on the IPC::Channel thread
152 0 : void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
153 0 : for (size_t i = 0; i < filters_.size(); ++i) {
154 0 : if (filters_[i].get() == filter) {
155 0 : filter->OnFilterRemoved();
156 0 : filters_.erase(filters_.begin() + i);
157 0 : return;
158 : }
159 : }
160 :
161 0 : NOTREACHED() << "filter to be removed not found";
162 : }
163 :
164 : // Called on the listener's thread
165 0 : void ChannelProxy::Context::OnDispatchMessage(const Message& message) {
166 0 : if (!listener_)
167 0 : return;
168 :
169 0 : OnDispatchConnected();
170 :
171 : #ifdef IPC_MESSAGE_LOG_ENABLED
172 0 : Logging* logger = Logging::current();
173 0 : if (message.type() == IPC_LOGGING_ID) {
174 0 : logger->OnReceivedLoggingMessage(message);
175 0 : return;
176 : }
177 :
178 0 : if (logger->Enabled())
179 0 : logger->OnPreDispatchMessage(message);
180 : #endif
181 :
182 0 : listener_->OnMessageReceived(message);
183 :
184 : #ifdef IPC_MESSAGE_LOG_ENABLED
185 0 : if (logger->Enabled())
186 0 : logger->OnPostDispatchMessage(message, channel_id_);
187 : #endif
188 : }
189 :
190 : // Called on the listener's thread
191 0 : void ChannelProxy::Context::OnDispatchConnected() {
192 0 : if (channel_connected_called_)
193 0 : return;
194 :
195 0 : channel_connected_called_ = true;
196 0 : if (listener_)
197 0 : listener_->OnChannelConnected(peer_pid_);
198 : }
199 :
200 : // Called on the listener's thread
201 0 : void ChannelProxy::Context::OnDispatchError() {
202 0 : if (listener_)
203 0 : listener_->OnChannelError();
204 0 : }
205 :
206 : //-----------------------------------------------------------------------------
207 :
208 0 : ChannelProxy::ChannelProxy(const std::wstring& channel_id, Channel::Mode mode,
209 : Channel::Listener* listener, MessageFilter* filter,
210 : MessageLoop* ipc_thread)
211 0 : : context_(new Context(listener, filter, ipc_thread)) {
212 0 : Init(channel_id, mode, ipc_thread, true);
213 0 : }
214 :
215 0 : ChannelProxy::ChannelProxy(const std::wstring& channel_id, Channel::Mode mode,
216 : MessageLoop* ipc_thread, Context* context,
217 : bool create_pipe_now)
218 0 : : context_(context) {
219 0 : Init(channel_id, mode, ipc_thread, create_pipe_now);
220 0 : }
221 :
222 0 : void ChannelProxy::Init(const std::wstring& channel_id, Channel::Mode mode,
223 : MessageLoop* ipc_thread_loop, bool create_pipe_now) {
224 0 : 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 0 : 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 0 : NOTIMPLEMENTED();
243 : #endif // defined(OS_POSIX)
244 : context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
245 0 : context_.get(), &Context::CreateChannel, channel_id, mode));
246 : }
247 :
248 : // complete initialization on the background thread
249 : context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
250 0 : context_.get(), &Context::OnChannelOpened));
251 0 : }
252 :
253 0 : 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 0 : context_->Clear();
258 :
259 0 : if (context_->ipc_message_loop()) {
260 : context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
261 0 : context_.get(), &Context::OnChannelClosed));
262 : }
263 0 : }
264 :
265 0 : bool ChannelProxy::Send(Message* message) {
266 : #ifdef IPC_MESSAGE_LOG_ENABLED
267 0 : Logging::current()->OnSendMessage(message, context_->channel_id());
268 : #endif
269 :
270 : context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
271 0 : context_.get(), &Context::OnSendMessage, message));
272 0 : return true;
273 : }
274 :
275 0 : 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 0 : filter->AddRef();
279 : context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
280 0 : context_.get(), &Context::OnAddFilter, filter));
281 0 : }
282 :
283 0 : void ChannelProxy::RemoveFilter(MessageFilter* filter) {
284 : context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
285 0 : context_.get(), &Context::OnRemoveFilter, filter));
286 0 : }
287 :
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 0 : void ChannelProxy::GetClientFileDescriptorMapping(int *src_fd,
293 : int *dest_fd) const {
294 0 : Channel *channel = context_.get()->channel_;
295 0 : DCHECK(channel); // Channel must have been created first.
296 0 : channel->GetClientFileDescriptorMapping(src_fd, dest_fd);
297 0 : }
298 : #endif
299 :
300 : //-----------------------------------------------------------------------------
301 :
302 : } // namespace IPC
|