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. 4 5 #include "chrome/browser/extensions/api/mdns/mdns_api.h" 6 7 #include <vector> 8 9 #include "base/lazy_instance.h" 10 #include "chrome/browser/extensions/extension_service.h" 11 #include "chrome/common/extensions/api/mdns.h" 12 13 namespace extensions { 14 15 namespace mdns = api::mdns; 16 17 namespace { 18 19 // Whitelisted mDNS service types. 20 const char kCastServiceType[] = "_googlecast._tcp.local"; 21 const char kPrivetServiceType[] = "_privet._tcp.local"; 22 const char kTestServiceType[] = "_testing._tcp.local"; 23 IsServiceTypeWhitelisted(const std::string & service_type)24bool IsServiceTypeWhitelisted(const std::string& service_type) { 25 return service_type == kCastServiceType || 26 service_type == kPrivetServiceType || 27 service_type == kTestServiceType; 28 } 29 30 } // namespace 31 MDnsAPI(content::BrowserContext * context)32MDnsAPI::MDnsAPI(content::BrowserContext* context) : browser_context_(context) { 33 DCHECK(browser_context_); 34 EventRouter::Get(context) 35 ->RegisterObserver(this, mdns::OnServiceList::kEventName); 36 } 37 ~MDnsAPI()38MDnsAPI::~MDnsAPI() { 39 if (dns_sd_registry_.get()) { 40 dns_sd_registry_->RemoveObserver(this); 41 } 42 } 43 44 // static Get(content::BrowserContext * context)45MDnsAPI* MDnsAPI::Get(content::BrowserContext* context) { 46 return BrowserContextKeyedAPIFactory<MDnsAPI>::Get(context); 47 } 48 49 static base::LazyInstance<BrowserContextKeyedAPIFactory<MDnsAPI> > g_factory = 50 LAZY_INSTANCE_INITIALIZER; 51 52 // static GetFactoryInstance()53BrowserContextKeyedAPIFactory<MDnsAPI>* MDnsAPI::GetFactoryInstance() { 54 return g_factory.Pointer(); 55 } 56 SetDnsSdRegistryForTesting(scoped_ptr<DnsSdRegistry> dns_sd_registry)57void MDnsAPI::SetDnsSdRegistryForTesting( 58 scoped_ptr<DnsSdRegistry> dns_sd_registry) { 59 dns_sd_registry_ = dns_sd_registry.Pass(); 60 } 61 dns_sd_registry()62DnsSdRegistry* MDnsAPI::dns_sd_registry() { 63 DCHECK(thread_checker_.CalledOnValidThread()); 64 if (!dns_sd_registry_.get()) { 65 dns_sd_registry_.reset(new extensions::DnsSdRegistry()); 66 dns_sd_registry_->AddObserver(this); 67 } 68 return dns_sd_registry_.get(); 69 } 70 OnListenerAdded(const EventListenerInfo & details)71void MDnsAPI::OnListenerAdded(const EventListenerInfo& details) { 72 DCHECK(thread_checker_.CalledOnValidThread()); 73 UpdateMDnsListeners(details); 74 } 75 OnListenerRemoved(const EventListenerInfo & details)76void MDnsAPI::OnListenerRemoved(const EventListenerInfo& details) { 77 DCHECK(thread_checker_.CalledOnValidThread()); 78 UpdateMDnsListeners(details); 79 } 80 UpdateMDnsListeners(const EventListenerInfo & details)81void MDnsAPI::UpdateMDnsListeners(const EventListenerInfo& details) { 82 std::set<std::string> new_service_types; 83 84 // Check all listeners for service type filers. 85 const EventListenerMap::ListenerList& listeners = 86 extensions::EventRouter::Get(browser_context_) 87 ->listeners() 88 .GetEventListenersByName(details.event_name); 89 for (EventListenerMap::ListenerList::const_iterator it = listeners.begin(); 90 it != listeners.end(); ++it) { 91 base::DictionaryValue* filter = ((*it)->filter()); 92 93 std::string filter_value; 94 filter->GetStringASCII(kEventFilterServiceTypeKey, &filter_value); 95 if (filter_value.empty()) 96 continue; 97 new_service_types.insert(filter_value); 98 } 99 100 // Find all the added and removed service types since last update. 101 std::set<std::string> added_service_types = 102 base::STLSetDifference<std::set<std::string> >( 103 new_service_types, service_types_); 104 std::set<std::string> removed_service_types = 105 base::STLSetDifference<std::set<std::string> >( 106 service_types_, new_service_types); 107 108 // Update the registry. 109 DnsSdRegistry* registry = dns_sd_registry(); 110 for (std::set<std::string>::iterator it = added_service_types.begin(); 111 it != added_service_types.end(); ++it) { 112 if (IsServiceTypeWhitelisted(*it)) 113 registry->RegisterDnsSdListener(*it); 114 } 115 for (std::set<std::string>::iterator it = removed_service_types.begin(); 116 it != removed_service_types.end(); ++it) { 117 if (IsServiceTypeWhitelisted(*it)) 118 registry->UnregisterDnsSdListener(*it); 119 } 120 121 service_types_ = new_service_types; 122 } 123 OnDnsSdEvent(const std::string & service_type,const DnsSdRegistry::DnsSdServiceList & services)124void MDnsAPI::OnDnsSdEvent(const std::string& service_type, 125 const DnsSdRegistry::DnsSdServiceList& services) { 126 DCHECK(thread_checker_.CalledOnValidThread()); 127 128 std::vector<linked_ptr<mdns::MDnsService> > args; 129 for (DnsSdRegistry::DnsSdServiceList::const_iterator it = services.begin(); 130 it != services.end(); ++it) { 131 linked_ptr<mdns::MDnsService> mdns_service = 132 make_linked_ptr(new mdns::MDnsService); 133 mdns_service->service_name = (*it).service_name; 134 mdns_service->service_host_port = (*it).service_host_port; 135 mdns_service->ip_address = (*it).ip_address; 136 mdns_service->service_data = (*it).service_data; 137 args.push_back(mdns_service); 138 } 139 140 scoped_ptr<base::ListValue> results = mdns::OnServiceList::Create(args); 141 scoped_ptr<Event> event( 142 new Event(mdns::OnServiceList::kEventName, results.Pass())); 143 event->restrict_to_browser_context = browser_context_; 144 event->filter_info.SetServiceType(service_type); 145 146 VLOG(1) << "Broadcasting OnServiceList event: " << event.get(); 147 148 // TODO(justinlin): To avoid having listeners without filters getting all 149 // events, modify API to have this event require filters. 150 extensions::EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); 151 } 152 153 } // namespace extensions 154