// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/local_discovery/service_discovery_device_lister.h" #include #include #include "base/bind.h" #include "base/message_loop/message_loop.h" namespace local_discovery { namespace { #if defined(OS_MACOSX) const int kMacServiceResolvingIntervalSecs = 60; #endif } // namespace ServiceDiscoveryDeviceLister::ServiceDiscoveryDeviceLister( Delegate* delegate, ServiceDiscoveryClient* service_discovery_client, const std::string& service_type) : delegate_(delegate), service_discovery_client_(service_discovery_client), service_type_(service_type), weak_factory_(this) { } ServiceDiscoveryDeviceLister::~ServiceDiscoveryDeviceLister() { } void ServiceDiscoveryDeviceLister::Start() { VLOG(1) << "DeviceListerStart: service_type: " << service_type_; CreateServiceWatcher(); } void ServiceDiscoveryDeviceLister::DiscoverNewDevices(bool force_update) { VLOG(1) << "DiscoverNewDevices: service_type: " << service_type_; service_watcher_->DiscoverNewServices(force_update); } void ServiceDiscoveryDeviceLister::OnServiceUpdated( ServiceWatcher::UpdateType update, const std::string& service_name) { VLOG(1) << "OnServiceUpdated: service_type: " << service_type_ << ", service_name: " << service_name << ", update: " << update; if (update == ServiceWatcher::UPDATE_INVALIDATED) { resolvers_.clear(); CreateServiceWatcher(); delegate_->OnDeviceCacheFlushed(); return; } if (update != ServiceWatcher::UPDATE_REMOVED) { bool added = (update == ServiceWatcher::UPDATE_ADDED); std::pair insert_result = resolvers_.insert(make_pair(service_name, linked_ptr(NULL))); // If there is already a resolver working on this service, don't add one. if (insert_result.second) { VLOG(1) << "Adding resolver for service_name: " << service_name; scoped_ptr resolver = service_discovery_client_->CreateServiceResolver( service_name, base::Bind( &ServiceDiscoveryDeviceLister::OnResolveComplete, weak_factory_.GetWeakPtr(), added, service_name)); insert_result.first->second.reset(resolver.release()); insert_result.first->second->StartResolving(); } else { VLOG(1) << "Resolver already exists, service_name: " << service_name; } } else { delegate_->OnDeviceRemoved(service_name); } } // TODO(noamsml): Update ServiceDiscoveryClient interface to match this. void ServiceDiscoveryDeviceLister::OnResolveComplete( bool added, std::string service_name, ServiceResolver::RequestStatus status, const ServiceDescription& service_description) { VLOG(1) << "OnResolveComplete: service_type: " << service_type_ << ", service_name: " << service_name << ", status: " << status; if (status == ServiceResolver::STATUS_SUCCESS) { delegate_->OnDeviceChanged(added, service_description); #if defined(OS_MACOSX) // On Mac, the Bonjour service does not seem to ever evict a service if a // device is unplugged, so we need to continuously try to resolve the // service to detect non-graceful shutdowns. base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated, weak_factory_.GetWeakPtr(), ServiceWatcher::UPDATE_CHANGED, service_description.service_name), base::TimeDelta::FromSeconds(kMacServiceResolvingIntervalSecs)); #endif } else { // TODO(noamsml): Add retry logic. } resolvers_.erase(service_name); } void ServiceDiscoveryDeviceLister::CreateServiceWatcher() { service_watcher_ = service_discovery_client_->CreateServiceWatcher( service_type_, base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated, weak_factory_.GetWeakPtr())); service_watcher_->Start(); } } // namespace local_discovery