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/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 
     24 bool IsServiceTypeWhitelisted(const std::string& service_type) {
     25   return service_type == kCastServiceType ||
     26          service_type == kPrivetServiceType ||
     27          service_type == kTestServiceType;
     28 }
     29 
     30 }  // namespace
     31 
     32 MDnsAPI::MDnsAPI(content::BrowserContext* context) : browser_context_(context) {
     33   DCHECK(browser_context_);
     34   EventRouter::Get(context)
     35       ->RegisterObserver(this, mdns::OnServiceList::kEventName);
     36 }
     37 
     38 MDnsAPI::~MDnsAPI() {
     39   if (dns_sd_registry_.get()) {
     40     dns_sd_registry_->RemoveObserver(this);
     41   }
     42 }
     43 
     44 // static
     45 MDnsAPI* 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
     53 BrowserContextKeyedAPIFactory<MDnsAPI>* MDnsAPI::GetFactoryInstance() {
     54   return g_factory.Pointer();
     55 }
     56 
     57 void MDnsAPI::SetDnsSdRegistryForTesting(
     58     scoped_ptr<DnsSdRegistry> dns_sd_registry) {
     59   dns_sd_registry_ = dns_sd_registry.Pass();
     60 }
     61 
     62 DnsSdRegistry* 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 
     71 void MDnsAPI::OnListenerAdded(const EventListenerInfo& details) {
     72   DCHECK(thread_checker_.CalledOnValidThread());
     73   UpdateMDnsListeners(details);
     74 }
     75 
     76 void MDnsAPI::OnListenerRemoved(const EventListenerInfo& details) {
     77   DCHECK(thread_checker_.CalledOnValidThread());
     78   UpdateMDnsListeners(details);
     79 }
     80 
     81 void 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 
    124 void 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