Home | History | Annotate | Download | only in mdns
      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