1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/dns/mdns_client_impl.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <algorithm>
8*6777b538SAndroid Build Coastguard Worker #include <cstdint>
9*6777b538SAndroid Build Coastguard Worker #include <memory>
10*6777b538SAndroid Build Coastguard Worker #include <optional>
11*6777b538SAndroid Build Coastguard Worker #include <utility>
12*6777b538SAndroid Build Coastguard Worker #include <vector>
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker #include "base/containers/fixed_flat_set.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/observer_list.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/task/single_thread_task_runner.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/time/clock.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/time/default_clock.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/timer/timer.h"
26*6777b538SAndroid Build Coastguard Worker #include "net/base/net_errors.h"
27*6777b538SAndroid Build Coastguard Worker #include "net/base/rand_callback.h"
28*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_names_util.h"
29*6777b538SAndroid Build Coastguard Worker #include "net/dns/public/dns_protocol.h"
30*6777b538SAndroid Build Coastguard Worker #include "net/dns/public/util.h"
31*6777b538SAndroid Build Coastguard Worker #include "net/dns/record_rdata.h"
32*6777b538SAndroid Build Coastguard Worker #include "net/socket/datagram_socket.h"
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker // TODO(gene): Remove this temporary method of disabling NSEC support once it
35*6777b538SAndroid Build Coastguard Worker // becomes clear whether this feature should be
36*6777b538SAndroid Build Coastguard Worker // supported. http://crbug.com/255232
37*6777b538SAndroid Build Coastguard Worker #define ENABLE_NSEC
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard Worker namespace net {
40*6777b538SAndroid Build Coastguard Worker
41*6777b538SAndroid Build Coastguard Worker namespace {
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker // The fractions of the record's original TTL after which an active listener
44*6777b538SAndroid Build Coastguard Worker // (one that had |SetActiveRefresh(true)| called) will send a query to refresh
45*6777b538SAndroid Build Coastguard Worker // its cache. This happens both at 85% of the original TTL and again at 95% of
46*6777b538SAndroid Build Coastguard Worker // the original TTL.
47*6777b538SAndroid Build Coastguard Worker const double kListenerRefreshRatio1 = 0.85;
48*6777b538SAndroid Build Coastguard Worker const double kListenerRefreshRatio2 = 0.95;
49*6777b538SAndroid Build Coastguard Worker
50*6777b538SAndroid Build Coastguard Worker // These values are persisted to logs. Entries should not be renumbered and
51*6777b538SAndroid Build Coastguard Worker // numeric values should never be reused.
52*6777b538SAndroid Build Coastguard Worker enum class mdnsQueryType {
53*6777b538SAndroid Build Coastguard Worker kInitial = 0, // Initial mDNS query sent.
54*6777b538SAndroid Build Coastguard Worker kRefresh = 1, // Refresh mDNS query sent.
55*6777b538SAndroid Build Coastguard Worker kMaxValue = kRefresh,
56*6777b538SAndroid Build Coastguard Worker };
57*6777b538SAndroid Build Coastguard Worker
RecordQueryMetric(mdnsQueryType query_type,std::string_view host)58*6777b538SAndroid Build Coastguard Worker void RecordQueryMetric(mdnsQueryType query_type, std::string_view host) {
59*6777b538SAndroid Build Coastguard Worker constexpr auto kPrintScanServices = base::MakeFixedFlatSet<std::string_view>({
60*6777b538SAndroid Build Coastguard Worker "_ipps._tcp.local",
61*6777b538SAndroid Build Coastguard Worker "_ipp._tcp.local",
62*6777b538SAndroid Build Coastguard Worker "_pdl-datastream._tcp.local",
63*6777b538SAndroid Build Coastguard Worker "_printer._tcp.local",
64*6777b538SAndroid Build Coastguard Worker "_print._sub._ipps._tcp.local",
65*6777b538SAndroid Build Coastguard Worker "_print._sub._ipp._tcp.local",
66*6777b538SAndroid Build Coastguard Worker "_scanner._tcp.local",
67*6777b538SAndroid Build Coastguard Worker "_uscans._tcp.local",
68*6777b538SAndroid Build Coastguard Worker "_uscan._tcp.local",
69*6777b538SAndroid Build Coastguard Worker });
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Worker if (host.ends_with("_googlecast._tcp.local")) {
72*6777b538SAndroid Build Coastguard Worker base::UmaHistogramEnumeration("Network.Mdns.Googlecast", query_type);
73*6777b538SAndroid Build Coastguard Worker } else if (base::ranges::any_of(kPrintScanServices,
74*6777b538SAndroid Build Coastguard Worker [&host](std::string_view service) {
75*6777b538SAndroid Build Coastguard Worker return host.ends_with(service);
76*6777b538SAndroid Build Coastguard Worker })) {
77*6777b538SAndroid Build Coastguard Worker base::UmaHistogramEnumeration("Network.Mdns.PrintScan", query_type);
78*6777b538SAndroid Build Coastguard Worker } else {
79*6777b538SAndroid Build Coastguard Worker base::UmaHistogramEnumeration("Network.Mdns.Other", query_type);
80*6777b538SAndroid Build Coastguard Worker }
81*6777b538SAndroid Build Coastguard Worker }
82*6777b538SAndroid Build Coastguard Worker
83*6777b538SAndroid Build Coastguard Worker } // namespace
84*6777b538SAndroid Build Coastguard Worker
CreateSockets(std::vector<std::unique_ptr<DatagramServerSocket>> * sockets)85*6777b538SAndroid Build Coastguard Worker void MDnsSocketFactoryImpl::CreateSockets(
86*6777b538SAndroid Build Coastguard Worker std::vector<std::unique_ptr<DatagramServerSocket>>* sockets) {
87*6777b538SAndroid Build Coastguard Worker InterfaceIndexFamilyList interfaces(GetMDnsInterfacesToBind());
88*6777b538SAndroid Build Coastguard Worker for (const auto& interface : interfaces) {
89*6777b538SAndroid Build Coastguard Worker DCHECK(interface.second == ADDRESS_FAMILY_IPV4 ||
90*6777b538SAndroid Build Coastguard Worker interface.second == ADDRESS_FAMILY_IPV6);
91*6777b538SAndroid Build Coastguard Worker std::unique_ptr<DatagramServerSocket> socket(
92*6777b538SAndroid Build Coastguard Worker CreateAndBindMDnsSocket(interface.second, interface.first, net_log_));
93*6777b538SAndroid Build Coastguard Worker if (socket)
94*6777b538SAndroid Build Coastguard Worker sockets->push_back(std::move(socket));
95*6777b538SAndroid Build Coastguard Worker }
96*6777b538SAndroid Build Coastguard Worker }
97*6777b538SAndroid Build Coastguard Worker
SocketHandler(std::unique_ptr<DatagramServerSocket> socket,MDnsConnection * connection)98*6777b538SAndroid Build Coastguard Worker MDnsConnection::SocketHandler::SocketHandler(
99*6777b538SAndroid Build Coastguard Worker std::unique_ptr<DatagramServerSocket> socket,
100*6777b538SAndroid Build Coastguard Worker MDnsConnection* connection)
101*6777b538SAndroid Build Coastguard Worker : socket_(std::move(socket)),
102*6777b538SAndroid Build Coastguard Worker connection_(connection),
103*6777b538SAndroid Build Coastguard Worker response_(dns_protocol::kMaxMulticastSize) {}
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker MDnsConnection::SocketHandler::~SocketHandler() = default;
106*6777b538SAndroid Build Coastguard Worker
Start()107*6777b538SAndroid Build Coastguard Worker int MDnsConnection::SocketHandler::Start() {
108*6777b538SAndroid Build Coastguard Worker IPEndPoint end_point;
109*6777b538SAndroid Build Coastguard Worker int rv = socket_->GetLocalAddress(&end_point);
110*6777b538SAndroid Build Coastguard Worker if (rv != OK)
111*6777b538SAndroid Build Coastguard Worker return rv;
112*6777b538SAndroid Build Coastguard Worker DCHECK(end_point.GetFamily() == ADDRESS_FAMILY_IPV4 ||
113*6777b538SAndroid Build Coastguard Worker end_point.GetFamily() == ADDRESS_FAMILY_IPV6);
114*6777b538SAndroid Build Coastguard Worker multicast_addr_ = dns_util::GetMdnsGroupEndPoint(end_point.GetFamily());
115*6777b538SAndroid Build Coastguard Worker return DoLoop(0);
116*6777b538SAndroid Build Coastguard Worker }
117*6777b538SAndroid Build Coastguard Worker
DoLoop(int rv)118*6777b538SAndroid Build Coastguard Worker int MDnsConnection::SocketHandler::DoLoop(int rv) {
119*6777b538SAndroid Build Coastguard Worker do {
120*6777b538SAndroid Build Coastguard Worker if (rv > 0)
121*6777b538SAndroid Build Coastguard Worker connection_->OnDatagramReceived(&response_, recv_addr_, rv);
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker rv = socket_->RecvFrom(
124*6777b538SAndroid Build Coastguard Worker response_.io_buffer(), response_.io_buffer_size(), &recv_addr_,
125*6777b538SAndroid Build Coastguard Worker base::BindOnce(&MDnsConnection::SocketHandler::OnDatagramReceived,
126*6777b538SAndroid Build Coastguard Worker base::Unretained(this)));
127*6777b538SAndroid Build Coastguard Worker } while (rv > 0);
128*6777b538SAndroid Build Coastguard Worker
129*6777b538SAndroid Build Coastguard Worker if (rv != ERR_IO_PENDING)
130*6777b538SAndroid Build Coastguard Worker return rv;
131*6777b538SAndroid Build Coastguard Worker
132*6777b538SAndroid Build Coastguard Worker return OK;
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker
OnDatagramReceived(int rv)135*6777b538SAndroid Build Coastguard Worker void MDnsConnection::SocketHandler::OnDatagramReceived(int rv) {
136*6777b538SAndroid Build Coastguard Worker if (rv >= OK)
137*6777b538SAndroid Build Coastguard Worker rv = DoLoop(rv);
138*6777b538SAndroid Build Coastguard Worker
139*6777b538SAndroid Build Coastguard Worker if (rv != OK)
140*6777b538SAndroid Build Coastguard Worker connection_->PostOnError(this, rv);
141*6777b538SAndroid Build Coastguard Worker }
142*6777b538SAndroid Build Coastguard Worker
Send(const scoped_refptr<IOBuffer> & buffer,unsigned size)143*6777b538SAndroid Build Coastguard Worker void MDnsConnection::SocketHandler::Send(const scoped_refptr<IOBuffer>& buffer,
144*6777b538SAndroid Build Coastguard Worker unsigned size) {
145*6777b538SAndroid Build Coastguard Worker if (send_in_progress_) {
146*6777b538SAndroid Build Coastguard Worker send_queue_.emplace(buffer, size);
147*6777b538SAndroid Build Coastguard Worker return;
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker int rv =
150*6777b538SAndroid Build Coastguard Worker socket_->SendTo(buffer.get(), size, multicast_addr_,
151*6777b538SAndroid Build Coastguard Worker base::BindOnce(&MDnsConnection::SocketHandler::SendDone,
152*6777b538SAndroid Build Coastguard Worker base::Unretained(this)));
153*6777b538SAndroid Build Coastguard Worker if (rv == ERR_IO_PENDING) {
154*6777b538SAndroid Build Coastguard Worker send_in_progress_ = true;
155*6777b538SAndroid Build Coastguard Worker } else if (rv < OK) {
156*6777b538SAndroid Build Coastguard Worker connection_->PostOnError(this, rv);
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker }
159*6777b538SAndroid Build Coastguard Worker
SendDone(int rv)160*6777b538SAndroid Build Coastguard Worker void MDnsConnection::SocketHandler::SendDone(int rv) {
161*6777b538SAndroid Build Coastguard Worker DCHECK(send_in_progress_);
162*6777b538SAndroid Build Coastguard Worker send_in_progress_ = false;
163*6777b538SAndroid Build Coastguard Worker if (rv != OK)
164*6777b538SAndroid Build Coastguard Worker connection_->PostOnError(this, rv);
165*6777b538SAndroid Build Coastguard Worker while (!send_in_progress_ && !send_queue_.empty()) {
166*6777b538SAndroid Build Coastguard Worker std::pair<scoped_refptr<IOBuffer>, unsigned> buffer = send_queue_.front();
167*6777b538SAndroid Build Coastguard Worker send_queue_.pop();
168*6777b538SAndroid Build Coastguard Worker Send(buffer.first, buffer.second);
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker }
171*6777b538SAndroid Build Coastguard Worker
MDnsConnection(MDnsConnection::Delegate * delegate)172*6777b538SAndroid Build Coastguard Worker MDnsConnection::MDnsConnection(MDnsConnection::Delegate* delegate)
173*6777b538SAndroid Build Coastguard Worker : delegate_(delegate) {}
174*6777b538SAndroid Build Coastguard Worker
175*6777b538SAndroid Build Coastguard Worker MDnsConnection::~MDnsConnection() = default;
176*6777b538SAndroid Build Coastguard Worker
Init(MDnsSocketFactory * socket_factory)177*6777b538SAndroid Build Coastguard Worker int MDnsConnection::Init(MDnsSocketFactory* socket_factory) {
178*6777b538SAndroid Build Coastguard Worker std::vector<std::unique_ptr<DatagramServerSocket>> sockets;
179*6777b538SAndroid Build Coastguard Worker socket_factory->CreateSockets(&sockets);
180*6777b538SAndroid Build Coastguard Worker
181*6777b538SAndroid Build Coastguard Worker for (std::unique_ptr<DatagramServerSocket>& socket : sockets) {
182*6777b538SAndroid Build Coastguard Worker socket_handlers_.push_back(std::make_unique<MDnsConnection::SocketHandler>(
183*6777b538SAndroid Build Coastguard Worker std::move(socket), this));
184*6777b538SAndroid Build Coastguard Worker }
185*6777b538SAndroid Build Coastguard Worker
186*6777b538SAndroid Build Coastguard Worker // All unbound sockets need to be bound before processing untrusted input.
187*6777b538SAndroid Build Coastguard Worker // This is done for security reasons, so that an attacker can't get an unbound
188*6777b538SAndroid Build Coastguard Worker // socket.
189*6777b538SAndroid Build Coastguard Worker int last_failure = ERR_FAILED;
190*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < socket_handlers_.size();) {
191*6777b538SAndroid Build Coastguard Worker int rv = socket_handlers_[i]->Start();
192*6777b538SAndroid Build Coastguard Worker if (rv != OK) {
193*6777b538SAndroid Build Coastguard Worker last_failure = rv;
194*6777b538SAndroid Build Coastguard Worker socket_handlers_.erase(socket_handlers_.begin() + i);
195*6777b538SAndroid Build Coastguard Worker VLOG(1) << "Start failed, socket=" << i << ", error=" << rv;
196*6777b538SAndroid Build Coastguard Worker } else {
197*6777b538SAndroid Build Coastguard Worker ++i;
198*6777b538SAndroid Build Coastguard Worker }
199*6777b538SAndroid Build Coastguard Worker }
200*6777b538SAndroid Build Coastguard Worker VLOG(1) << "Sockets ready:" << socket_handlers_.size();
201*6777b538SAndroid Build Coastguard Worker DCHECK_NE(ERR_IO_PENDING, last_failure);
202*6777b538SAndroid Build Coastguard Worker return socket_handlers_.empty() ? last_failure : OK;
203*6777b538SAndroid Build Coastguard Worker }
204*6777b538SAndroid Build Coastguard Worker
Send(const scoped_refptr<IOBuffer> & buffer,unsigned size)205*6777b538SAndroid Build Coastguard Worker void MDnsConnection::Send(const scoped_refptr<IOBuffer>& buffer,
206*6777b538SAndroid Build Coastguard Worker unsigned size) {
207*6777b538SAndroid Build Coastguard Worker for (std::unique_ptr<SocketHandler>& handler : socket_handlers_)
208*6777b538SAndroid Build Coastguard Worker handler->Send(buffer, size);
209*6777b538SAndroid Build Coastguard Worker }
210*6777b538SAndroid Build Coastguard Worker
PostOnError(SocketHandler * loop,int rv)211*6777b538SAndroid Build Coastguard Worker void MDnsConnection::PostOnError(SocketHandler* loop, int rv) {
212*6777b538SAndroid Build Coastguard Worker int id = 0;
213*6777b538SAndroid Build Coastguard Worker for (const auto& it : socket_handlers_) {
214*6777b538SAndroid Build Coastguard Worker if (it.get() == loop)
215*6777b538SAndroid Build Coastguard Worker break;
216*6777b538SAndroid Build Coastguard Worker id++;
217*6777b538SAndroid Build Coastguard Worker }
218*6777b538SAndroid Build Coastguard Worker VLOG(1) << "Socket error. id=" << id << ", error=" << rv;
219*6777b538SAndroid Build Coastguard Worker // Post to allow deletion of this object by delegate.
220*6777b538SAndroid Build Coastguard Worker base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
221*6777b538SAndroid Build Coastguard Worker FROM_HERE, base::BindOnce(&MDnsConnection::OnError,
222*6777b538SAndroid Build Coastguard Worker weak_ptr_factory_.GetWeakPtr(), rv));
223*6777b538SAndroid Build Coastguard Worker }
224*6777b538SAndroid Build Coastguard Worker
OnError(int rv)225*6777b538SAndroid Build Coastguard Worker void MDnsConnection::OnError(int rv) {
226*6777b538SAndroid Build Coastguard Worker // TODO(noamsml): Specific handling of intermittent errors that can be handled
227*6777b538SAndroid Build Coastguard Worker // in the connection.
228*6777b538SAndroid Build Coastguard Worker delegate_->OnConnectionError(rv);
229*6777b538SAndroid Build Coastguard Worker }
230*6777b538SAndroid Build Coastguard Worker
OnDatagramReceived(DnsResponse * response,const IPEndPoint & recv_addr,int bytes_read)231*6777b538SAndroid Build Coastguard Worker void MDnsConnection::OnDatagramReceived(
232*6777b538SAndroid Build Coastguard Worker DnsResponse* response,
233*6777b538SAndroid Build Coastguard Worker const IPEndPoint& recv_addr,
234*6777b538SAndroid Build Coastguard Worker int bytes_read) {
235*6777b538SAndroid Build Coastguard Worker // TODO(noamsml): More sophisticated error handling.
236*6777b538SAndroid Build Coastguard Worker DCHECK_GT(bytes_read, 0);
237*6777b538SAndroid Build Coastguard Worker delegate_->HandlePacket(response, bytes_read);
238*6777b538SAndroid Build Coastguard Worker }
239*6777b538SAndroid Build Coastguard Worker
Core(base::Clock * clock,base::OneShotTimer * timer)240*6777b538SAndroid Build Coastguard Worker MDnsClientImpl::Core::Core(base::Clock* clock, base::OneShotTimer* timer)
241*6777b538SAndroid Build Coastguard Worker : clock_(clock),
242*6777b538SAndroid Build Coastguard Worker cleanup_timer_(timer),
243*6777b538SAndroid Build Coastguard Worker connection_(
244*6777b538SAndroid Build Coastguard Worker std::make_unique<MDnsConnection>((MDnsConnection::Delegate*)this)) {
245*6777b538SAndroid Build Coastguard Worker DCHECK(cleanup_timer_);
246*6777b538SAndroid Build Coastguard Worker DCHECK(!cleanup_timer_->IsRunning());
247*6777b538SAndroid Build Coastguard Worker }
248*6777b538SAndroid Build Coastguard Worker
~Core()249*6777b538SAndroid Build Coastguard Worker MDnsClientImpl::Core::~Core() {
250*6777b538SAndroid Build Coastguard Worker cleanup_timer_->Stop();
251*6777b538SAndroid Build Coastguard Worker }
252*6777b538SAndroid Build Coastguard Worker
Init(MDnsSocketFactory * socket_factory)253*6777b538SAndroid Build Coastguard Worker int MDnsClientImpl::Core::Init(MDnsSocketFactory* socket_factory) {
254*6777b538SAndroid Build Coastguard Worker CHECK(!cleanup_timer_->IsRunning());
255*6777b538SAndroid Build Coastguard Worker return connection_->Init(socket_factory);
256*6777b538SAndroid Build Coastguard Worker }
257*6777b538SAndroid Build Coastguard Worker
SendQuery(uint16_t rrtype,const std::string & name)258*6777b538SAndroid Build Coastguard Worker bool MDnsClientImpl::Core::SendQuery(uint16_t rrtype, const std::string& name) {
259*6777b538SAndroid Build Coastguard Worker std::optional<std::vector<uint8_t>> name_dns =
260*6777b538SAndroid Build Coastguard Worker dns_names_util::DottedNameToNetwork(name);
261*6777b538SAndroid Build Coastguard Worker if (!name_dns.has_value())
262*6777b538SAndroid Build Coastguard Worker return false;
263*6777b538SAndroid Build Coastguard Worker
264*6777b538SAndroid Build Coastguard Worker DnsQuery query(0, name_dns.value(), rrtype);
265*6777b538SAndroid Build Coastguard Worker query.set_flags(0); // Remove the RD flag from the query. It is unneeded.
266*6777b538SAndroid Build Coastguard Worker
267*6777b538SAndroid Build Coastguard Worker connection_->Send(query.io_buffer(), query.io_buffer()->size());
268*6777b538SAndroid Build Coastguard Worker return true;
269*6777b538SAndroid Build Coastguard Worker }
270*6777b538SAndroid Build Coastguard Worker
HandlePacket(DnsResponse * response,int bytes_read)271*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::HandlePacket(DnsResponse* response,
272*6777b538SAndroid Build Coastguard Worker int bytes_read) {
273*6777b538SAndroid Build Coastguard Worker unsigned offset;
274*6777b538SAndroid Build Coastguard Worker // Note: We store cache keys rather than record pointers to avoid
275*6777b538SAndroid Build Coastguard Worker // erroneous behavior in case a packet contains multiple exclusive
276*6777b538SAndroid Build Coastguard Worker // records with the same type and name.
277*6777b538SAndroid Build Coastguard Worker std::map<MDnsCache::Key, MDnsCache::UpdateType> update_keys;
278*6777b538SAndroid Build Coastguard Worker DCHECK_GT(bytes_read, 0);
279*6777b538SAndroid Build Coastguard Worker if (!response->InitParseWithoutQuery(bytes_read)) {
280*6777b538SAndroid Build Coastguard Worker DVLOG(1) << "Could not understand an mDNS packet.";
281*6777b538SAndroid Build Coastguard Worker return; // Message is unreadable.
282*6777b538SAndroid Build Coastguard Worker }
283*6777b538SAndroid Build Coastguard Worker
284*6777b538SAndroid Build Coastguard Worker // TODO(noamsml): duplicate query suppression.
285*6777b538SAndroid Build Coastguard Worker if (!(response->flags() & dns_protocol::kFlagResponse))
286*6777b538SAndroid Build Coastguard Worker return; // Message is a query. ignore it.
287*6777b538SAndroid Build Coastguard Worker
288*6777b538SAndroid Build Coastguard Worker DnsRecordParser parser = response->Parser();
289*6777b538SAndroid Build Coastguard Worker unsigned answer_count = response->answer_count() +
290*6777b538SAndroid Build Coastguard Worker response->additional_answer_count();
291*6777b538SAndroid Build Coastguard Worker
292*6777b538SAndroid Build Coastguard Worker for (unsigned i = 0; i < answer_count; i++) {
293*6777b538SAndroid Build Coastguard Worker offset = parser.GetOffset();
294*6777b538SAndroid Build Coastguard Worker std::unique_ptr<const RecordParsed> record =
295*6777b538SAndroid Build Coastguard Worker RecordParsed::CreateFrom(&parser, clock_->Now());
296*6777b538SAndroid Build Coastguard Worker
297*6777b538SAndroid Build Coastguard Worker if (!record) {
298*6777b538SAndroid Build Coastguard Worker DVLOG(1) << "Could not understand an mDNS record.";
299*6777b538SAndroid Build Coastguard Worker
300*6777b538SAndroid Build Coastguard Worker if (offset == parser.GetOffset()) {
301*6777b538SAndroid Build Coastguard Worker DVLOG(1) << "Abandoned parsing the rest of the packet.";
302*6777b538SAndroid Build Coastguard Worker return; // The parser did not advance, abort reading the packet.
303*6777b538SAndroid Build Coastguard Worker } else {
304*6777b538SAndroid Build Coastguard Worker continue; // We may be able to extract other records from the packet.
305*6777b538SAndroid Build Coastguard Worker }
306*6777b538SAndroid Build Coastguard Worker }
307*6777b538SAndroid Build Coastguard Worker
308*6777b538SAndroid Build Coastguard Worker if ((record->klass() & dns_protocol::kMDnsClassMask) !=
309*6777b538SAndroid Build Coastguard Worker dns_protocol::kClassIN) {
310*6777b538SAndroid Build Coastguard Worker DVLOG(1) << "Received an mDNS record with non-IN class. Ignoring.";
311*6777b538SAndroid Build Coastguard Worker continue; // Ignore all records not in the IN class.
312*6777b538SAndroid Build Coastguard Worker }
313*6777b538SAndroid Build Coastguard Worker
314*6777b538SAndroid Build Coastguard Worker MDnsCache::Key update_key = MDnsCache::Key::CreateFor(record.get());
315*6777b538SAndroid Build Coastguard Worker MDnsCache::UpdateType update = cache_.UpdateDnsRecord(std::move(record));
316*6777b538SAndroid Build Coastguard Worker
317*6777b538SAndroid Build Coastguard Worker // Cleanup time may have changed.
318*6777b538SAndroid Build Coastguard Worker ScheduleCleanup(cache_.next_expiration());
319*6777b538SAndroid Build Coastguard Worker
320*6777b538SAndroid Build Coastguard Worker update_keys.emplace(update_key, update);
321*6777b538SAndroid Build Coastguard Worker }
322*6777b538SAndroid Build Coastguard Worker
323*6777b538SAndroid Build Coastguard Worker for (const auto& update_key : update_keys) {
324*6777b538SAndroid Build Coastguard Worker const RecordParsed* record = cache_.LookupKey(update_key.first);
325*6777b538SAndroid Build Coastguard Worker if (!record)
326*6777b538SAndroid Build Coastguard Worker continue;
327*6777b538SAndroid Build Coastguard Worker
328*6777b538SAndroid Build Coastguard Worker if (record->type() == dns_protocol::kTypeNSEC) {
329*6777b538SAndroid Build Coastguard Worker #if defined(ENABLE_NSEC)
330*6777b538SAndroid Build Coastguard Worker NotifyNsecRecord(record);
331*6777b538SAndroid Build Coastguard Worker #endif
332*6777b538SAndroid Build Coastguard Worker } else {
333*6777b538SAndroid Build Coastguard Worker AlertListeners(update_key.second,
334*6777b538SAndroid Build Coastguard Worker ListenerKey(record->name(), record->type()), record);
335*6777b538SAndroid Build Coastguard Worker }
336*6777b538SAndroid Build Coastguard Worker }
337*6777b538SAndroid Build Coastguard Worker }
338*6777b538SAndroid Build Coastguard Worker
NotifyNsecRecord(const RecordParsed * record)339*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::NotifyNsecRecord(const RecordParsed* record) {
340*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(dns_protocol::kTypeNSEC, record->type());
341*6777b538SAndroid Build Coastguard Worker const NsecRecordRdata* rdata = record->rdata<NsecRecordRdata>();
342*6777b538SAndroid Build Coastguard Worker DCHECK(rdata);
343*6777b538SAndroid Build Coastguard Worker
344*6777b538SAndroid Build Coastguard Worker // Remove all cached records matching the nonexistent RR types.
345*6777b538SAndroid Build Coastguard Worker std::vector<const RecordParsed*> records_to_remove;
346*6777b538SAndroid Build Coastguard Worker
347*6777b538SAndroid Build Coastguard Worker cache_.FindDnsRecords(0, record->name(), &records_to_remove, clock_->Now());
348*6777b538SAndroid Build Coastguard Worker
349*6777b538SAndroid Build Coastguard Worker for (const auto* record_to_remove : records_to_remove) {
350*6777b538SAndroid Build Coastguard Worker if (record_to_remove->type() == dns_protocol::kTypeNSEC)
351*6777b538SAndroid Build Coastguard Worker continue;
352*6777b538SAndroid Build Coastguard Worker if (!rdata->GetBit(record_to_remove->type())) {
353*6777b538SAndroid Build Coastguard Worker std::unique_ptr<const RecordParsed> record_removed =
354*6777b538SAndroid Build Coastguard Worker cache_.RemoveRecord(record_to_remove);
355*6777b538SAndroid Build Coastguard Worker DCHECK(record_removed);
356*6777b538SAndroid Build Coastguard Worker OnRecordRemoved(record_removed.get());
357*6777b538SAndroid Build Coastguard Worker }
358*6777b538SAndroid Build Coastguard Worker }
359*6777b538SAndroid Build Coastguard Worker
360*6777b538SAndroid Build Coastguard Worker // Alert all listeners waiting for the nonexistent RR types.
361*6777b538SAndroid Build Coastguard Worker ListenerKey key(record->name(), 0);
362*6777b538SAndroid Build Coastguard Worker auto i = listeners_.upper_bound(key);
363*6777b538SAndroid Build Coastguard Worker for (; i != listeners_.end() &&
364*6777b538SAndroid Build Coastguard Worker i->first.name_lowercase() == key.name_lowercase();
365*6777b538SAndroid Build Coastguard Worker i++) {
366*6777b538SAndroid Build Coastguard Worker if (!rdata->GetBit(i->first.type())) {
367*6777b538SAndroid Build Coastguard Worker for (auto& observer : *i->second)
368*6777b538SAndroid Build Coastguard Worker observer.AlertNsecRecord();
369*6777b538SAndroid Build Coastguard Worker }
370*6777b538SAndroid Build Coastguard Worker }
371*6777b538SAndroid Build Coastguard Worker }
372*6777b538SAndroid Build Coastguard Worker
OnConnectionError(int error)373*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::OnConnectionError(int error) {
374*6777b538SAndroid Build Coastguard Worker // TODO(noamsml): On connection error, recreate connection and flush cache.
375*6777b538SAndroid Build Coastguard Worker VLOG(1) << "MDNS OnConnectionError (code: " << error << ")";
376*6777b538SAndroid Build Coastguard Worker }
377*6777b538SAndroid Build Coastguard Worker
ListenerKey(const std::string & name,uint16_t type)378*6777b538SAndroid Build Coastguard Worker MDnsClientImpl::Core::ListenerKey::ListenerKey(const std::string& name,
379*6777b538SAndroid Build Coastguard Worker uint16_t type)
380*6777b538SAndroid Build Coastguard Worker : name_lowercase_(base::ToLowerASCII(name)), type_(type) {}
381*6777b538SAndroid Build Coastguard Worker
operator <(const MDnsClientImpl::Core::ListenerKey & key) const382*6777b538SAndroid Build Coastguard Worker bool MDnsClientImpl::Core::ListenerKey::operator<(
383*6777b538SAndroid Build Coastguard Worker const MDnsClientImpl::Core::ListenerKey& key) const {
384*6777b538SAndroid Build Coastguard Worker if (name_lowercase_ == key.name_lowercase_)
385*6777b538SAndroid Build Coastguard Worker return type_ < key.type_;
386*6777b538SAndroid Build Coastguard Worker return name_lowercase_ < key.name_lowercase_;
387*6777b538SAndroid Build Coastguard Worker }
388*6777b538SAndroid Build Coastguard Worker
AlertListeners(MDnsCache::UpdateType update_type,const ListenerKey & key,const RecordParsed * record)389*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::AlertListeners(
390*6777b538SAndroid Build Coastguard Worker MDnsCache::UpdateType update_type,
391*6777b538SAndroid Build Coastguard Worker const ListenerKey& key,
392*6777b538SAndroid Build Coastguard Worker const RecordParsed* record) {
393*6777b538SAndroid Build Coastguard Worker auto listener_map_iterator = listeners_.find(key);
394*6777b538SAndroid Build Coastguard Worker if (listener_map_iterator == listeners_.end()) return;
395*6777b538SAndroid Build Coastguard Worker
396*6777b538SAndroid Build Coastguard Worker for (auto& observer : *listener_map_iterator->second)
397*6777b538SAndroid Build Coastguard Worker observer.HandleRecordUpdate(update_type, record);
398*6777b538SAndroid Build Coastguard Worker }
399*6777b538SAndroid Build Coastguard Worker
AddListener(MDnsListenerImpl * listener)400*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::AddListener(
401*6777b538SAndroid Build Coastguard Worker MDnsListenerImpl* listener) {
402*6777b538SAndroid Build Coastguard Worker ListenerKey key(listener->GetName(), listener->GetType());
403*6777b538SAndroid Build Coastguard Worker
404*6777b538SAndroid Build Coastguard Worker auto& observer_list = listeners_[key];
405*6777b538SAndroid Build Coastguard Worker if (!observer_list)
406*6777b538SAndroid Build Coastguard Worker observer_list = std::make_unique<ObserverListType>();
407*6777b538SAndroid Build Coastguard Worker
408*6777b538SAndroid Build Coastguard Worker observer_list->AddObserver(listener);
409*6777b538SAndroid Build Coastguard Worker }
410*6777b538SAndroid Build Coastguard Worker
RemoveListener(MDnsListenerImpl * listener)411*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::RemoveListener(MDnsListenerImpl* listener) {
412*6777b538SAndroid Build Coastguard Worker ListenerKey key(listener->GetName(), listener->GetType());
413*6777b538SAndroid Build Coastguard Worker auto observer_list_iterator = listeners_.find(key);
414*6777b538SAndroid Build Coastguard Worker
415*6777b538SAndroid Build Coastguard Worker DCHECK(observer_list_iterator != listeners_.end());
416*6777b538SAndroid Build Coastguard Worker DCHECK(observer_list_iterator->second->HasObserver(listener));
417*6777b538SAndroid Build Coastguard Worker
418*6777b538SAndroid Build Coastguard Worker observer_list_iterator->second->RemoveObserver(listener);
419*6777b538SAndroid Build Coastguard Worker
420*6777b538SAndroid Build Coastguard Worker // Remove the observer list from the map if it is empty
421*6777b538SAndroid Build Coastguard Worker if (observer_list_iterator->second->empty()) {
422*6777b538SAndroid Build Coastguard Worker // Schedule the actual removal for later in case the listener removal
423*6777b538SAndroid Build Coastguard Worker // happens while iterating over the observer list.
424*6777b538SAndroid Build Coastguard Worker base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
425*6777b538SAndroid Build Coastguard Worker FROM_HERE, base::BindOnce(&MDnsClientImpl::Core::CleanupObserverList,
426*6777b538SAndroid Build Coastguard Worker AsWeakPtr(), key));
427*6777b538SAndroid Build Coastguard Worker }
428*6777b538SAndroid Build Coastguard Worker }
429*6777b538SAndroid Build Coastguard Worker
CleanupObserverList(const ListenerKey & key)430*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::CleanupObserverList(const ListenerKey& key) {
431*6777b538SAndroid Build Coastguard Worker auto found = listeners_.find(key);
432*6777b538SAndroid Build Coastguard Worker if (found != listeners_.end() && found->second->empty()) {
433*6777b538SAndroid Build Coastguard Worker listeners_.erase(found);
434*6777b538SAndroid Build Coastguard Worker }
435*6777b538SAndroid Build Coastguard Worker }
436*6777b538SAndroid Build Coastguard Worker
ScheduleCleanup(base::Time cleanup)437*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::ScheduleCleanup(base::Time cleanup) {
438*6777b538SAndroid Build Coastguard Worker // If cache is overfilled. Force an immediate cleanup.
439*6777b538SAndroid Build Coastguard Worker if (cache_.IsCacheOverfilled())
440*6777b538SAndroid Build Coastguard Worker cleanup = clock_->Now();
441*6777b538SAndroid Build Coastguard Worker
442*6777b538SAndroid Build Coastguard Worker // Cleanup is already scheduled, no need to do anything.
443*6777b538SAndroid Build Coastguard Worker if (cleanup == scheduled_cleanup_) {
444*6777b538SAndroid Build Coastguard Worker return;
445*6777b538SAndroid Build Coastguard Worker }
446*6777b538SAndroid Build Coastguard Worker scheduled_cleanup_ = cleanup;
447*6777b538SAndroid Build Coastguard Worker
448*6777b538SAndroid Build Coastguard Worker // This cancels the previously scheduled cleanup.
449*6777b538SAndroid Build Coastguard Worker cleanup_timer_->Stop();
450*6777b538SAndroid Build Coastguard Worker
451*6777b538SAndroid Build Coastguard Worker // If |cleanup| is empty, then no cleanup necessary.
452*6777b538SAndroid Build Coastguard Worker if (cleanup != base::Time()) {
453*6777b538SAndroid Build Coastguard Worker cleanup_timer_->Start(FROM_HERE,
454*6777b538SAndroid Build Coastguard Worker std::max(base::TimeDelta(), cleanup - clock_->Now()),
455*6777b538SAndroid Build Coastguard Worker base::BindOnce(&MDnsClientImpl::Core::DoCleanup,
456*6777b538SAndroid Build Coastguard Worker base::Unretained(this)));
457*6777b538SAndroid Build Coastguard Worker }
458*6777b538SAndroid Build Coastguard Worker }
459*6777b538SAndroid Build Coastguard Worker
DoCleanup()460*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::DoCleanup() {
461*6777b538SAndroid Build Coastguard Worker cache_.CleanupRecords(
462*6777b538SAndroid Build Coastguard Worker clock_->Now(), base::BindRepeating(&MDnsClientImpl::Core::OnRecordRemoved,
463*6777b538SAndroid Build Coastguard Worker base::Unretained(this)));
464*6777b538SAndroid Build Coastguard Worker
465*6777b538SAndroid Build Coastguard Worker ScheduleCleanup(cache_.next_expiration());
466*6777b538SAndroid Build Coastguard Worker }
467*6777b538SAndroid Build Coastguard Worker
OnRecordRemoved(const RecordParsed * record)468*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::OnRecordRemoved(
469*6777b538SAndroid Build Coastguard Worker const RecordParsed* record) {
470*6777b538SAndroid Build Coastguard Worker AlertListeners(MDnsCache::RecordRemoved,
471*6777b538SAndroid Build Coastguard Worker ListenerKey(record->name(), record->type()), record);
472*6777b538SAndroid Build Coastguard Worker }
473*6777b538SAndroid Build Coastguard Worker
QueryCache(uint16_t rrtype,const std::string & name,std::vector<const RecordParsed * > * records) const474*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::Core::QueryCache(
475*6777b538SAndroid Build Coastguard Worker uint16_t rrtype,
476*6777b538SAndroid Build Coastguard Worker const std::string& name,
477*6777b538SAndroid Build Coastguard Worker std::vector<const RecordParsed*>* records) const {
478*6777b538SAndroid Build Coastguard Worker cache_.FindDnsRecords(rrtype, name, records, clock_->Now());
479*6777b538SAndroid Build Coastguard Worker }
480*6777b538SAndroid Build Coastguard Worker
MDnsClientImpl()481*6777b538SAndroid Build Coastguard Worker MDnsClientImpl::MDnsClientImpl()
482*6777b538SAndroid Build Coastguard Worker : clock_(base::DefaultClock::GetInstance()),
483*6777b538SAndroid Build Coastguard Worker cleanup_timer_(std::make_unique<base::OneShotTimer>()) {}
484*6777b538SAndroid Build Coastguard Worker
MDnsClientImpl(base::Clock * clock,std::unique_ptr<base::OneShotTimer> timer)485*6777b538SAndroid Build Coastguard Worker MDnsClientImpl::MDnsClientImpl(base::Clock* clock,
486*6777b538SAndroid Build Coastguard Worker std::unique_ptr<base::OneShotTimer> timer)
487*6777b538SAndroid Build Coastguard Worker : clock_(clock), cleanup_timer_(std::move(timer)) {}
488*6777b538SAndroid Build Coastguard Worker
~MDnsClientImpl()489*6777b538SAndroid Build Coastguard Worker MDnsClientImpl::~MDnsClientImpl() {
490*6777b538SAndroid Build Coastguard Worker StopListening();
491*6777b538SAndroid Build Coastguard Worker }
492*6777b538SAndroid Build Coastguard Worker
StartListening(MDnsSocketFactory * socket_factory)493*6777b538SAndroid Build Coastguard Worker int MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) {
494*6777b538SAndroid Build Coastguard Worker DCHECK(!core_.get());
495*6777b538SAndroid Build Coastguard Worker core_ = std::make_unique<Core>(clock_, cleanup_timer_.get());
496*6777b538SAndroid Build Coastguard Worker int rv = core_->Init(socket_factory);
497*6777b538SAndroid Build Coastguard Worker if (rv != OK) {
498*6777b538SAndroid Build Coastguard Worker DCHECK_NE(ERR_IO_PENDING, rv);
499*6777b538SAndroid Build Coastguard Worker core_.reset();
500*6777b538SAndroid Build Coastguard Worker }
501*6777b538SAndroid Build Coastguard Worker return rv;
502*6777b538SAndroid Build Coastguard Worker }
503*6777b538SAndroid Build Coastguard Worker
StopListening()504*6777b538SAndroid Build Coastguard Worker void MDnsClientImpl::StopListening() {
505*6777b538SAndroid Build Coastguard Worker core_.reset();
506*6777b538SAndroid Build Coastguard Worker }
507*6777b538SAndroid Build Coastguard Worker
IsListening() const508*6777b538SAndroid Build Coastguard Worker bool MDnsClientImpl::IsListening() const {
509*6777b538SAndroid Build Coastguard Worker return core_.get() != nullptr;
510*6777b538SAndroid Build Coastguard Worker }
511*6777b538SAndroid Build Coastguard Worker
CreateListener(uint16_t rrtype,const std::string & name,MDnsListener::Delegate * delegate)512*6777b538SAndroid Build Coastguard Worker std::unique_ptr<MDnsListener> MDnsClientImpl::CreateListener(
513*6777b538SAndroid Build Coastguard Worker uint16_t rrtype,
514*6777b538SAndroid Build Coastguard Worker const std::string& name,
515*6777b538SAndroid Build Coastguard Worker MDnsListener::Delegate* delegate) {
516*6777b538SAndroid Build Coastguard Worker return std::make_unique<MDnsListenerImpl>(rrtype, name, clock_, delegate,
517*6777b538SAndroid Build Coastguard Worker this);
518*6777b538SAndroid Build Coastguard Worker }
519*6777b538SAndroid Build Coastguard Worker
CreateTransaction(uint16_t rrtype,const std::string & name,int flags,const MDnsTransaction::ResultCallback & callback)520*6777b538SAndroid Build Coastguard Worker std::unique_ptr<MDnsTransaction> MDnsClientImpl::CreateTransaction(
521*6777b538SAndroid Build Coastguard Worker uint16_t rrtype,
522*6777b538SAndroid Build Coastguard Worker const std::string& name,
523*6777b538SAndroid Build Coastguard Worker int flags,
524*6777b538SAndroid Build Coastguard Worker const MDnsTransaction::ResultCallback& callback) {
525*6777b538SAndroid Build Coastguard Worker return std::make_unique<MDnsTransactionImpl>(rrtype, name, flags, callback,
526*6777b538SAndroid Build Coastguard Worker this);
527*6777b538SAndroid Build Coastguard Worker }
528*6777b538SAndroid Build Coastguard Worker
MDnsListenerImpl(uint16_t rrtype,const std::string & name,base::Clock * clock,MDnsListener::Delegate * delegate,MDnsClientImpl * client)529*6777b538SAndroid Build Coastguard Worker MDnsListenerImpl::MDnsListenerImpl(uint16_t rrtype,
530*6777b538SAndroid Build Coastguard Worker const std::string& name,
531*6777b538SAndroid Build Coastguard Worker base::Clock* clock,
532*6777b538SAndroid Build Coastguard Worker MDnsListener::Delegate* delegate,
533*6777b538SAndroid Build Coastguard Worker MDnsClientImpl* client)
534*6777b538SAndroid Build Coastguard Worker : rrtype_(rrtype),
535*6777b538SAndroid Build Coastguard Worker name_(name),
536*6777b538SAndroid Build Coastguard Worker clock_(clock),
537*6777b538SAndroid Build Coastguard Worker client_(client),
538*6777b538SAndroid Build Coastguard Worker delegate_(delegate) {}
539*6777b538SAndroid Build Coastguard Worker
~MDnsListenerImpl()540*6777b538SAndroid Build Coastguard Worker MDnsListenerImpl::~MDnsListenerImpl() {
541*6777b538SAndroid Build Coastguard Worker if (started_) {
542*6777b538SAndroid Build Coastguard Worker DCHECK(client_->core());
543*6777b538SAndroid Build Coastguard Worker client_->core()->RemoveListener(this);
544*6777b538SAndroid Build Coastguard Worker }
545*6777b538SAndroid Build Coastguard Worker }
546*6777b538SAndroid Build Coastguard Worker
Start()547*6777b538SAndroid Build Coastguard Worker bool MDnsListenerImpl::Start() {
548*6777b538SAndroid Build Coastguard Worker DCHECK(!started_);
549*6777b538SAndroid Build Coastguard Worker
550*6777b538SAndroid Build Coastguard Worker started_ = true;
551*6777b538SAndroid Build Coastguard Worker
552*6777b538SAndroid Build Coastguard Worker DCHECK(client_->core());
553*6777b538SAndroid Build Coastguard Worker client_->core()->AddListener(this);
554*6777b538SAndroid Build Coastguard Worker
555*6777b538SAndroid Build Coastguard Worker return true;
556*6777b538SAndroid Build Coastguard Worker }
557*6777b538SAndroid Build Coastguard Worker
SetActiveRefresh(bool active_refresh)558*6777b538SAndroid Build Coastguard Worker void MDnsListenerImpl::SetActiveRefresh(bool active_refresh) {
559*6777b538SAndroid Build Coastguard Worker active_refresh_ = active_refresh;
560*6777b538SAndroid Build Coastguard Worker
561*6777b538SAndroid Build Coastguard Worker if (started_) {
562*6777b538SAndroid Build Coastguard Worker if (!active_refresh_) {
563*6777b538SAndroid Build Coastguard Worker next_refresh_.Cancel();
564*6777b538SAndroid Build Coastguard Worker } else if (last_update_ != base::Time()) {
565*6777b538SAndroid Build Coastguard Worker ScheduleNextRefresh();
566*6777b538SAndroid Build Coastguard Worker }
567*6777b538SAndroid Build Coastguard Worker }
568*6777b538SAndroid Build Coastguard Worker }
569*6777b538SAndroid Build Coastguard Worker
GetName() const570*6777b538SAndroid Build Coastguard Worker const std::string& MDnsListenerImpl::GetName() const {
571*6777b538SAndroid Build Coastguard Worker return name_;
572*6777b538SAndroid Build Coastguard Worker }
573*6777b538SAndroid Build Coastguard Worker
GetType() const574*6777b538SAndroid Build Coastguard Worker uint16_t MDnsListenerImpl::GetType() const {
575*6777b538SAndroid Build Coastguard Worker return rrtype_;
576*6777b538SAndroid Build Coastguard Worker }
577*6777b538SAndroid Build Coastguard Worker
HandleRecordUpdate(MDnsCache::UpdateType update_type,const RecordParsed * record)578*6777b538SAndroid Build Coastguard Worker void MDnsListenerImpl::HandleRecordUpdate(MDnsCache::UpdateType update_type,
579*6777b538SAndroid Build Coastguard Worker const RecordParsed* record) {
580*6777b538SAndroid Build Coastguard Worker DCHECK(started_);
581*6777b538SAndroid Build Coastguard Worker
582*6777b538SAndroid Build Coastguard Worker if (update_type != MDnsCache::RecordRemoved) {
583*6777b538SAndroid Build Coastguard Worker ttl_ = record->ttl();
584*6777b538SAndroid Build Coastguard Worker last_update_ = record->time_created();
585*6777b538SAndroid Build Coastguard Worker
586*6777b538SAndroid Build Coastguard Worker ScheduleNextRefresh();
587*6777b538SAndroid Build Coastguard Worker }
588*6777b538SAndroid Build Coastguard Worker
589*6777b538SAndroid Build Coastguard Worker if (update_type != MDnsCache::NoChange) {
590*6777b538SAndroid Build Coastguard Worker MDnsListener::UpdateType update_external;
591*6777b538SAndroid Build Coastguard Worker
592*6777b538SAndroid Build Coastguard Worker switch (update_type) {
593*6777b538SAndroid Build Coastguard Worker case MDnsCache::RecordAdded:
594*6777b538SAndroid Build Coastguard Worker update_external = MDnsListener::RECORD_ADDED;
595*6777b538SAndroid Build Coastguard Worker break;
596*6777b538SAndroid Build Coastguard Worker case MDnsCache::RecordChanged:
597*6777b538SAndroid Build Coastguard Worker update_external = MDnsListener::RECORD_CHANGED;
598*6777b538SAndroid Build Coastguard Worker break;
599*6777b538SAndroid Build Coastguard Worker case MDnsCache::RecordRemoved:
600*6777b538SAndroid Build Coastguard Worker update_external = MDnsListener::RECORD_REMOVED;
601*6777b538SAndroid Build Coastguard Worker break;
602*6777b538SAndroid Build Coastguard Worker case MDnsCache::NoChange:
603*6777b538SAndroid Build Coastguard Worker default:
604*6777b538SAndroid Build Coastguard Worker NOTREACHED();
605*6777b538SAndroid Build Coastguard Worker // Dummy assignment to suppress compiler warning.
606*6777b538SAndroid Build Coastguard Worker update_external = MDnsListener::RECORD_CHANGED;
607*6777b538SAndroid Build Coastguard Worker break;
608*6777b538SAndroid Build Coastguard Worker }
609*6777b538SAndroid Build Coastguard Worker
610*6777b538SAndroid Build Coastguard Worker delegate_->OnRecordUpdate(update_external, record);
611*6777b538SAndroid Build Coastguard Worker }
612*6777b538SAndroid Build Coastguard Worker }
613*6777b538SAndroid Build Coastguard Worker
AlertNsecRecord()614*6777b538SAndroid Build Coastguard Worker void MDnsListenerImpl::AlertNsecRecord() {
615*6777b538SAndroid Build Coastguard Worker DCHECK(started_);
616*6777b538SAndroid Build Coastguard Worker delegate_->OnNsecRecord(name_, rrtype_);
617*6777b538SAndroid Build Coastguard Worker }
618*6777b538SAndroid Build Coastguard Worker
ScheduleNextRefresh()619*6777b538SAndroid Build Coastguard Worker void MDnsListenerImpl::ScheduleNextRefresh() {
620*6777b538SAndroid Build Coastguard Worker DCHECK(last_update_ != base::Time());
621*6777b538SAndroid Build Coastguard Worker
622*6777b538SAndroid Build Coastguard Worker if (!active_refresh_)
623*6777b538SAndroid Build Coastguard Worker return;
624*6777b538SAndroid Build Coastguard Worker
625*6777b538SAndroid Build Coastguard Worker // A zero TTL is a goodbye packet and should not be refreshed.
626*6777b538SAndroid Build Coastguard Worker if (ttl_ == 0) {
627*6777b538SAndroid Build Coastguard Worker next_refresh_.Cancel();
628*6777b538SAndroid Build Coastguard Worker return;
629*6777b538SAndroid Build Coastguard Worker }
630*6777b538SAndroid Build Coastguard Worker
631*6777b538SAndroid Build Coastguard Worker next_refresh_.Reset(
632*6777b538SAndroid Build Coastguard Worker base::BindRepeating(&MDnsListenerImpl::DoRefresh, AsWeakPtr()));
633*6777b538SAndroid Build Coastguard Worker
634*6777b538SAndroid Build Coastguard Worker // Schedule refreshes at both 85% and 95% of the original TTL. These will both
635*6777b538SAndroid Build Coastguard Worker // be canceled and rescheduled if the record's TTL is updated due to a
636*6777b538SAndroid Build Coastguard Worker // response being received.
637*6777b538SAndroid Build Coastguard Worker base::Time next_refresh1 =
638*6777b538SAndroid Build Coastguard Worker last_update_ +
639*6777b538SAndroid Build Coastguard Worker base::Milliseconds(static_cast<int>(base::Time::kMillisecondsPerSecond *
640*6777b538SAndroid Build Coastguard Worker kListenerRefreshRatio1 * ttl_));
641*6777b538SAndroid Build Coastguard Worker
642*6777b538SAndroid Build Coastguard Worker base::Time next_refresh2 =
643*6777b538SAndroid Build Coastguard Worker last_update_ +
644*6777b538SAndroid Build Coastguard Worker base::Milliseconds(static_cast<int>(base::Time::kMillisecondsPerSecond *
645*6777b538SAndroid Build Coastguard Worker kListenerRefreshRatio2 * ttl_));
646*6777b538SAndroid Build Coastguard Worker
647*6777b538SAndroid Build Coastguard Worker base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
648*6777b538SAndroid Build Coastguard Worker FROM_HERE, next_refresh_.callback(), next_refresh1 - clock_->Now());
649*6777b538SAndroid Build Coastguard Worker
650*6777b538SAndroid Build Coastguard Worker base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
651*6777b538SAndroid Build Coastguard Worker FROM_HERE, next_refresh_.callback(), next_refresh2 - clock_->Now());
652*6777b538SAndroid Build Coastguard Worker }
653*6777b538SAndroid Build Coastguard Worker
DoRefresh()654*6777b538SAndroid Build Coastguard Worker void MDnsListenerImpl::DoRefresh() {
655*6777b538SAndroid Build Coastguard Worker RecordQueryMetric(mdnsQueryType::kRefresh, name_);
656*6777b538SAndroid Build Coastguard Worker client_->core()->SendQuery(rrtype_, name_);
657*6777b538SAndroid Build Coastguard Worker }
658*6777b538SAndroid Build Coastguard Worker
MDnsTransactionImpl(uint16_t rrtype,const std::string & name,int flags,const MDnsTransaction::ResultCallback & callback,MDnsClientImpl * client)659*6777b538SAndroid Build Coastguard Worker MDnsTransactionImpl::MDnsTransactionImpl(
660*6777b538SAndroid Build Coastguard Worker uint16_t rrtype,
661*6777b538SAndroid Build Coastguard Worker const std::string& name,
662*6777b538SAndroid Build Coastguard Worker int flags,
663*6777b538SAndroid Build Coastguard Worker const MDnsTransaction::ResultCallback& callback,
664*6777b538SAndroid Build Coastguard Worker MDnsClientImpl* client)
665*6777b538SAndroid Build Coastguard Worker : rrtype_(rrtype),
666*6777b538SAndroid Build Coastguard Worker name_(name),
667*6777b538SAndroid Build Coastguard Worker callback_(callback),
668*6777b538SAndroid Build Coastguard Worker client_(client),
669*6777b538SAndroid Build Coastguard Worker flags_(flags) {
670*6777b538SAndroid Build Coastguard Worker DCHECK((flags_ & MDnsTransaction::FLAG_MASK) == flags_);
671*6777b538SAndroid Build Coastguard Worker DCHECK(flags_ & MDnsTransaction::QUERY_CACHE ||
672*6777b538SAndroid Build Coastguard Worker flags_ & MDnsTransaction::QUERY_NETWORK);
673*6777b538SAndroid Build Coastguard Worker }
674*6777b538SAndroid Build Coastguard Worker
~MDnsTransactionImpl()675*6777b538SAndroid Build Coastguard Worker MDnsTransactionImpl::~MDnsTransactionImpl() {
676*6777b538SAndroid Build Coastguard Worker timeout_.Cancel();
677*6777b538SAndroid Build Coastguard Worker }
678*6777b538SAndroid Build Coastguard Worker
Start()679*6777b538SAndroid Build Coastguard Worker bool MDnsTransactionImpl::Start() {
680*6777b538SAndroid Build Coastguard Worker DCHECK(!started_);
681*6777b538SAndroid Build Coastguard Worker started_ = true;
682*6777b538SAndroid Build Coastguard Worker
683*6777b538SAndroid Build Coastguard Worker base::WeakPtr<MDnsTransactionImpl> weak_this = AsWeakPtr();
684*6777b538SAndroid Build Coastguard Worker if (flags_ & MDnsTransaction::QUERY_CACHE) {
685*6777b538SAndroid Build Coastguard Worker ServeRecordsFromCache();
686*6777b538SAndroid Build Coastguard Worker
687*6777b538SAndroid Build Coastguard Worker if (!weak_this || !is_active()) return true;
688*6777b538SAndroid Build Coastguard Worker }
689*6777b538SAndroid Build Coastguard Worker
690*6777b538SAndroid Build Coastguard Worker if (flags_ & MDnsTransaction::QUERY_NETWORK) {
691*6777b538SAndroid Build Coastguard Worker return QueryAndListen();
692*6777b538SAndroid Build Coastguard Worker }
693*6777b538SAndroid Build Coastguard Worker
694*6777b538SAndroid Build Coastguard Worker // If this is a cache only query, signal that the transaction is over
695*6777b538SAndroid Build Coastguard Worker // immediately.
696*6777b538SAndroid Build Coastguard Worker SignalTransactionOver();
697*6777b538SAndroid Build Coastguard Worker return true;
698*6777b538SAndroid Build Coastguard Worker }
699*6777b538SAndroid Build Coastguard Worker
GetName() const700*6777b538SAndroid Build Coastguard Worker const std::string& MDnsTransactionImpl::GetName() const {
701*6777b538SAndroid Build Coastguard Worker return name_;
702*6777b538SAndroid Build Coastguard Worker }
703*6777b538SAndroid Build Coastguard Worker
GetType() const704*6777b538SAndroid Build Coastguard Worker uint16_t MDnsTransactionImpl::GetType() const {
705*6777b538SAndroid Build Coastguard Worker return rrtype_;
706*6777b538SAndroid Build Coastguard Worker }
707*6777b538SAndroid Build Coastguard Worker
CacheRecordFound(const RecordParsed * record)708*6777b538SAndroid Build Coastguard Worker void MDnsTransactionImpl::CacheRecordFound(const RecordParsed* record) {
709*6777b538SAndroid Build Coastguard Worker DCHECK(started_);
710*6777b538SAndroid Build Coastguard Worker OnRecordUpdate(MDnsListener::RECORD_ADDED, record);
711*6777b538SAndroid Build Coastguard Worker }
712*6777b538SAndroid Build Coastguard Worker
TriggerCallback(MDnsTransaction::Result result,const RecordParsed * record)713*6777b538SAndroid Build Coastguard Worker void MDnsTransactionImpl::TriggerCallback(MDnsTransaction::Result result,
714*6777b538SAndroid Build Coastguard Worker const RecordParsed* record) {
715*6777b538SAndroid Build Coastguard Worker DCHECK(started_);
716*6777b538SAndroid Build Coastguard Worker if (!is_active()) return;
717*6777b538SAndroid Build Coastguard Worker
718*6777b538SAndroid Build Coastguard Worker // Ensure callback is run after touching all class state, so that
719*6777b538SAndroid Build Coastguard Worker // the callback can delete the transaction.
720*6777b538SAndroid Build Coastguard Worker MDnsTransaction::ResultCallback callback = callback_;
721*6777b538SAndroid Build Coastguard Worker
722*6777b538SAndroid Build Coastguard Worker // Reset the transaction if it expects a single result, or if the result
723*6777b538SAndroid Build Coastguard Worker // is a final one (everything except for a record).
724*6777b538SAndroid Build Coastguard Worker if (flags_ & MDnsTransaction::SINGLE_RESULT ||
725*6777b538SAndroid Build Coastguard Worker result != MDnsTransaction::RESULT_RECORD) {
726*6777b538SAndroid Build Coastguard Worker Reset();
727*6777b538SAndroid Build Coastguard Worker }
728*6777b538SAndroid Build Coastguard Worker
729*6777b538SAndroid Build Coastguard Worker callback.Run(result, record);
730*6777b538SAndroid Build Coastguard Worker }
731*6777b538SAndroid Build Coastguard Worker
Reset()732*6777b538SAndroid Build Coastguard Worker void MDnsTransactionImpl::Reset() {
733*6777b538SAndroid Build Coastguard Worker callback_.Reset();
734*6777b538SAndroid Build Coastguard Worker listener_.reset();
735*6777b538SAndroid Build Coastguard Worker timeout_.Cancel();
736*6777b538SAndroid Build Coastguard Worker }
737*6777b538SAndroid Build Coastguard Worker
OnRecordUpdate(MDnsListener::UpdateType update,const RecordParsed * record)738*6777b538SAndroid Build Coastguard Worker void MDnsTransactionImpl::OnRecordUpdate(MDnsListener::UpdateType update,
739*6777b538SAndroid Build Coastguard Worker const RecordParsed* record) {
740*6777b538SAndroid Build Coastguard Worker DCHECK(started_);
741*6777b538SAndroid Build Coastguard Worker if (update == MDnsListener::RECORD_ADDED ||
742*6777b538SAndroid Build Coastguard Worker update == MDnsListener::RECORD_CHANGED)
743*6777b538SAndroid Build Coastguard Worker TriggerCallback(MDnsTransaction::RESULT_RECORD, record);
744*6777b538SAndroid Build Coastguard Worker }
745*6777b538SAndroid Build Coastguard Worker
SignalTransactionOver()746*6777b538SAndroid Build Coastguard Worker void MDnsTransactionImpl::SignalTransactionOver() {
747*6777b538SAndroid Build Coastguard Worker DCHECK(started_);
748*6777b538SAndroid Build Coastguard Worker if (flags_ & MDnsTransaction::SINGLE_RESULT) {
749*6777b538SAndroid Build Coastguard Worker TriggerCallback(MDnsTransaction::RESULT_NO_RESULTS, nullptr);
750*6777b538SAndroid Build Coastguard Worker } else {
751*6777b538SAndroid Build Coastguard Worker TriggerCallback(MDnsTransaction::RESULT_DONE, nullptr);
752*6777b538SAndroid Build Coastguard Worker }
753*6777b538SAndroid Build Coastguard Worker }
754*6777b538SAndroid Build Coastguard Worker
ServeRecordsFromCache()755*6777b538SAndroid Build Coastguard Worker void MDnsTransactionImpl::ServeRecordsFromCache() {
756*6777b538SAndroid Build Coastguard Worker std::vector<const RecordParsed*> records;
757*6777b538SAndroid Build Coastguard Worker base::WeakPtr<MDnsTransactionImpl> weak_this = AsWeakPtr();
758*6777b538SAndroid Build Coastguard Worker
759*6777b538SAndroid Build Coastguard Worker if (client_->core()) {
760*6777b538SAndroid Build Coastguard Worker client_->core()->QueryCache(rrtype_, name_, &records);
761*6777b538SAndroid Build Coastguard Worker for (auto i = records.begin(); i != records.end() && weak_this; ++i) {
762*6777b538SAndroid Build Coastguard Worker weak_this->TriggerCallback(MDnsTransaction::RESULT_RECORD, *i);
763*6777b538SAndroid Build Coastguard Worker }
764*6777b538SAndroid Build Coastguard Worker
765*6777b538SAndroid Build Coastguard Worker #if defined(ENABLE_NSEC)
766*6777b538SAndroid Build Coastguard Worker if (records.empty()) {
767*6777b538SAndroid Build Coastguard Worker DCHECK(weak_this);
768*6777b538SAndroid Build Coastguard Worker client_->core()->QueryCache(dns_protocol::kTypeNSEC, name_, &records);
769*6777b538SAndroid Build Coastguard Worker if (!records.empty()) {
770*6777b538SAndroid Build Coastguard Worker const NsecRecordRdata* rdata =
771*6777b538SAndroid Build Coastguard Worker records.front()->rdata<NsecRecordRdata>();
772*6777b538SAndroid Build Coastguard Worker DCHECK(rdata);
773*6777b538SAndroid Build Coastguard Worker if (!rdata->GetBit(rrtype_))
774*6777b538SAndroid Build Coastguard Worker weak_this->TriggerCallback(MDnsTransaction::RESULT_NSEC, nullptr);
775*6777b538SAndroid Build Coastguard Worker }
776*6777b538SAndroid Build Coastguard Worker }
777*6777b538SAndroid Build Coastguard Worker #endif
778*6777b538SAndroid Build Coastguard Worker }
779*6777b538SAndroid Build Coastguard Worker }
780*6777b538SAndroid Build Coastguard Worker
QueryAndListen()781*6777b538SAndroid Build Coastguard Worker bool MDnsTransactionImpl::QueryAndListen() {
782*6777b538SAndroid Build Coastguard Worker listener_ = client_->CreateListener(rrtype_, name_, this);
783*6777b538SAndroid Build Coastguard Worker if (!listener_->Start())
784*6777b538SAndroid Build Coastguard Worker return false;
785*6777b538SAndroid Build Coastguard Worker
786*6777b538SAndroid Build Coastguard Worker DCHECK(client_->core());
787*6777b538SAndroid Build Coastguard Worker RecordQueryMetric(mdnsQueryType::kInitial, name_);
788*6777b538SAndroid Build Coastguard Worker if (!client_->core()->SendQuery(rrtype_, name_))
789*6777b538SAndroid Build Coastguard Worker return false;
790*6777b538SAndroid Build Coastguard Worker
791*6777b538SAndroid Build Coastguard Worker timeout_.Reset(
792*6777b538SAndroid Build Coastguard Worker base::BindOnce(&MDnsTransactionImpl::SignalTransactionOver, AsWeakPtr()));
793*6777b538SAndroid Build Coastguard Worker base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
794*6777b538SAndroid Build Coastguard Worker FROM_HERE, timeout_.callback(), kTransactionTimeout);
795*6777b538SAndroid Build Coastguard Worker
796*6777b538SAndroid Build Coastguard Worker return true;
797*6777b538SAndroid Build Coastguard Worker }
798*6777b538SAndroid Build Coastguard Worker
OnNsecRecord(const std::string & name,unsigned type)799*6777b538SAndroid Build Coastguard Worker void MDnsTransactionImpl::OnNsecRecord(const std::string& name, unsigned type) {
800*6777b538SAndroid Build Coastguard Worker TriggerCallback(RESULT_NSEC, nullptr);
801*6777b538SAndroid Build Coastguard Worker }
802*6777b538SAndroid Build Coastguard Worker
OnCachePurged()803*6777b538SAndroid Build Coastguard Worker void MDnsTransactionImpl::OnCachePurged() {
804*6777b538SAndroid Build Coastguard Worker // TODO(noamsml): Cache purge situations not yet implemented
805*6777b538SAndroid Build Coastguard Worker }
806*6777b538SAndroid Build Coastguard Worker
807*6777b538SAndroid Build Coastguard Worker } // namespace net
808