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