OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/api/mdns/mdns_api.h" | 5 #include "chrome/browser/extensions/api/mdns/mdns_api.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
10 #include "chrome/browser/extensions/extension_service.h" | 10 #include "chrome/browser/extensions/extension_service.h" |
11 #include "chrome/common/extensions/api/mdns.h" | 11 #include "chrome/common/extensions/api/mdns.h" |
12 #include "content/public/browser/render_process_host.h" | |
13 #include "content/public/browser/render_view_host.h" | |
14 #include "extensions/browser/extension_host.h" | |
12 #include "extensions/browser/extension_registry.h" | 15 #include "extensions/browser/extension_registry.h" |
16 #include "extensions/common/extension_messages.h" | |
13 | 17 |
14 namespace extensions { | 18 namespace extensions { |
15 | 19 |
16 namespace mdns = api::mdns; | 20 namespace mdns = api::mdns; |
17 | 21 |
18 namespace { | 22 namespace { |
19 | 23 |
20 // Whitelisted mDNS service types. | 24 // Whitelisted mDNS service types. |
21 const char kCastServiceType[] = "_googlecast._tcp.local"; | 25 const char kCastServiceType[] = "_googlecast._tcp.local"; |
22 const char kPrivetServiceType[] = "_privet._tcp.local"; | 26 const char kPrivetServiceType[] = "_privet._tcp.local"; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
77 UpdateMDnsListeners(details); | 81 UpdateMDnsListeners(details); |
78 } | 82 } |
79 | 83 |
80 void MDnsAPI::OnListenerRemoved(const EventListenerInfo& details) { | 84 void MDnsAPI::OnListenerRemoved(const EventListenerInfo& details) { |
81 DCHECK(thread_checker_.CalledOnValidThread()); | 85 DCHECK(thread_checker_.CalledOnValidThread()); |
82 UpdateMDnsListeners(details); | 86 UpdateMDnsListeners(details); |
83 } | 87 } |
84 | 88 |
85 void MDnsAPI::UpdateMDnsListeners(const EventListenerInfo& details) { | 89 void MDnsAPI::UpdateMDnsListeners(const EventListenerInfo& details) { |
86 std::set<std::string> new_service_types; | 90 std::set<std::string> new_service_types; |
87 | 91 GetValidOnServiceListListeners("" /* sevice_type_filter */, |
mark a. foltz
2015/04/07 22:43:32
What does an empty filter mean? Please document.
mark a. foltz
2015/04/07 22:43:32
service_type_filter
Red Daly
2015/04/07 23:16:56
Done.
Red Daly
2015/04/07 23:16:57
Done. Added explanation to inline comment; there
| |
88 // Check all listeners for service type filters. | 92 nullptr /* extension_ids */, |
89 const EventListenerMap::ListenerList& listeners = | 93 &new_service_types); |
90 extensions::EventRouter::Get(browser_context_) | |
91 ->listeners() | |
92 .GetEventListenersByName(details.event_name); | |
93 for (EventListenerMap::ListenerList::const_iterator it = listeners.begin(); | |
94 it != listeners.end(); ++it) { | |
95 base::DictionaryValue* filter = ((*it)->filter()); | |
96 | |
97 std::string filter_value; | |
98 filter->GetStringASCII(kEventFilterServiceTypeKey, &filter_value); | |
99 if (filter_value.empty()) | |
100 continue; | |
101 | |
102 const Extension* extension = ExtensionRegistry::Get(browser_context_)-> | |
103 enabled_extensions().GetByID((*it)->extension_id()); | |
104 // Don't listen for services associated only with disabled extensions. | |
105 if (!extension) | |
106 continue; | |
107 | |
108 // Platform apps may query for all services; other types of extensions are | |
109 // restricted to a whitelist. | |
110 if (!extension->is_platform_app() && | |
111 !IsServiceTypeWhitelisted(filter_value)) | |
112 continue; | |
113 | |
114 new_service_types.insert(filter_value); | |
115 } | |
116 | 94 |
117 // Find all the added and removed service types since last update. | 95 // Find all the added and removed service types since last update. |
118 std::set<std::string> added_service_types = | 96 std::set<std::string> added_service_types = |
119 base::STLSetDifference<std::set<std::string> >( | 97 base::STLSetDifference<std::set<std::string> >( |
120 new_service_types, service_types_); | 98 new_service_types, service_types_); |
121 std::set<std::string> removed_service_types = | 99 std::set<std::string> removed_service_types = |
122 base::STLSetDifference<std::set<std::string> >( | 100 base::STLSetDifference<std::set<std::string> >( |
123 service_types_, new_service_types); | 101 service_types_, new_service_types); |
124 | 102 |
125 // Update the registry. | 103 // Update the registry. |
126 DnsSdRegistry* registry = dns_sd_registry(); | 104 DnsSdRegistry* registry = dns_sd_registry(); |
127 for (const auto& srv : added_service_types) { | 105 for (const auto& srv : added_service_types) { |
128 registry->RegisterDnsSdListener(srv); | 106 registry->RegisterDnsSdListener(srv); |
129 } | 107 } |
130 for (const auto& srv : removed_service_types) { | 108 for (const auto& srv : removed_service_types) { |
131 registry->UnregisterDnsSdListener(srv); | 109 registry->UnregisterDnsSdListener(srv); |
132 } | 110 } |
133 service_types_ = new_service_types; | 111 service_types_ = new_service_types; |
134 } | 112 } |
135 | 113 |
136 void MDnsAPI::OnDnsSdEvent(const std::string& service_type, | 114 void MDnsAPI::OnDnsSdEvent(const std::string& service_type, |
137 const DnsSdRegistry::DnsSdServiceList& services) { | 115 const DnsSdRegistry::DnsSdServiceList& services) { |
138 DCHECK(thread_checker_.CalledOnValidThread()); | 116 DCHECK(thread_checker_.CalledOnValidThread()); |
139 | 117 |
140 std::vector<linked_ptr<mdns::MDnsService> > args; | 118 std::vector<linked_ptr<mdns::MDnsService> > args; |
141 for (DnsSdRegistry::DnsSdServiceList::const_iterator it = services.begin(); | 119 for (DnsSdRegistry::DnsSdServiceList::const_iterator it = services.begin(); |
142 it != services.end(); ++it) { | 120 it != services.end(); ++it) { |
121 if (static_cast<long>(args.size()) == | |
122 api::mdns::MAX_SERVICE_INSTANCES_PER_EVENT) { | |
123 // TODO(reddaly): This is not the most meaningful way of notifying the | |
124 // application that something bad happened. It will go to the user's | |
125 // console (which most users don't look at)and the developer will be none | |
126 // the wiser. Instead, changing the event to pass the number of | |
127 // discovered instances would allow the caller to know when the list is | |
128 // truncated and tell the user something meaningful in the extension/app. | |
129 WriteToConsole(service_type, | |
130 content::CONSOLE_MESSAGE_LEVEL_WARNING, | |
131 base::StringPrintf( | |
132 "Truncating number of service instances in " | |
133 "onServiceList to maximum allowed: %d", | |
134 api::mdns::MAX_SERVICE_INSTANCES_PER_EVENT)); | |
135 break; | |
136 } | |
143 linked_ptr<mdns::MDnsService> mdns_service = | 137 linked_ptr<mdns::MDnsService> mdns_service = |
144 make_linked_ptr(new mdns::MDnsService); | 138 make_linked_ptr(new mdns::MDnsService); |
145 mdns_service->service_name = (*it).service_name; | 139 mdns_service->service_name = (*it).service_name; |
146 mdns_service->service_host_port = (*it).service_host_port; | 140 mdns_service->service_host_port = (*it).service_host_port; |
147 mdns_service->ip_address = (*it).ip_address; | 141 mdns_service->ip_address = (*it).ip_address; |
148 mdns_service->service_data = (*it).service_data; | 142 mdns_service->service_data = (*it).service_data; |
149 args.push_back(mdns_service); | 143 args.push_back(mdns_service); |
150 } | 144 } |
151 | 145 |
152 scoped_ptr<base::ListValue> results = mdns::OnServiceList::Create(args); | 146 scoped_ptr<base::ListValue> results = mdns::OnServiceList::Create(args); |
153 scoped_ptr<Event> event( | 147 scoped_ptr<Event> event( |
154 new Event(mdns::OnServiceList::kEventName, results.Pass())); | 148 new Event(mdns::OnServiceList::kEventName, results.Pass())); |
155 event->restrict_to_browser_context = browser_context_; | 149 event->restrict_to_browser_context = browser_context_; |
156 event->filter_info.SetServiceType(service_type); | 150 event->filter_info.SetServiceType(service_type); |
157 | 151 |
158 // TODO(justinlin): To avoid having listeners without filters getting all | 152 // TODO(justinlin): To avoid having listeners without filters getting all |
159 // events, modify API to have this event require filters. | 153 // events, modify API to have this event require filters. |
160 // TODO(reddaly): If event isn't on whitelist, ensure it does not get | 154 // TODO(reddaly): If event isn't on whitelist, ensure it does not get |
161 // broadcast to extensions. | 155 // broadcast to extensions. |
162 extensions::EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); | 156 extensions::EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); |
163 } | 157 } |
164 | 158 |
159 void MDnsAPI::GetValidOnServiceListListeners( | |
160 const std::string& service_type_filter, | |
161 std::set<std::string>* extension_ids, | |
162 std::set<std::string>* service_types) { | |
163 for (const auto& listener : | |
164 extensions::EventRouter::Get(browser_context_)->listeners() | |
mark a. foltz
2015/04/07 22:43:33
This indentation looks funny, but might be right.
Red Daly
2015/04/07 23:16:56
Acknowledged - changed to 2 spaces for indentation
| |
165 .GetEventListenersByName(mdns::OnServiceList::kEventName)) { | |
166 base::DictionaryValue* filter = (listener->filter()); | |
mark a. foltz
2015/04/07 22:43:33
Extra ( )
Red Daly
2015/04/07 23:16:56
Done.
| |
167 | |
168 std::string service_type; | |
169 filter->GetStringASCII(kEventFilterServiceTypeKey, &service_type); | |
170 if (service_type.empty()) | |
171 continue; | |
172 | |
173 // Match service type when filter isn't "" | |
174 if (!service_type_filter.empty() && service_type_filter != service_type) | |
175 continue; | |
176 | |
177 const Extension* extension = ExtensionRegistry::Get(browser_context_)-> | |
178 enabled_extensions().GetByID(listener->extension_id()); | |
179 // Don't listen for services associated only with disabled extensions. | |
180 if (!extension) | |
181 continue; | |
182 | |
183 // Platform apps may query for all services; other types of extensions are | |
184 // restricted to a whitelist. | |
185 if (!extension->is_platform_app() && | |
186 !IsServiceTypeWhitelisted(service_type)) | |
187 continue; | |
188 | |
189 if (extension_ids) | |
190 extension_ids->insert(listener->extension_id()); | |
191 if (service_types) | |
192 service_types->insert(service_type); | |
193 } | |
194 } | |
195 | |
196 void MDnsAPI::WriteToConsole(const std::string& service_type, | |
197 content::ConsoleMessageLevel level, | |
198 const std::string& message) { | |
199 // Get all the extensions with an onServiceList listener for a particular | |
200 // service type. | |
201 std::set<std::string> extension_ids; | |
202 GetValidOnServiceListListeners(service_type, | |
203 &extension_ids, | |
204 nullptr /* service_types */); | |
205 | |
206 std::string logged_message(std::string("[chrome.mdns] ") + message); | |
207 | |
208 // Log to the consoles of the background pages for those extensions. | |
209 for (const std::string& extension_id : extension_ids) { | |
210 extensions::ExtensionHost* host = | |
211 extensions::ProcessManager::Get(browser_context_) | |
212 ->GetBackgroundHostForExtension(extension_id); | |
213 if (!host) | |
214 continue; | |
215 content::RenderViewHost* rvh = host->render_view_host(); | |
216 if (!rvh) | |
217 continue; | |
218 rvh->Send(new ExtensionMsg_AddMessageToConsole( | |
219 rvh->GetRoutingID(), | |
220 level, | |
221 logged_message)); | |
222 } | |
223 } | |
224 | |
165 } // namespace extensions | 225 } // namespace extensions |
OLD | NEW |