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
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/mdns/mdns_api.h"
9 #include "base/lazy_instance.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/common/extensions/api/mdns.h"
12 #include "extensions/browser/extension_registry.h"
14 namespace extensions
{
16 namespace mdns
= api::mdns
;
20 // Whitelisted mDNS service types.
21 const char kCastServiceType
[] = "_googlecast._tcp.local";
22 const char kPrivetServiceType
[] = "_privet._tcp.local";
23 const char kTestServiceType
[] = "_testing._tcp.local";
25 bool IsServiceTypeWhitelisted(const std::string
& service_type
) {
26 return service_type
== kCastServiceType
||
27 service_type
== kPrivetServiceType
||
28 service_type
== kTestServiceType
;
33 MDnsAPI::MDnsAPI(content::BrowserContext
* context
) : browser_context_(context
) {
34 DCHECK(browser_context_
);
35 extensions::EventRouter
* event_router
= EventRouter::Get(context
);
37 event_router
->RegisterObserver(this, mdns::OnServiceList::kEventName
);
41 if (dns_sd_registry_
.get()) {
42 dns_sd_registry_
->RemoveObserver(this);
47 MDnsAPI
* MDnsAPI::Get(content::BrowserContext
* context
) {
48 return BrowserContextKeyedAPIFactory
<MDnsAPI
>::Get(context
);
51 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<MDnsAPI
> > g_factory
=
52 LAZY_INSTANCE_INITIALIZER
;
55 BrowserContextKeyedAPIFactory
<MDnsAPI
>* MDnsAPI::GetFactoryInstance() {
56 return g_factory
.Pointer();
59 void MDnsAPI::SetDnsSdRegistryForTesting(
60 scoped_ptr
<DnsSdRegistry
> dns_sd_registry
) {
61 dns_sd_registry_
= dns_sd_registry
.Pass();
62 if (dns_sd_registry_
.get())
63 dns_sd_registry_
.get()->AddObserver(this);
66 DnsSdRegistry
* MDnsAPI::dns_sd_registry() {
67 DCHECK(thread_checker_
.CalledOnValidThread());
68 if (!dns_sd_registry_
.get()) {
69 dns_sd_registry_
.reset(new extensions::DnsSdRegistry());
70 dns_sd_registry_
->AddObserver(this);
72 return dns_sd_registry_
.get();
75 void MDnsAPI::OnListenerAdded(const EventListenerInfo
& details
) {
76 DCHECK(thread_checker_
.CalledOnValidThread());
77 UpdateMDnsListeners(details
);
80 void MDnsAPI::OnListenerRemoved(const EventListenerInfo
& details
) {
81 DCHECK(thread_checker_
.CalledOnValidThread());
82 UpdateMDnsListeners(details
);
85 void MDnsAPI::UpdateMDnsListeners(const EventListenerInfo
& details
) {
86 std::set
<std::string
> new_service_types
;
88 // Check all listeners for service type filters.
89 const EventListenerMap::ListenerList
& listeners
=
90 extensions::EventRouter::Get(browser_context_
)
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());
97 std::string filter_value
;
98 filter
->GetStringASCII(kEventFilterServiceTypeKey
, &filter_value
);
99 if (filter_value
.empty())
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.
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
))
114 new_service_types
.insert(filter_value
);
117 // Find all the added and removed service types since last update.
118 std::set
<std::string
> added_service_types
=
119 base::STLSetDifference
<std::set
<std::string
> >(
120 new_service_types
, service_types_
);
121 std::set
<std::string
> removed_service_types
=
122 base::STLSetDifference
<std::set
<std::string
> >(
123 service_types_
, new_service_types
);
125 // Update the registry.
126 DnsSdRegistry
* registry
= dns_sd_registry();
127 for (const auto& srv
: added_service_types
) {
128 registry
->RegisterDnsSdListener(srv
);
130 for (const auto& srv
: removed_service_types
) {
131 registry
->UnregisterDnsSdListener(srv
);
133 service_types_
= new_service_types
;
136 void MDnsAPI::OnDnsSdEvent(const std::string
& service_type
,
137 const DnsSdRegistry::DnsSdServiceList
& services
) {
138 DCHECK(thread_checker_
.CalledOnValidThread());
140 std::vector
<linked_ptr
<mdns::MDnsService
> > args
;
141 for (DnsSdRegistry::DnsSdServiceList::const_iterator it
= services
.begin();
142 it
!= services
.end(); ++it
) {
143 linked_ptr
<mdns::MDnsService
> mdns_service
=
144 make_linked_ptr(new mdns::MDnsService
);
145 mdns_service
->service_name
= (*it
).service_name
;
146 mdns_service
->service_host_port
= (*it
).service_host_port
;
147 mdns_service
->ip_address
= (*it
).ip_address
;
148 mdns_service
->service_data
= (*it
).service_data
;
149 args
.push_back(mdns_service
);
152 scoped_ptr
<base::ListValue
> results
= mdns::OnServiceList::Create(args
);
153 scoped_ptr
<Event
> event(
154 new Event(mdns::OnServiceList::kEventName
, results
.Pass()));
155 event
->restrict_to_browser_context
= browser_context_
;
156 event
->filter_info
.SetServiceType(service_type
);
158 // TODO(justinlin): To avoid having listeners without filters getting all
159 // events, modify API to have this event require filters.
160 // TODO(reddaly): If event isn't on whitelist, ensure it does not get
161 // broadcast to extensions.
162 extensions::EventRouter::Get(browser_context_
)->BroadcastEvent(event
.Pass());
165 } // namespace extensions