| 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( |
| 88 // Check all listeners for service type filters. | 92 "" /* service_type_filter - blank = all services */, |
| 89 const EventListenerMap::ListenerList& listeners = | 93 nullptr /* extension_ids */, |
| 90 extensions::EventRouter::Get(browser_context_) | 94 &new_service_types); |
| 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 | 95 |
| 117 // Find all the added and removed service types since last update. | 96 // Find all the added and removed service types since last update. |
| 118 std::set<std::string> added_service_types = | 97 std::set<std::string> added_service_types = |
| 119 base::STLSetDifference<std::set<std::string> >( | 98 base::STLSetDifference<std::set<std::string> >( |
| 120 new_service_types, service_types_); | 99 new_service_types, service_types_); |
| 121 std::set<std::string> removed_service_types = | 100 std::set<std::string> removed_service_types = |
| 122 base::STLSetDifference<std::set<std::string> >( | 101 base::STLSetDifference<std::set<std::string> >( |
| 123 service_types_, new_service_types); | 102 service_types_, new_service_types); |
| 124 | 103 |
| 125 // Update the registry. | 104 // Update the registry. |
| 126 DnsSdRegistry* registry = dns_sd_registry(); | 105 DnsSdRegistry* registry = dns_sd_registry(); |
| 127 for (const auto& srv : added_service_types) { | 106 for (const auto& srv : added_service_types) { |
| 128 registry->RegisterDnsSdListener(srv); | 107 registry->RegisterDnsSdListener(srv); |
| 129 } | 108 } |
| 130 for (const auto& srv : removed_service_types) { | 109 for (const auto& srv : removed_service_types) { |
| 131 registry->UnregisterDnsSdListener(srv); | 110 registry->UnregisterDnsSdListener(srv); |
| 132 } | 111 } |
| 133 service_types_ = new_service_types; | 112 service_types_ = new_service_types; |
| 134 } | 113 } |
| 135 | 114 |
| 136 void MDnsAPI::OnDnsSdEvent(const std::string& service_type, | 115 void MDnsAPI::OnDnsSdEvent(const std::string& service_type, |
| 137 const DnsSdRegistry::DnsSdServiceList& services) { | 116 const DnsSdRegistry::DnsSdServiceList& services) { |
| 138 DCHECK(thread_checker_.CalledOnValidThread()); | 117 DCHECK(thread_checker_.CalledOnValidThread()); |
| 139 | 118 |
| 140 std::vector<linked_ptr<mdns::MDnsService> > args; | 119 std::vector<linked_ptr<mdns::MDnsService> > args; |
| 141 for (DnsSdRegistry::DnsSdServiceList::const_iterator it = services.begin(); | 120 for (DnsSdRegistry::DnsSdServiceList::const_iterator it = services.begin(); |
| 142 it != services.end(); ++it) { | 121 it != services.end(); ++it) { |
| 122 if (static_cast<long>(args.size()) == |
| 123 api::mdns::MAX_SERVICE_INSTANCES_PER_EVENT) { |
| 124 // TODO(reddaly): This is not the most meaningful way of notifying the |
| 125 // application that something bad happened. It will go to the user's |
| 126 // console (which most users don't look at)and the developer will be none |
| 127 // the wiser. Instead, changing the event to pass the number of |
| 128 // discovered instances would allow the caller to know when the list is |
| 129 // truncated and tell the user something meaningful in the extension/app. |
| 130 WriteToConsole(service_type, |
| 131 content::CONSOLE_MESSAGE_LEVEL_WARNING, |
| 132 base::StringPrintf( |
| 133 "Truncating number of service instances in " |
| 134 "onServiceList to maximum allowed: %d", |
| 135 api::mdns::MAX_SERVICE_INSTANCES_PER_EVENT)); |
| 136 break; |
| 137 } |
| 143 linked_ptr<mdns::MDnsService> mdns_service = | 138 linked_ptr<mdns::MDnsService> mdns_service = |
| 144 make_linked_ptr(new mdns::MDnsService); | 139 make_linked_ptr(new mdns::MDnsService); |
| 145 mdns_service->service_name = (*it).service_name; | 140 mdns_service->service_name = (*it).service_name; |
| 146 mdns_service->service_host_port = (*it).service_host_port; | 141 mdns_service->service_host_port = (*it).service_host_port; |
| 147 mdns_service->ip_address = (*it).ip_address; | 142 mdns_service->ip_address = (*it).ip_address; |
| 148 mdns_service->service_data = (*it).service_data; | 143 mdns_service->service_data = (*it).service_data; |
| 149 args.push_back(mdns_service); | 144 args.push_back(mdns_service); |
| 150 } | 145 } |
| 151 | 146 |
| 152 scoped_ptr<base::ListValue> results = mdns::OnServiceList::Create(args); | 147 scoped_ptr<base::ListValue> results = mdns::OnServiceList::Create(args); |
| 153 scoped_ptr<Event> event( | 148 scoped_ptr<Event> event( |
| 154 new Event(mdns::OnServiceList::kEventName, results.Pass())); | 149 new Event(mdns::OnServiceList::kEventName, results.Pass())); |
| 155 event->restrict_to_browser_context = browser_context_; | 150 event->restrict_to_browser_context = browser_context_; |
| 156 event->filter_info.SetServiceType(service_type); | 151 event->filter_info.SetServiceType(service_type); |
| 157 | 152 |
| 158 // TODO(justinlin): To avoid having listeners without filters getting all | 153 // TODO(justinlin): To avoid having listeners without filters getting all |
| 159 // events, modify API to have this event require filters. | 154 // events, modify API to have this event require filters. |
| 160 // TODO(reddaly): If event isn't on whitelist, ensure it does not get | 155 // TODO(reddaly): If event isn't on whitelist, ensure it does not get |
| 161 // broadcast to extensions. | 156 // broadcast to extensions. |
| 162 extensions::EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); | 157 extensions::EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); |
| 163 } | 158 } |
| 164 | 159 |
| 160 void MDnsAPI::GetValidOnServiceListListeners( |
| 161 const std::string& service_type_filter, |
| 162 std::set<std::string>* extension_ids, |
| 163 std::set<std::string>* service_types) { |
| 164 for (const auto& listener : |
| 165 extensions::EventRouter::Get(browser_context_)->listeners() |
| 166 .GetEventListenersByName(mdns::OnServiceList::kEventName)) { |
| 167 base::DictionaryValue* filter = listener->filter(); |
| 168 |
| 169 std::string service_type; |
| 170 filter->GetStringASCII(kEventFilterServiceTypeKey, &service_type); |
| 171 if (service_type.empty()) |
| 172 continue; |
| 173 |
| 174 // Match service type when filter isn't "" |
| 175 if (!service_type_filter.empty() && service_type_filter != service_type) |
| 176 continue; |
| 177 |
| 178 const Extension* extension = ExtensionRegistry::Get(browser_context_)-> |
| 179 enabled_extensions().GetByID(listener->extension_id()); |
| 180 // Don't listen for services associated only with disabled extensions. |
| 181 if (!extension) |
| 182 continue; |
| 183 |
| 184 // Platform apps may query for all services; other types of extensions are |
| 185 // restricted to a whitelist. |
| 186 if (!extension->is_platform_app() && |
| 187 !IsServiceTypeWhitelisted(service_type)) |
| 188 continue; |
| 189 |
| 190 if (extension_ids) |
| 191 extension_ids->insert(listener->extension_id()); |
| 192 if (service_types) |
| 193 service_types->insert(service_type); |
| 194 } |
| 195 } |
| 196 |
| 197 void MDnsAPI::WriteToConsole(const std::string& service_type, |
| 198 content::ConsoleMessageLevel level, |
| 199 const std::string& message) { |
| 200 // Get all the extensions with an onServiceList listener for a particular |
| 201 // service type. |
| 202 std::set<std::string> extension_ids; |
| 203 GetValidOnServiceListListeners(service_type, |
| 204 &extension_ids, |
| 205 nullptr /* service_types */); |
| 206 |
| 207 std::string logged_message(std::string("[chrome.mdns] ") + message); |
| 208 |
| 209 // Log to the consoles of the background pages for those extensions. |
| 210 for (const std::string& extension_id : extension_ids) { |
| 211 extensions::ExtensionHost* host = |
| 212 extensions::ProcessManager::Get(browser_context_) |
| 213 ->GetBackgroundHostForExtension(extension_id); |
| 214 if (!host) |
| 215 continue; |
| 216 content::RenderViewHost* rvh = host->render_view_host(); |
| 217 if (!rvh) |
| 218 continue; |
| 219 rvh->Send(new ExtensionMsg_AddMessageToConsole( |
| 220 rvh->GetRoutingID(), |
| 221 level, |
| 222 logged_message)); |
| 223 } |
| 224 } |
| 225 |
| 165 } // namespace extensions | 226 } // namespace extensions |
| OLD | NEW |