15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved. 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file. 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <utility> 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/logging.h" 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/memory/singleton.h" 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/message_loop/message_loop_proxy.h" 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/stl_util.h" 115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/common/local_discovery/service_discovery_client_impl.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/dns/dns_protocol.h" 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/dns/record_rdata.h" 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace local_discovery { 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace { 18424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// TODO(noamsml): Make this configurable through the LocalDomainResolver 19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// interface. 20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const int kLocalDomainSecondAddressTimeoutMs = 100; 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kInitialRequeryTimeSeconds = 1; 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kMaxRequeryTimeSeconds = 2; // Time for last requery 24424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 25424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochServiceDiscoveryClientImpl::ServiceDiscoveryClientImpl( 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsClient* mdns_client) : mdns_client_(mdns_client) { 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochServiceDiscoveryClientImpl::~ServiceDiscoveryClientImpl() { 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochscoped_ptr<ServiceWatcher> ServiceDiscoveryClientImpl::CreateServiceWatcher( 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& service_type, 357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const ServiceWatcher::UpdatedCallback& callback) { 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return scoped_ptr<ServiceWatcher>(new ServiceWatcherImpl( 3768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) service_type, callback, mdns_client_)); 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochscoped_ptr<ServiceResolver> ServiceDiscoveryClientImpl::CreateServiceResolver( 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& service_name, 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const ServiceResolver::ResolveCompleteCallback& callback) { 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return scoped_ptr<ServiceResolver>(new ServiceResolverImpl( 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch service_name, callback, mdns_client_)); 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 47a3f7b4e666c476898878fa745f637129375cd889Ben Murdochscoped_ptr<LocalDomainResolver> 48a3f7b4e666c476898878fa745f637129375cd889Ben MurdochServiceDiscoveryClientImpl::CreateLocalDomainResolver( 49a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const std::string& domain, 50a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch net::AddressFamily address_family, 51a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const LocalDomainResolver::IPAddressCallback& callback) { 52a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return scoped_ptr<LocalDomainResolver>(new LocalDomainResolverImpl( 53a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch domain, address_family, callback, mdns_client_)); 54a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 55a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochServiceWatcherImpl::ServiceWatcherImpl( 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& service_type, 587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const ServiceWatcher::UpdatedCallback& callback, 59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsClient* mdns_client) 607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch : service_type_(service_type), callback_(callback), started_(false), 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) actively_refresh_services_(false), mdns_client_(mdns_client) { 62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ServiceWatcherImpl::Start() { 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(!started_); 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch listener_ = mdns_client_->CreateListener( 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::dns_protocol::kTypePTR, service_type_, this); 687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch started_ = listener_->Start(); 697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (started_) 707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ReadCachedServices(); 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochServiceWatcherImpl::~ServiceWatcherImpl() { 74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceWatcherImpl::DiscoverNewServices(bool force_update) { 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(started_); 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (force_update) 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch services_.clear(); 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SendQuery(kInitialRequeryTimeSeconds, force_update); 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ServiceWatcherImpl::SetActivelyRefreshServices( 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool actively_refresh_services) { 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(started_); 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) actively_refresh_services_ = actively_refresh_services; 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (ServiceListenersMap::iterator i = services_.begin(); 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) i != services_.end(); i++) { 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) i->second->SetActiveRefresh(actively_refresh_services); 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceWatcherImpl::ReadCachedServices() { 95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(started_); 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CreateTransaction(false /*network*/, true /*cache*/, false /*force refresh*/, 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch &transaction_cache_); 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ServiceWatcherImpl::CreateTransaction( 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool network, bool cache, bool force_refresh, 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_ptr<net::MDnsTransaction>* transaction) { 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int transaction_flags = 0; 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (network) 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch transaction_flags |= net::MDnsTransaction::QUERY_NETWORK; 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (cache) 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch transaction_flags |= net::MDnsTransaction::QUERY_CACHE; 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // TODO(noamsml): Add flag for force_refresh when supported. 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (transaction_flags) { 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *transaction = mdns_client_->CreateTransaction( 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::dns_protocol::kTypePTR, service_type_, transaction_flags, 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(&ServiceWatcherImpl::OnTransactionResponse, 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Unretained(this), transaction)); 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return (*transaction)->Start(); 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstd::string ServiceWatcherImpl::GetServiceType() const { 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return listener_->GetName(); 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceWatcherImpl::OnRecordUpdate( 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsListener::UpdateType update, 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::RecordParsed* record) { 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(started_); 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (record->type() == net::dns_protocol::kTypePTR) { 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(record->name() == GetServiceType()); 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::PtrRecordRdata* rdata = record->rdata<net::PtrRecordRdata>(); 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch switch (update) { 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case net::MDnsListener::RECORD_ADDED: 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AddService(rdata->ptrdomain()); 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case net::MDnsListener::RECORD_CHANGED: 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch NOTREACHED(); 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case net::MDnsListener::RECORD_REMOVED: 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RemovePTR(rdata->ptrdomain()); 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(record->type() == net::dns_protocol::kTypeSRV || 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch record->type() == net::dns_protocol::kTypeTXT); 149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(services_.find(record->name()) != services_.end()); 150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (record->type() == net::dns_protocol::kTypeSRV) { 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (update == net::MDnsListener::RECORD_REMOVED) { 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RemoveSRV(record->name()); 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (update == net::MDnsListener::RECORD_ADDED) { 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AddSRV(record->name()); 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If this is the first time we see an SRV record, do not send 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // an UPDATE_CHANGED. 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (record->type() != net::dns_protocol::kTypeSRV || 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) update != net::MDnsListener::RECORD_ADDED) { 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DeferUpdate(UPDATE_CHANGED, record->name()); 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceWatcherImpl::OnCachePurged() { 169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Not yet implemented. 170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceWatcherImpl::OnTransactionResponse( 173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_ptr<net::MDnsTransaction>* transaction, 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsTransaction::Result result, 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::RecordParsed* record) { 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(started_); 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (result == net::MDnsTransaction::RESULT_RECORD) { 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::PtrRecordRdata* rdata = record->rdata<net::PtrRecordRdata>(); 179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(rdata); 180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AddService(rdata->ptrdomain()); 181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else if (result == net::MDnsTransaction::RESULT_DONE) { 182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch transaction->reset(); 183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Do nothing for NSEC records. It is an error for hosts to broadcast an NSEC 186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // record for PTR records on any name. 187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochServiceWatcherImpl::ServiceListeners::ServiceListeners( 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& service_name, 191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ServiceWatcherImpl* watcher, 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net::MDnsClient* mdns_client) 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : service_name_(service_name), mdns_client_(mdns_client), 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) update_pending_(false), has_ptr_(true), has_srv_(false) { 195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch srv_listener_ = mdns_client->CreateListener( 196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::dns_protocol::kTypeSRV, service_name, watcher); 197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch txt_listener_ = mdns_client->CreateListener( 198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::dns_protocol::kTypeTXT, service_name, watcher); 199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochServiceWatcherImpl::ServiceListeners::~ServiceListeners() { 202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ServiceWatcherImpl::ServiceListeners::Start() { 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!srv_listener_->Start()) 206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return txt_listener_->Start(); 208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ServiceWatcherImpl::ServiceListeners::SetActiveRefresh( 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool active_refresh) { 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) srv_listener_->SetActiveRefresh(active_refresh); 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (active_refresh && !has_srv_) { 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(has_ptr_); 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) srv_transaction_ = mdns_client_->CreateTransaction( 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net::dns_protocol::kTypeSRV, service_name_, 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net::MDnsTransaction::SINGLE_RESULT | 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net::MDnsTransaction::QUERY_CACHE | net::MDnsTransaction::QUERY_NETWORK, 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&ServiceWatcherImpl::ServiceListeners::OnSRVRecord, 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(this))); 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) srv_transaction_->Start(); 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (!active_refresh) { 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) srv_transaction_.reset(); 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ServiceWatcherImpl::ServiceListeners::OnSRVRecord( 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net::MDnsTransaction::Result result, 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const net::RecordParsed* record) { 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) set_has_srv(record != NULL); 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ServiceWatcherImpl::ServiceListeners::set_has_srv(bool has_srv) { 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) has_srv_ = has_srv; 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) srv_transaction_.reset(); 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceWatcherImpl::AddService(const std::string& service) { 241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(started_); 242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::pair<ServiceListenersMap::iterator, bool> found = services_.insert( 2437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch make_pair(service, linked_ptr<ServiceListeners>(NULL))); 2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (found.second) { // Newly inserted. 246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch found.first->second = linked_ptr<ServiceListeners>( 247eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch new ServiceListeners(service, this, mdns_client_)); 248eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool success = found.first->second->Start(); 2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) found.first->second->SetActiveRefresh(actively_refresh_services_); 250eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DeferUpdate(UPDATE_ADDED, service); 251eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(success); 253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) found.first->second->set_has_ptr(true); 2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ServiceWatcherImpl::AddSRV(const std::string& service) { 2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(started_); 2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ServiceListenersMap::iterator found = services_.find(service); 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (found != services_.end()) { 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) found->second->set_has_srv(true); 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceWatcherImpl::DeferUpdate(ServiceWatcher::UpdateType update_type, 268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& service_name) { 269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ServiceListenersMap::iterator found = services_.find(service_name); 270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (found != services_.end() && !found->second->update_pending()) { 272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch found->second->set_update_pending(true); 273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::MessageLoop::current()->PostTask( 274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch FROM_HERE, 275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(&ServiceWatcherImpl::DeliverDeferredUpdate, AsWeakPtr(), 276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch update_type, service_name)); 277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceWatcherImpl::DeliverDeferredUpdate( 281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ServiceWatcher::UpdateType update_type, const std::string& service_name) { 282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ServiceListenersMap::iterator found = services_.find(service_name); 283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (found != services_.end()) { 285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch found->second->set_update_pending(false); 2867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!callback_.is_null()) 2877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch callback_.Run(update_type, service_name); 288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ServiceWatcherImpl::RemovePTR(const std::string& service) { 292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(started_); 2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ServiceListenersMap::iterator found = services_.find(service); 295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (found != services_.end()) { 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) found->second->set_has_ptr(false); 2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!found->second->has_ptr_or_srv()) { 2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) services_.erase(found); 3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!callback_.is_null()) 3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback_.Run(UPDATE_REMOVED, service); 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ServiceWatcherImpl::RemoveSRV(const std::string& service) { 3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(started_); 3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ServiceListenersMap::iterator found = services_.find(service); 3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (found != services_.end()) { 3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) found->second->set_has_srv(false); 3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!found->second->has_ptr_or_srv()) { 3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) services_.erase(found); 3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!callback_.is_null()) 3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback_.Run(UPDATE_REMOVED, service); 3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceWatcherImpl::OnNsecRecord(const std::string& name, 322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch unsigned rrtype) { 323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Do nothing. It is an error for hosts to broadcast an NSEC record for PTR 324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // on any name. 325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ServiceWatcherImpl::ScheduleQuery(int timeout_seconds) { 3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (timeout_seconds <= kMaxRequeryTimeSeconds) { 3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&ServiceWatcherImpl::SendQuery, 3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AsWeakPtr(), 3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) timeout_seconds * 2 /*next_timeout_seconds*/, 3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) false /*force_update*/), 3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeDelta::FromSeconds(timeout_seconds)); 3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ServiceWatcherImpl::SendQuery(int next_timeout_seconds, 3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool force_update) { 3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateTransaction(true /*network*/, false /*cache*/, force_update, 3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &transaction_network_); 3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScheduleQuery(next_timeout_seconds); 3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochServiceResolverImpl::ServiceResolverImpl( 347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& service_name, 348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const ResolveCompleteCallback& callback, 349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsClient* mdns_client) 350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch : service_name_(service_name), callback_(callback), 3517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch metadata_resolved_(false), address_resolved_(false), 3527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch mdns_client_(mdns_client) { 353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 3557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ServiceResolverImpl::StartResolving() { 356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch address_resolved_ = false; 357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch metadata_resolved_ = false; 3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) service_staging_ = ServiceDescription(); 3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) service_staging_.service_name = service_name_; 360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 3617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!CreateTxtTransaction() || !CreateSrvTransaction()) { 3627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch ServiceNotFound(ServiceResolver::STATUS_REQUEST_TIMEOUT); 3637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochServiceResolverImpl::~ServiceResolverImpl() { 367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ServiceResolverImpl::CreateTxtTransaction() { 370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch txt_transaction_ = mdns_client_->CreateTransaction( 371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::dns_protocol::kTypeTXT, service_name_, 372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsTransaction::SINGLE_RESULT | net::MDnsTransaction::QUERY_CACHE | 373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsTransaction::QUERY_NETWORK, 374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(&ServiceResolverImpl::TxtRecordTransactionResponse, 375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AsWeakPtr())); 376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return txt_transaction_->Start(); 377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// TODO(noamsml): quick-resolve for AAAA records. Since A records tend to be in 380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceResolverImpl::CreateATransaction() { 381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch a_transaction_ = mdns_client_->CreateTransaction( 382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::dns_protocol::kTypeA, 3837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch service_staging_.address.host(), 384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsTransaction::SINGLE_RESULT | net::MDnsTransaction::QUERY_CACHE, 385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(&ServiceResolverImpl::ARecordTransactionResponse, 386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AsWeakPtr())); 387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch a_transaction_->Start(); 388eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 389eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ServiceResolverImpl::CreateSrvTransaction() { 391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch srv_transaction_ = mdns_client_->CreateTransaction( 392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::dns_protocol::kTypeSRV, service_name_, 393eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsTransaction::SINGLE_RESULT | net::MDnsTransaction::QUERY_CACHE | 394eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsTransaction::QUERY_NETWORK, 395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(&ServiceResolverImpl::SrvRecordTransactionResponse, 396eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AsWeakPtr())); 397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return srv_transaction_->Start(); 398eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 399eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 400eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstd::string ServiceResolverImpl::GetName() const { 401eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return service_name_; 402eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 403eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 404eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceResolverImpl::SrvRecordTransactionResponse( 405eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsTransaction::Result status, const net::RecordParsed* record) { 406eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch srv_transaction_.reset(); 407eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (status == net::MDnsTransaction::RESULT_RECORD) { 408eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(record); 4097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch service_staging_.address = RecordToAddress(record); 4107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch service_staging_.last_seen = record->time_created(); 411eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CreateATransaction(); 412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 413eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ServiceNotFound(MDnsStatusToRequestStatus(status)); 414eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 415eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 416eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 417eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceResolverImpl::TxtRecordTransactionResponse( 418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsTransaction::Result status, const net::RecordParsed* record) { 419eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch txt_transaction_.reset(); 420eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (status == net::MDnsTransaction::RESULT_RECORD) { 421eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(record); 4227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch service_staging_.metadata = RecordToMetadata(record); 423eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 4247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch service_staging_.metadata = std::vector<std::string>(); 425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 426eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 427eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch metadata_resolved_ = true; 428eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AlertCallbackIfReady(); 429eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 430eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 431eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceResolverImpl::ARecordTransactionResponse( 432eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsTransaction::Result status, const net::RecordParsed* record) { 433eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch a_transaction_.reset(); 434eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 435eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (status == net::MDnsTransaction::RESULT_RECORD) { 436eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(record); 4377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch service_staging_.ip_address = RecordToIPAddress(record); 438eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 4397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch service_staging_.ip_address = net::IPAddressNumber(); 440eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 441eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 442eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch address_resolved_ = true; 443eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AlertCallbackIfReady(); 444eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 445eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 446eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceResolverImpl::AlertCallbackIfReady() { 447eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (metadata_resolved_ && address_resolved_) { 448eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch txt_transaction_.reset(); 449eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch srv_transaction_.reset(); 450eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch a_transaction_.reset(); 4517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!callback_.is_null()) 4527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch callback_.Run(STATUS_SUCCESS, service_staging_); 453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 454eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 455eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 456eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ServiceResolverImpl::ServiceNotFound( 457eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ServiceResolver::RequestStatus status) { 458eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch txt_transaction_.reset(); 459eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch srv_transaction_.reset(); 460eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch a_transaction_.reset(); 4617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (!callback_.is_null()) 4627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch callback_.Run(status, ServiceDescription()); 463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 464eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochServiceResolver::RequestStatus ServiceResolverImpl::MDnsStatusToRequestStatus( 466eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch net::MDnsTransaction::Result status) const { 467eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch switch (status) { 468eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case net::MDnsTransaction::RESULT_RECORD: 469eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return ServiceResolver::STATUS_SUCCESS; 470eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case net::MDnsTransaction::RESULT_NO_RESULTS: 471eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return ServiceResolver::STATUS_REQUEST_TIMEOUT; 472eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case net::MDnsTransaction::RESULT_NSEC: 473eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return ServiceResolver::STATUS_KNOWN_NONEXISTENT; 474eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case net::MDnsTransaction::RESULT_DONE: // Pass through. 475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch default: 476eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch NOTREACHED(); 477eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return ServiceResolver::STATUS_REQUEST_TIMEOUT; 478eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 479eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 480eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 481eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst std::vector<std::string>& ServiceResolverImpl::RecordToMetadata( 482eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::RecordParsed* record) const { 483eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(record->type() == net::dns_protocol::kTypeTXT); 484eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::TxtRecordRdata* txt_rdata = record->rdata<net::TxtRecordRdata>(); 485eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(txt_rdata); 486eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return txt_rdata->texts(); 487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnet::HostPortPair ServiceResolverImpl::RecordToAddress( 490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::RecordParsed* record) const { 491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(record->type() == net::dns_protocol::kTypeSRV); 492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::SrvRecordRdata* srv_rdata = record->rdata<net::SrvRecordRdata>(); 493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(srv_rdata); 494eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return net::HostPortPair(srv_rdata->target(), srv_rdata->port()); 495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 496eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst net::IPAddressNumber& ServiceResolverImpl::RecordToIPAddress( 498eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::RecordParsed* record) const { 499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(record->type() == net::dns_protocol::kTypeA); 500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const net::ARecordRdata* a_rdata = record->rdata<net::ARecordRdata>(); 501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(a_rdata); 502eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return a_rdata->address(); 503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 504eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 505a3f7b4e666c476898878fa745f637129375cd889Ben MurdochLocalDomainResolverImpl::LocalDomainResolverImpl( 506a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const std::string& domain, 507a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch net::AddressFamily address_family, 508a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const IPAddressCallback& callback, 509a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch net::MDnsClient* mdns_client) 510a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch : domain_(domain), address_family_(address_family), callback_(callback), 511424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) transactions_finished_(0), mdns_client_(mdns_client) { 512a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 513a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 514a3f7b4e666c476898878fa745f637129375cd889Ben MurdochLocalDomainResolverImpl::~LocalDomainResolverImpl() { 515424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) timeout_callback_.Cancel(); 516a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 517a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 518a3f7b4e666c476898878fa745f637129375cd889Ben Murdochvoid LocalDomainResolverImpl::Start() { 519a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if (address_family_ == net::ADDRESS_FAMILY_IPV4 || 520a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch address_family_ == net::ADDRESS_FAMILY_UNSPECIFIED) { 521a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch transaction_a_ = CreateTransaction(net::dns_protocol::kTypeA); 522a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch transaction_a_->Start(); 523a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 524a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 525a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if (address_family_ == net::ADDRESS_FAMILY_IPV6 || 526a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch address_family_ == net::ADDRESS_FAMILY_UNSPECIFIED) { 527a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch transaction_aaaa_ = CreateTransaction(net::dns_protocol::kTypeAAAA); 528a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch transaction_aaaa_->Start(); 529a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 530a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 531a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 532a3f7b4e666c476898878fa745f637129375cd889Ben Murdochscoped_ptr<net::MDnsTransaction> LocalDomainResolverImpl::CreateTransaction( 533a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch uint16 type) { 534a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return mdns_client_->CreateTransaction( 535a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch type, domain_, net::MDnsTransaction::SINGLE_RESULT | 536a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch net::MDnsTransaction::QUERY_CACHE | 537a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch net::MDnsTransaction::QUERY_NETWORK, 538a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch base::Bind(&LocalDomainResolverImpl::OnTransactionComplete, 539a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch base::Unretained(this))); 540a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 541a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 542a3f7b4e666c476898878fa745f637129375cd889Ben Murdochvoid LocalDomainResolverImpl::OnTransactionComplete( 543a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch net::MDnsTransaction::Result result, const net::RecordParsed* record) { 544424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) transactions_finished_++; 545a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 546a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if (result == net::MDnsTransaction::RESULT_RECORD) { 547a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if (record->type() == net::dns_protocol::kTypeA) { 548a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const net::ARecordRdata* rdata = record->rdata<net::ARecordRdata>(); 549424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) address_ipv4_ = rdata->address(); 550a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } else { 551a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch DCHECK_EQ(net::dns_protocol::kTypeAAAA, record->type()); 552a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch const net::AAAARecordRdata* rdata = record->rdata<net::AAAARecordRdata>(); 553424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) address_ipv6_ = rdata->address(); 554a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 555a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 556a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 557424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (transactions_finished_ == 1 && 558424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) address_family_ == net::ADDRESS_FAMILY_UNSPECIFIED) { 559424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) timeout_callback_.Reset(base::Bind( 560424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) &LocalDomainResolverImpl::SendResolvedAddresses, 561424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::Unretained(this))); 562424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 563424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 564424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) FROM_HERE, 565424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) timeout_callback_.callback(), 566424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kLocalDomainSecondAddressTimeoutMs)); 567424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } else if (transactions_finished_ == 2 568424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) || address_family_ != net::ADDRESS_FAMILY_UNSPECIFIED) { 569424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) SendResolvedAddresses(); 570424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 571424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 572424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 573424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)bool LocalDomainResolverImpl::IsSuccess() { 574424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return !address_ipv4_.empty() || !address_ipv6_.empty(); 575424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)} 576424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) 577424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void LocalDomainResolverImpl::SendResolvedAddresses() { 578424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) transaction_a_.reset(); 579424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) transaction_aaaa_.reset(); 580424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) timeout_callback_.Cancel(); 581424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) callback_.Run(IsSuccess(), address_ipv4_, address_ipv6_); 582a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 583a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 584eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace local_discovery 585