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/local_discovery/service_discovery_device_lister.h" 6 7#include <utility> 8#include <vector> 9 10#include "base/bind.h" 11#include "base/message_loop/message_loop.h" 12 13namespace local_discovery { 14 15namespace { 16#if defined(OS_MACOSX) 17const int kMacServiceResolvingIntervalSecs = 60; 18#endif 19} // namespace 20 21ServiceDiscoveryDeviceLister::ServiceDiscoveryDeviceLister( 22 Delegate* delegate, 23 ServiceDiscoveryClient* service_discovery_client, 24 const std::string& service_type) 25 : delegate_(delegate), 26 service_discovery_client_(service_discovery_client), 27 service_type_(service_type), 28 weak_factory_(this) { 29} 30 31ServiceDiscoveryDeviceLister::~ServiceDiscoveryDeviceLister() { 32} 33 34void ServiceDiscoveryDeviceLister::Start() { 35 VLOG(1) << "DeviceListerStart: service_type: " << service_type_; 36 CreateServiceWatcher(); 37} 38 39void ServiceDiscoveryDeviceLister::DiscoverNewDevices(bool force_update) { 40 VLOG(1) << "DiscoverNewDevices: service_type: " << service_type_; 41 service_watcher_->DiscoverNewServices(force_update); 42} 43 44void ServiceDiscoveryDeviceLister::OnServiceUpdated( 45 ServiceWatcher::UpdateType update, 46 const std::string& service_name) { 47 VLOG(1) << "OnServiceUpdated: service_type: " << service_type_ 48 << ", service_name: " << service_name 49 << ", update: " << update; 50 if (update == ServiceWatcher::UPDATE_INVALIDATED) { 51 resolvers_.clear(); 52 CreateServiceWatcher(); 53 54 delegate_->OnDeviceCacheFlushed(); 55 return; 56 } 57 58 if (update != ServiceWatcher::UPDATE_REMOVED) { 59 bool added = (update == ServiceWatcher::UPDATE_ADDED); 60 std::pair<ServiceResolverMap::iterator, bool> insert_result = 61 resolvers_.insert(make_pair(service_name, 62 linked_ptr<ServiceResolver>(NULL))); 63 64 // If there is already a resolver working on this service, don't add one. 65 if (insert_result.second) { 66 VLOG(1) << "Adding resolver for service_name: " << service_name; 67 scoped_ptr<ServiceResolver> resolver = 68 service_discovery_client_->CreateServiceResolver( 69 service_name, base::Bind( 70 &ServiceDiscoveryDeviceLister::OnResolveComplete, 71 weak_factory_.GetWeakPtr(), 72 added, 73 service_name)); 74 75 insert_result.first->second.reset(resolver.release()); 76 insert_result.first->second->StartResolving(); 77 } else { 78 VLOG(1) << "Resolver already exists, service_name: " << service_name; 79 } 80 } else { 81 delegate_->OnDeviceRemoved(service_name); 82 } 83} 84 85// TODO(noamsml): Update ServiceDiscoveryClient interface to match this. 86void ServiceDiscoveryDeviceLister::OnResolveComplete( 87 bool added, 88 std::string service_name, 89 ServiceResolver::RequestStatus status, 90 const ServiceDescription& service_description) { 91 VLOG(1) << "OnResolveComplete: service_type: " << service_type_ 92 << ", service_name: " << service_name 93 << ", status: " << status; 94 if (status == ServiceResolver::STATUS_SUCCESS) { 95 delegate_->OnDeviceChanged(added, service_description); 96 97#if defined(OS_MACOSX) 98 // On Mac, the Bonjour service does not seem to ever evict a service if a 99 // device is unplugged, so we need to continuously try to resolve the 100 // service to detect non-graceful shutdowns. 101 base::MessageLoop::current()->PostDelayedTask( 102 FROM_HERE, 103 base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated, 104 weak_factory_.GetWeakPtr(), 105 ServiceWatcher::UPDATE_CHANGED, 106 service_description.service_name), 107 base::TimeDelta::FromSeconds(kMacServiceResolvingIntervalSecs)); 108#endif 109 } else { 110 // TODO(noamsml): Add retry logic. 111 } 112 resolvers_.erase(service_name); 113} 114 115void ServiceDiscoveryDeviceLister::CreateServiceWatcher() { 116 service_watcher_ = 117 service_discovery_client_->CreateServiceWatcher( 118 service_type_, 119 base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated, 120 weak_factory_.GetWeakPtr())); 121 service_watcher_->Start(); 122} 123 124} // namespace local_discovery 125