[content shell] hook up testRunner.dumpEditingCallbacks
[chromium-blink-merge.git] / content / common / np_channel_base.cc
bloba85fdb528f53eaa08c8b7c4729c41cc4a2626225
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.
5 #include "content/common/np_channel_base.h"
7 #include <stack>
9 #include "base/auto_reset.h"
10 #include "base/hash_tables.h"
11 #include "base/lazy_instance.h"
12 #include "base/string_number_conversions.h"
13 #include "ipc/ipc_sync_message.h"
15 #if defined(OS_POSIX)
16 #include "ipc/ipc_channel_posix.h"
17 #endif
19 namespace content {
21 typedef base::hash_map<std::string, scoped_refptr<NPChannelBase> > ChannelMap;
22 static base::LazyInstance<ChannelMap>::Leaky
23 g_channels = LAZY_INSTANCE_INITIALIZER;
25 typedef std::stack<scoped_refptr<NPChannelBase> > NPChannelRefStack;
26 static base::LazyInstance<NPChannelRefStack>::Leaky
27 g_lazy_channel_stack = LAZY_INSTANCE_INITIALIZER;
29 NPChannelBase* NPChannelBase::GetChannel(
30 const IPC::ChannelHandle& channel_handle, IPC::Channel::Mode mode,
31 ChannelFactory factory, base::MessageLoopProxy* ipc_message_loop,
32 bool create_pipe_now, base::WaitableEvent* shutdown_event) {
33 scoped_refptr<NPChannelBase> channel;
34 std::string channel_key = channel_handle.name;
35 ChannelMap::const_iterator iter = g_channels.Get().find(channel_key);
36 if (iter == g_channels.Get().end()) {
37 channel = factory();
38 } else {
39 channel = iter->second;
42 DCHECK(channel != NULL);
44 if (!channel->channel_valid()) {
45 channel->channel_handle_ = channel_handle;
46 if (mode & IPC::Channel::MODE_SERVER_FLAG) {
47 channel->channel_handle_.name =
48 IPC::Channel::GenerateVerifiedChannelID(channel_key);
50 channel->mode_ = mode;
51 if (channel->Init(ipc_message_loop, create_pipe_now, shutdown_event)) {
52 g_channels.Get()[channel_key] = channel;
53 } else {
54 channel = NULL;
58 return channel;
61 void NPChannelBase::Broadcast(IPC::Message* message) {
62 for (ChannelMap::iterator iter = g_channels.Get().begin();
63 iter != g_channels.Get().end();
64 ++iter) {
65 iter->second->Send(new IPC::Message(*message));
67 delete message;
70 NPChannelBase::NPChannelBase()
71 : mode_(IPC::Channel::MODE_NONE),
72 non_npobject_count_(0),
73 peer_pid_(0),
74 in_remove_route_(false),
75 channel_valid_(false),
76 in_unblock_dispatch_(0),
77 send_unblocking_only_during_unblock_dispatch_(false) {
80 NPChannelBase::~NPChannelBase() {
83 NPChannelBase* NPChannelBase::GetCurrentChannel() {
84 return g_lazy_channel_stack.Pointer()->top();
87 void NPChannelBase::CleanupChannels() {
88 // Make a copy of the references as we can't iterate the map since items will
89 // be removed from it as we clean them up.
90 std::vector<scoped_refptr<NPChannelBase> > channels;
91 for (ChannelMap::const_iterator iter = g_channels.Get().begin();
92 iter != g_channels.Get().end();
93 ++iter) {
94 channels.push_back(iter->second);
97 for (size_t i = 0; i < channels.size(); ++i)
98 channels[i]->CleanUp();
100 // This will clean up channels added to the map for which subsequent
101 // AddRoute wasn't called
102 g_channels.Get().clear();
105 NPObjectBase* NPChannelBase::GetNPObjectListenerForRoute(int route_id) {
106 ListenerMap::iterator iter = npobject_listeners_.find(route_id);
107 if (iter == npobject_listeners_.end()) {
108 DLOG(WARNING) << "Invalid route id passed in:" << route_id;
109 return NULL;
111 return iter->second;
114 base::WaitableEvent* NPChannelBase::GetModalDialogEvent(int render_view_id) {
115 return NULL;
118 bool NPChannelBase::Init(base::MessageLoopProxy* ipc_message_loop,
119 bool create_pipe_now,
120 base::WaitableEvent* shutdown_event) {
121 #if defined(OS_POSIX)
122 // Attempting to initialize with an invalid channel handle.
123 // See http://crbug.com/97285 for details.
124 if (mode_ == IPC::Channel::MODE_CLIENT && -1 == channel_handle_.socket.fd)
125 return false;
126 #endif
128 channel_.reset(new IPC::SyncChannel(
129 channel_handle_, mode_, this, ipc_message_loop, create_pipe_now,
130 shutdown_event));
132 #if defined(OS_POSIX)
133 // Check the validity of fd for bug investigation. Remove after fixed.
134 // See crbug.com/97285 for details.
135 if (mode_ == IPC::Channel::MODE_SERVER)
136 CHECK_NE(-1, channel_->GetClientFileDescriptor());
137 #endif
139 channel_valid_ = true;
140 return true;
143 bool NPChannelBase::Send(IPC::Message* message) {
144 if (!channel_.get()) {
145 VLOG(1) << "Channel is NULL; dropping message";
146 delete message;
147 return false;
150 if (send_unblocking_only_during_unblock_dispatch_ &&
151 in_unblock_dispatch_ == 0 &&
152 message->is_sync()) {
153 message->set_unblock(false);
156 return channel_->Send(message);
159 int NPChannelBase::Count() {
160 return static_cast<int>(g_channels.Get().size());
163 bool NPChannelBase::OnMessageReceived(const IPC::Message& message) {
164 // This call might cause us to be deleted, so keep an extra reference to
165 // ourself so that we can send the reply and decrement back in_dispatch_.
166 g_lazy_channel_stack.Pointer()->push(
167 scoped_refptr<NPChannelBase>(this));
169 bool handled;
170 if (message.should_unblock())
171 in_unblock_dispatch_++;
172 if (message.routing_id() == MSG_ROUTING_CONTROL) {
173 handled = OnControlMessageReceived(message);
174 } else {
175 handled = router_.RouteMessage(message);
176 if (!handled && message.is_sync()) {
177 // The listener has gone away, so we must respond or else the caller will
178 // hang waiting for a reply.
179 IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
180 reply->set_reply_error();
181 Send(reply);
184 if (message.should_unblock())
185 in_unblock_dispatch_--;
187 g_lazy_channel_stack.Pointer()->pop();
188 return handled;
191 void NPChannelBase::OnChannelConnected(int32 peer_pid) {
192 peer_pid_ = peer_pid;
195 void NPChannelBase::AddRoute(int route_id,
196 IPC::Listener* listener,
197 NPObjectBase* npobject) {
198 if (npobject) {
199 npobject_listeners_[route_id] = npobject;
200 } else {
201 non_npobject_count_++;
204 router_.AddRoute(route_id, listener);
207 void NPChannelBase::RemoveRoute(int route_id) {
208 router_.RemoveRoute(route_id);
210 ListenerMap::iterator iter = npobject_listeners_.find(route_id);
211 if (iter != npobject_listeners_.end()) {
212 // This was an NPObject proxy or stub, it's not involved in the refcounting.
214 // If this RemoveRoute call from the NPObject is a result of us calling
215 // OnChannelError below, don't call erase() here because that'll corrupt
216 // the iterator below.
217 if (in_remove_route_) {
218 iter->second = NULL;
219 } else {
220 npobject_listeners_.erase(iter);
223 return;
226 non_npobject_count_--;
227 DCHECK(non_npobject_count_ >= 0);
229 if (!non_npobject_count_) {
230 base::AutoReset<bool> auto_reset_in_remove_route(&in_remove_route_, true);
231 for (ListenerMap::iterator npobj_iter = npobject_listeners_.begin();
232 npobj_iter != npobject_listeners_.end(); ++npobj_iter) {
233 if (npobj_iter->second) {
234 npobj_iter->second->GetChannelListener()->OnChannelError();
238 for (ChannelMap::iterator iter = g_channels.Get().begin();
239 iter != g_channels.Get().end(); ++iter) {
240 if (iter->second == this) {
241 g_channels.Get().erase(iter);
242 return;
246 NOTREACHED();
250 bool NPChannelBase::OnControlMessageReceived(const IPC::Message& msg) {
251 NOTREACHED() <<
252 "should override in subclass if you care about control messages";
253 return false;
256 void NPChannelBase::OnChannelError() {
257 channel_valid_ = false;
259 // TODO(shess): http://crbug.com/97285
260 // Once an error is seen on a channel, remap the channel to prevent
261 // it from being vended again. Keep the channel in the map so
262 // RemoveRoute() can clean things up correctly.
263 for (ChannelMap::iterator iter = g_channels.Get().begin();
264 iter != g_channels.Get().end(); ++iter) {
265 if (iter->second == this) {
266 // Insert new element before invalidating |iter|.
267 g_channels.Get()[iter->first + "-error"] = iter->second;
268 g_channels.Get().erase(iter);
269 break;
274 NPObject* NPChannelBase::GetExistingNPObjectProxy(int route_id) {
275 ProxyMap::iterator iter = proxy_map_.find(route_id);
276 return iter != proxy_map_.end() ? iter->second : NULL;
279 int NPChannelBase::GetExistingRouteForNPObjectStub(NPObject* npobject) {
280 StubMap::iterator iter = stub_map_.find(npobject);
281 return iter != stub_map_.end() ? iter->second : MSG_ROUTING_NONE;
284 void NPChannelBase::AddMappingForNPObjectProxy(int route_id,
285 NPObject* object) {
286 proxy_map_[route_id] = object;
289 void NPChannelBase::AddMappingForNPObjectStub(int route_id,
290 NPObject* object) {
291 DCHECK(object != NULL);
292 stub_map_[object] = route_id;
295 void NPChannelBase::RemoveMappingForNPObjectStub(int route_id,
296 NPObject* object) {
297 DCHECK(object != NULL);
298 stub_map_.erase(object);
301 void NPChannelBase::RemoveMappingForNPObjectProxy(int route_id) {
302 proxy_map_.erase(route_id);
305 } // namespace content