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