17d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 27d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 37d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// found in the LICENSE file. 47d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 57d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "net/dns/mdns_client_impl.h" 67d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <queue> 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/bind.h" 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/message_loop/message_loop_proxy.h" 117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/stl_util.h" 127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/time/default_clock.h" 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/time/time.h" 147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "net/base/dns_util.h" 157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "net/base/net_errors.h" 167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "net/base/net_log.h" 177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "net/base/rand_callback.h" 187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "net/dns/dns_protocol.h" 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/dns/record_rdata.h" 207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "net/udp/datagram_socket.h" 217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// TODO(gene): Remove this temporary method of disabling NSEC support once it 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// becomes clear whether this feature should be 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// supported. http://crbug.com/255232 25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#define ENABLE_NSEC 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace net { 287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace { 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const unsigned MDnsTransactionTimeoutSeconds = 3; 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The fractions of the record's original TTL after which an active listener 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// (one that had |SetActiveRefresh(true)| called) will send a query to refresh 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// its cache. This happens both at 85% of the original TTL and again at 95% of 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the original TTL. 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const double kListenerRefreshRatio1 = 0.85; 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const double kListenerRefreshRatio2 = 0.95; 38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void MDnsSocketFactoryImpl::CreateSockets( 42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ScopedVector<DatagramServerSocket>* sockets) { 43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) InterfaceIndexFamilyList interfaces(GetMDnsInterfacesToBind()); 44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (size_t i = 0; i < interfaces.size(); ++i) { 45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(interfaces[i].second == net::ADDRESS_FAMILY_IPV4 || 46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) interfaces[i].second == net::ADDRESS_FAMILY_IPV6); 47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<DatagramServerSocket> socket( 48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndBindMDnsSocket(interfaces[i].second, interfaces[i].first)); 49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (socket) 50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sockets->push_back(socket.release()); 51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)MDnsConnection::SocketHandler::SocketHandler( 55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<DatagramServerSocket> socket, 56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MDnsConnection* connection) 57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : socket_(socket.Pass()), 58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) connection_(connection), 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci response_(dns_protocol::kMaxMulticastSize), 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci send_in_progress_(false) { 617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)MDnsConnection::SocketHandler::~SocketHandler() { 647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int MDnsConnection::SocketHandler::Start() { 67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) IPEndPoint end_point; 68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int rv = socket_->GetLocalAddress(&end_point); 69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (rv != OK) 70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return rv; 71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(end_point.GetFamily() == ADDRESS_FAMILY_IPV4 || 72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) end_point.GetFamily() == ADDRESS_FAMILY_IPV6); 73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) multicast_addr_ = GetMDnsIPEndPoint(end_point.GetFamily()); 747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return DoLoop(0); 757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int MDnsConnection::SocketHandler::DoLoop(int rv) { 787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) do { 797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (rv > 0) 80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) connection_->OnDatagramReceived(&response_, recv_addr_, rv); 817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) rv = socket_->RecvFrom( 83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) response_.io_buffer(), 84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) response_.io_buffer()->size(), 857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) &recv_addr_, 867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::Bind(&MDnsConnection::SocketHandler::OnDatagramReceived, 877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::Unretained(this))); 887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } while (rv > 0); 897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (rv != ERR_IO_PENDING) 917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return rv; 927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return OK; 947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsConnection::SocketHandler::OnDatagramReceived(int rv) { 977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (rv >= OK) 987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) rv = DoLoop(rv); 997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (rv != OK) 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci connection_->PostOnError(this, rv); 1027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MDnsConnection::SocketHandler::Send(const scoped_refptr<IOBuffer>& buffer, 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci unsigned size) { 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (send_in_progress_) { 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci send_queue_.push(std::make_pair(buffer, size)); 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int rv = socket_->SendTo(buffer.get(), 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size, 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci multicast_addr_, 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::Bind(&MDnsConnection::SocketHandler::SendDone, 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::Unretained(this))); 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (rv == ERR_IO_PENDING) { 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci send_in_progress_ = true; 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else if (rv < OK) { 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci connection_->PostOnError(this, rv); 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsConnection::SocketHandler::SendDone(int rv) { 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(send_in_progress_); 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci send_in_progress_ = false; 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (rv != OK) 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci connection_->PostOnError(this, rv); 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci while (!send_in_progress_ && !send_queue_.empty()) { 1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::pair<scoped_refptr<IOBuffer>, unsigned> buffer = send_queue_.front(); 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci send_queue_.pop(); 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Send(buffer.first, buffer.second); 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMDnsConnection::MDnsConnection(MDnsConnection::Delegate* delegate) 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : delegate_(delegate), weak_ptr_factory_(this) { 1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)MDnsConnection::~MDnsConnection() { 1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool MDnsConnection::Init(MDnsSocketFactory* socket_factory) { 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ScopedVector<DatagramServerSocket> sockets; 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_factory->CreateSockets(&sockets); 14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (size_t i = 0; i < sockets.size(); ++i) { 146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_handlers_.push_back( 147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new MDnsConnection::SocketHandler(make_scoped_ptr(sockets[i]), this)); 14868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sockets.weak_clear(); 15068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 15158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // All unbound sockets need to be bound before processing untrusted input. 15258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // This is done for security reasons, so that an attacker can't get an unbound 15358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // socket. 15468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) for (size_t i = 0; i < socket_handlers_.size();) { 1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int rv = socket_handlers_[i]->Start(); 1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (rv != OK) { 15768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) socket_handlers_.erase(socket_handlers_.begin() + i); 1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) VLOG(1) << "Start failed, socket=" << i << ", error=" << rv; 15968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } else { 16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ++i; 16168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 16268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) VLOG(1) << "Sockets ready:" << socket_handlers_.size(); 16468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return !socket_handlers_.empty(); 1657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MDnsConnection::Send(const scoped_refptr<IOBuffer>& buffer, 1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci unsigned size) { 1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t i = 0; i < socket_handlers_.size(); ++i) 1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci socket_handlers_[i]->Send(buffer, size); 1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MDnsConnection::PostOnError(SocketHandler* loop, int rv) { 1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "Socket error. id=" 1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << std::find(socket_handlers_.begin(), socket_handlers_.end(), loop) - 1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci socket_handlers_.begin() << ", error=" << rv; 1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Post to allow deletion of this object by delegate. 1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::MessageLoop::current()->PostTask( 1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FROM_HERE, 1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::Bind(&MDnsConnection::OnError, weak_ptr_factory_.GetWeakPtr(), rv)); 1817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MDnsConnection::OnError(int rv) { 1847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // TODO(noamsml): Specific handling of intermittent errors that can be handled 1857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // in the connection. 1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci delegate_->OnConnectionError(rv); 1877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsConnection::OnDatagramReceived( 1907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DnsResponse* response, 1917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const IPEndPoint& recv_addr, 1927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) int bytes_read) { 1937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // TODO(noamsml): More sophisticated error handling. 1947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK_GT(bytes_read, 0); 1957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) delegate_->HandlePacket(response, bytes_read); 1967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 1977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 19868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)MDnsClientImpl::Core::Core(MDnsClientImpl* client) 19968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) : client_(client), connection_(new MDnsConnection(this)) { 2007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 2017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)MDnsClientImpl::Core::~Core() { 2037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) STLDeleteValues(&listeners_); 2047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 2057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool MDnsClientImpl::Core::Init(MDnsSocketFactory* socket_factory) { 20768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return connection_->Init(socket_factory); 2087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 2097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool MDnsClientImpl::Core::SendQuery(uint16 rrtype, std::string name) { 2117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::string name_dns; 2127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!DNSDomainFromDot(name, &name_dns)) 2137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return false; 2147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DnsQuery query(0, name_dns, rrtype); 2167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) query.set_flags(0); // Remove the RD flag from the query. It is unneeded. 2177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci connection_->Send(query.io_buffer(), query.io_buffer()->size()); 2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return true; 2207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 2217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsClientImpl::Core::HandlePacket(DnsResponse* response, 2237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) int bytes_read) { 2247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) unsigned offset; 2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Note: We store cache keys rather than record pointers to avoid 2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // erroneous behavior in case a packet contains multiple exclusive 2277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // records with the same type and name. 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::map<MDnsCache::Key, MDnsCache::UpdateType> update_keys; 2297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!response->InitParseWithoutQuery(bytes_read)) { 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "Could not understand an mDNS packet."; 2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return; // Message is unreadable. 2337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 2347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // TODO(noamsml): duplicate query suppression. 2367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!(response->flags() & dns_protocol::kFlagResponse)) 2377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return; // Message is a query. ignore it. 2387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DnsRecordParser parser = response->Parser(); 2407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) unsigned answer_count = response->answer_count() + 2417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) response->additional_answer_count(); 2427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) for (unsigned i = 0; i < answer_count; i++) { 2447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) offset = parser.GetOffset(); 2457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) scoped_ptr<const RecordParsed> record = RecordParsed::CreateFrom( 2467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) &parser, base::Time::Now()); 2477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!record) { 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "Could not understand an mDNS record."; 2507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (offset == parser.GetOffset()) { 252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "Abandoned parsing the rest of the packet."; 2537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return; // The parser did not advance, abort reading the packet. 2547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } else { 2557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) continue; // We may be able to extract other records from the packet. 2567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 2577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 2587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if ((record->klass() & dns_protocol::kMDnsClassMask) != 2607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) dns_protocol::kClassIN) { 261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DVLOG(1) << "Received an mDNS record with non-IN class. Ignoring."; 2627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) continue; // Ignore all records not in the IN class. 2637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 2647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) MDnsCache::Key update_key = MDnsCache::Key::CreateFor(record.get()); 2667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) MDnsCache::UpdateType update = cache_.UpdateDnsRecord(record.Pass()); 2677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Cleanup time may have changed. 2697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ScheduleCleanup(cache_.next_expiration()); 2707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) update_keys.insert(std::make_pair(update_key, update)); 2727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 2737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (std::map<MDnsCache::Key, MDnsCache::UpdateType>::iterator i = 2757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) update_keys.begin(); i != update_keys.end(); i++) { 2767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const RecordParsed* record = cache_.LookupKey(i->first); 277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!record) 278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch continue; 279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (record->type() == dns_protocol::kTypeNSEC) { 281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(ENABLE_NSEC) 282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch NotifyNsecRecord(record); 283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif 284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AlertListeners(i->second, ListenerKey(record->name(), record->type()), 2867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) record); 2877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 2887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 2897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 2907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MDnsClientImpl::Core::NotifyNsecRecord(const RecordParsed* record) { 292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK_EQ(dns_protocol::kTypeNSEC, record->type()); 293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const NsecRecordRdata* rdata = record->rdata<NsecRecordRdata>(); 294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(rdata); 295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Remove all cached records matching the nonexistent RR types. 297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::vector<const RecordParsed*> records_to_remove; 298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch cache_.FindDnsRecords(0, record->name(), &records_to_remove, 300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Time::Now()); 301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (std::vector<const RecordParsed*>::iterator i = records_to_remove.begin(); 303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch i != records_to_remove.end(); i++) { 304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if ((*i)->type() == dns_protocol::kTypeNSEC) 305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch continue; 306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!rdata->GetBit((*i)->type())) { 307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_ptr<const RecordParsed> record_removed = cache_.RemoveRecord((*i)); 308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(record_removed); 309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch OnRecordRemoved(record_removed.get()); 310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Alert all listeners waiting for the nonexistent RR types. 314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ListenerMap::iterator i = 315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch listeners_.upper_bound(ListenerKey(record->name(), 0)); 316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (; i != listeners_.end() && i->first.first == record->name(); i++) { 317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!rdata->GetBit(i->first.second)) { 318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch FOR_EACH_OBSERVER(MDnsListenerImpl, *i->second, AlertNsecRecord()); 319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 3237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsClientImpl::Core::OnConnectionError(int error) { 3247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // TODO(noamsml): On connection error, recreate connection and flush cache. 3257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 3267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsClientImpl::Core::AlertListeners( 3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) MDnsCache::UpdateType update_type, 3297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const ListenerKey& key, 3307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const RecordParsed* record) { 3317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ListenerMap::iterator listener_map_iterator = listeners_.find(key); 3327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (listener_map_iterator == listeners_.end()) return; 3337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) FOR_EACH_OBSERVER(MDnsListenerImpl, *listener_map_iterator->second, 3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HandleRecordUpdate(update_type, record)); 3367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 3377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsClientImpl::Core::AddListener( 3397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) MDnsListenerImpl* listener) { 340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ListenerKey key(listener->GetName(), listener->GetType()); 3417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::pair<ListenerMap::iterator, bool> observer_insert_result = 3427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) listeners_.insert( 3437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) make_pair(key, static_cast<ObserverList<MDnsListenerImpl>*>(NULL))); 3447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // If an equivalent key does not exist, actually create the observer list. 3467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (observer_insert_result.second) 3477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) observer_insert_result.first->second = new ObserverList<MDnsListenerImpl>(); 3487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ObserverList<MDnsListenerImpl>* observer_list = 3507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) observer_insert_result.first->second; 3517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) observer_list->AddObserver(listener); 3537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 3547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsClientImpl::Core::RemoveListener(MDnsListenerImpl* listener) { 356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ListenerKey key(listener->GetName(), listener->GetType()); 3577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ListenerMap::iterator observer_list_iterator = listeners_.find(key); 3587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(observer_list_iterator != listeners_.end()); 3607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(observer_list_iterator->second->HasObserver(listener)); 3617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) observer_list_iterator->second->RemoveObserver(listener); 3637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Remove the observer list from the map if it is empty 365424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (!observer_list_iterator->second->might_have_observers()) { 366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Schedule the actual removal for later in case the listener removal 367eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // happens while iterating over the observer list. 368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::MessageLoop::current()->PostTask( 369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch FROM_HERE, base::Bind( 370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch &MDnsClientImpl::Core::CleanupObserverList, AsWeakPtr(), key)); 371eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 372eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 374eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MDnsClientImpl::Core::CleanupObserverList(const ListenerKey& key) { 375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ListenerMap::iterator found = listeners_.find(key); 376424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (found != listeners_.end() && !found->second->might_have_observers()) { 377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch delete found->second; 378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch listeners_.erase(found); 3797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 3807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 3817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsClientImpl::Core::ScheduleCleanup(base::Time cleanup) { 3837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Cleanup is already scheduled, no need to do anything. 3847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (cleanup == scheduled_cleanup_) return; 3857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) scheduled_cleanup_ = cleanup; 3867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // This cancels the previously scheduled cleanup. 3887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) cleanup_callback_.Reset(base::Bind( 3897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) &MDnsClientImpl::Core::DoCleanup, base::Unretained(this))); 3907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // If |cleanup| is empty, then no cleanup necessary. 3927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (cleanup != base::Time()) { 3937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 3947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) FROM_HERE, 3957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) cleanup_callback_.callback(), 3967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) cleanup - base::Time::Now()); 3977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 3987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 3997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsClientImpl::Core::DoCleanup() { 4017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) cache_.CleanupRecords(base::Time::Now(), base::Bind( 4027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) &MDnsClientImpl::Core::OnRecordRemoved, base::Unretained(this))); 4037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ScheduleCleanup(cache_.next_expiration()); 4057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsClientImpl::Core::OnRecordRemoved( 4087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const RecordParsed* record) { 4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AlertListeners(MDnsCache::RecordRemoved, 410eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ListenerKey(record->name(), record->type()), record); 4117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsClientImpl::Core::QueryCache( 4147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) uint16 rrtype, const std::string& name, 4157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::vector<const RecordParsed*>* records) const { 4167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) cache_.FindDnsRecords(rrtype, name, records, base::Time::Now()); 4177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)MDnsClientImpl::MDnsClientImpl() { 4207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)MDnsClientImpl::~MDnsClientImpl() { 4237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 425a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) { 426eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(!core_.get()); 42768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) core_.reset(new Core(this)); 428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!core_->Init(socket_factory)) { 429eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch core_.reset(); 430eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 4317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 4327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return true; 4337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 435eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MDnsClientImpl::StopListening() { 436eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch core_.reset(); 4377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 439eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool MDnsClientImpl::IsListening() const { 4407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return core_.get() != NULL; 4417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)scoped_ptr<MDnsListener> MDnsClientImpl::CreateListener( 4447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) uint16 rrtype, 4457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const std::string& name, 4467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) MDnsListener::Delegate* delegate) { 4477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return scoped_ptr<net::MDnsListener>( 4487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) new MDnsListenerImpl(rrtype, name, delegate, this)); 4497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)scoped_ptr<MDnsTransaction> MDnsClientImpl::CreateTransaction( 4527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) uint16 rrtype, 4537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const std::string& name, 4547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) int flags, 4557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const MDnsTransaction::ResultCallback& callback) { 4567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return scoped_ptr<MDnsTransaction>( 4577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) new MDnsTransactionImpl(rrtype, name, flags, callback, this)); 4587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)MDnsListenerImpl::MDnsListenerImpl( 4617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) uint16 rrtype, 4627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const std::string& name, 4637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) MDnsListener::Delegate* delegate, 4647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) MDnsClientImpl* client) 4657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) : rrtype_(rrtype), name_(name), client_(client), delegate_(delegate), 4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) started_(false), active_refresh_(false) { 4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MDnsListenerImpl::~MDnsListenerImpl() { 4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (started_) { 4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(client_->core()); 4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) client_->core()->RemoveListener(this); 4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool MDnsListenerImpl::Start() { 4777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(!started_); 4787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) started_ = true; 4807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(client_->core()); 4827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) client_->core()->AddListener(this); 4837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return true; 4857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MDnsListenerImpl::SetActiveRefresh(bool active_refresh) { 4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) active_refresh_ = active_refresh; 4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (started_) { 4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!active_refresh_) { 4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) next_refresh_.Cancel(); 4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else if (last_update_ != base::Time()) { 4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScheduleNextRefresh(); 4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 4977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const std::string& MDnsListenerImpl::GetName() const { 5007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return name_; 5017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 5027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 5037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)uint16 MDnsListenerImpl::GetType() const { 5047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return rrtype_; 5057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 5067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MDnsListenerImpl::HandleRecordUpdate(MDnsCache::UpdateType update_type, 5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const RecordParsed* record) { 5097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(started_); 5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (update_type != MDnsCache::RecordRemoved) { 5125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ttl_ = record->ttl(); 5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) last_update_ = record->time_created(); 5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScheduleNextRefresh(); 5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (update_type != MDnsCache::NoChange) { 5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) MDnsListener::UpdateType update_external; 5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) switch (update_type) { 5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case MDnsCache::RecordAdded: 5235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) update_external = MDnsListener::RECORD_ADDED; 5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case MDnsCache::RecordChanged: 5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) update_external = MDnsListener::RECORD_CHANGED; 5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case MDnsCache::RecordRemoved: 5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) update_external = MDnsListener::RECORD_REMOVED; 5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case MDnsCache::NoChange: 5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) default: 5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NOTREACHED(); 5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Dummy assignment to suppress compiler warning. 5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) update_external = MDnsListener::RECORD_CHANGED; 5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delegate_->OnRecordUpdate(update_external, record); 5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 5427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 543eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MDnsListenerImpl::AlertNsecRecord() { 544eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(started_); 545eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch delegate_->OnNsecRecord(name_, rrtype_); 546eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 547eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MDnsListenerImpl::ScheduleNextRefresh() { 5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(last_update_ != base::Time()); 5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!active_refresh_) 5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // A zero TTL is a goodbye packet and should not be refreshed. 5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (ttl_ == 0) { 5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) next_refresh_.Cancel(); 5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) next_refresh_.Reset(base::Bind(&MDnsListenerImpl::DoRefresh, 5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AsWeakPtr())); 5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Schedule refreshes at both 85% and 95% of the original TTL. These will both 5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // be canceled and rescheduled if the record's TTL is updated due to a 5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // response being received. 5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Time next_refresh1 = last_update_ + base::TimeDelta::FromMilliseconds( 5671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static_cast<int>(base::Time::kMillisecondsPerSecond * 5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kListenerRefreshRatio1 * ttl_)); 5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Time next_refresh2 = last_update_ + base::TimeDelta::FromMilliseconds( 5711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static_cast<int>(base::Time::kMillisecondsPerSecond * 5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kListenerRefreshRatio2 * ttl_)); 5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) next_refresh_.callback(), 5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) next_refresh1 - base::Time::Now()); 5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) next_refresh_.callback(), 5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) next_refresh2 - base::Time::Now()); 5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MDnsListenerImpl::DoRefresh() { 5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) client_->core()->SendQuery(rrtype_, name_); 5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)MDnsTransactionImpl::MDnsTransactionImpl( 5907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) uint16 rrtype, 5917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const std::string& name, 5927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) int flags, 5937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const MDnsTransaction::ResultCallback& callback, 5947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) MDnsClientImpl* client) 5957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) : rrtype_(rrtype), name_(name), callback_(callback), client_(client), 5967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) started_(false), flags_(flags) { 5977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK((flags_ & MDnsTransaction::FLAG_MASK) == flags_); 5987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(flags_ & MDnsTransaction::QUERY_CACHE || 5997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) flags_ & MDnsTransaction::QUERY_NETWORK); 6007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 6017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)MDnsTransactionImpl::~MDnsTransactionImpl() { 6037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) timeout_.Cancel(); 6047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 6057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool MDnsTransactionImpl::Start() { 6077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(!started_); 6087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) started_ = true; 6097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 610eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::WeakPtr<MDnsTransactionImpl> weak_this = AsWeakPtr(); 6117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (flags_ & MDnsTransaction::QUERY_CACHE) { 612eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ServeRecordsFromCache(); 6137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 614eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!weak_this || !is_active()) return true; 615eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 6167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 617eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (flags_ & MDnsTransaction::QUERY_NETWORK) { 618eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return QueryAndListen(); 6197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 6207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 621eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // If this is a cache only query, signal that the transaction is over 622eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // immediately. 623eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SignalTransactionOver(); 6247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return true; 6257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 6267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)const std::string& MDnsTransactionImpl::GetName() const { 6287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return name_; 6297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 6307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)uint16 MDnsTransactionImpl::GetType() const { 6327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return rrtype_; 6337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 6347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsTransactionImpl::CacheRecordFound(const RecordParsed* record) { 6367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(started_); 6377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) OnRecordUpdate(MDnsListener::RECORD_ADDED, record); 6387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 6397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsTransactionImpl::TriggerCallback(MDnsTransaction::Result result, 6417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const RecordParsed* record) { 6427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(started_); 6437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!is_active()) return; 6447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Ensure callback is run after touching all class state, so that 6467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // the callback can delete the transaction. 6477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) MDnsTransaction::ResultCallback callback = callback_; 6487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Reset the transaction if it expects a single result, or if the result 650eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // is a final one (everything except for a record). 651eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (flags_ & MDnsTransaction::SINGLE_RESULT || 652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch result != MDnsTransaction::RESULT_RECORD) { 6537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) Reset(); 654eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 6557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) callback.Run(result, record); 6577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 6587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsTransactionImpl::Reset() { 6607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) callback_.Reset(); 6617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) listener_.reset(); 6627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) timeout_.Cancel(); 6637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 6647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsTransactionImpl::OnRecordUpdate(MDnsListener::UpdateType update, 6667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const RecordParsed* record) { 6677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(started_); 6687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (update == MDnsListener::RECORD_ADDED || 6697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) update == MDnsListener::RECORD_CHANGED) 6707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) TriggerCallback(MDnsTransaction::RESULT_RECORD, record); 6717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 6727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 6737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsTransactionImpl::SignalTransactionOver() { 6747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(started_); 6757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (flags_ & MDnsTransaction::SINGLE_RESULT) { 6767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) TriggerCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL); 6777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } else { 6787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) TriggerCallback(MDnsTransaction::RESULT_DONE, NULL); 6797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 680eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 681eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 682eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MDnsTransactionImpl::ServeRecordsFromCache() { 683eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::vector<const RecordParsed*> records; 684eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::WeakPtr<MDnsTransactionImpl> weak_this = AsWeakPtr(); 685eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 686eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (client_->core()) { 687eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch client_->core()->QueryCache(rrtype_, name_, &records); 688eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (std::vector<const RecordParsed*>::iterator i = records.begin(); 689eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch i != records.end() && weak_this; ++i) { 690bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch weak_this->TriggerCallback(MDnsTransaction::RESULT_RECORD, *i); 691eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 6927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 693eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(ENABLE_NSEC) 694eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (records.empty()) { 695eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(weak_this); 696eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch client_->core()->QueryCache(dns_protocol::kTypeNSEC, name_, &records); 697eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!records.empty()) { 698eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const NsecRecordRdata* rdata = 699eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch records.front()->rdata<NsecRecordRdata>(); 700eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(rdata); 701eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!rdata->GetBit(rrtype_)) 702eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch weak_this->TriggerCallback(MDnsTransaction::RESULT_NSEC, NULL); 703eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 704eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 705eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif 7067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 7077d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 7087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 709eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool MDnsTransactionImpl::QueryAndListen() { 710eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch listener_ = client_->CreateListener(rrtype_, name_, this); 711eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!listener_->Start()) 712eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 713eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 714eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(client_->core()); 715eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!client_->core()->SendQuery(rrtype_, name_)) 716eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 717eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 718eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch timeout_.Reset(base::Bind(&MDnsTransactionImpl::SignalTransactionOver, 719eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AsWeakPtr())); 720eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::MessageLoop::current()->PostDelayedTask( 721eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch FROM_HERE, 722eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch timeout_.callback(), 723eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::TimeDelta::FromSeconds(MDnsTransactionTimeoutSeconds)); 724eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 725eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 726eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 727eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) { 729eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch TriggerCallback(RESULT_NSEC, NULL); 7307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 7317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 7327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void MDnsTransactionImpl::OnCachePurged() { 7337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // TODO(noamsml): Cache purge situations not yet implemented 7347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 7357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 7367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} // namespace net 737