[go: nahoru, domu]

blob: 1b0b0a5abf0543a2c5114c786d18b31a75f6f22e [file] [log] [blame]
Avi Drissman64595482022-09-14 20:52:291// Copyright 2013 The Chromium Authors
noamsml@chromium.org245b164e2013-06-13 22:31:422// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef NET_DNS_MDNS_CLIENT_IMPL_H_
6#define NET_DNS_MDNS_CLIENT_IMPL_H_
7
Avi Drissman13fc8932015-12-20 04:40:468#include <stdint.h>
9
noamsml@chromium.org245b164e2013-06-13 22:31:4210#include <map>
danakj22f90e72016-04-16 01:55:4011#include <memory>
noamsml@chromium.org245b164e2013-06-13 22:31:4212#include <string>
13#include <utility>
14#include <vector>
15
16#include "base/cancelable_callback.h"
Brett Wilsonc6a0c822017-09-12 00:04:2917#include "base/containers/queue.h"
thestiga0e18cd2015-09-25 04:58:3618#include "base/gtest_prod_util.h"
Keishi Hattori0e45c022021-11-27 09:25:5219#include "base/memory/raw_ptr.h"
Dave Tapuska61bdb9e2024-06-17 14:54:0220#include "base/memory/weak_ptr.h"
noamsml@chromium.org245b164e2013-06-13 22:31:4221#include "base/observer_list.h"
Gabriel Charetted87f10f2022-03-31 00:44:2222#include "base/time/time.h"
noamsml@chromium.org245b164e2013-06-13 22:31:4223#include "net/base/io_buffer.h"
24#include "net/base/ip_endpoint.h"
bnc81c46c1f2016-10-04 16:25:5925#include "net/base/net_export.h"
noamsml@chromium.org245b164e2013-06-13 22:31:4226#include "net/dns/mdns_cache.h"
27#include "net/dns/mdns_client.h"
tfarina5dd13c22016-11-16 12:08:2628#include "net/socket/datagram_server_socket.h"
29#include "net/socket/udp_server_socket.h"
30#include "net/socket/udp_socket.h"
noamsml@chromium.org245b164e2013-06-13 22:31:4231
kmarshall3e740be2015-03-02 21:30:4432namespace base {
33class Clock;
tzik08d8d6e2018-07-09 04:11:4734class OneShotTimer;
kmarshall3e740be2015-03-02 21:30:4435} // namespace base
36
noamsml@chromium.org245b164e2013-06-13 22:31:4237namespace net {
38
Eric Orth9871aaf2018-10-02 19:59:1839class NetLog;
40
vitalybuka@chromium.org95b331b42013-12-02 06:26:3141class MDnsSocketFactoryImpl : public MDnsSocketFactory {
42 public:
Eric Orth9871aaf2018-10-02 19:59:1843 MDnsSocketFactoryImpl() : net_log_(nullptr) {}
44 explicit MDnsSocketFactoryImpl(NetLog* net_log) : net_log_(net_log) {}
Peter Boström293b1342021-09-22 17:31:4345
46 MDnsSocketFactoryImpl(const MDnsSocketFactoryImpl&) = delete;
47 MDnsSocketFactoryImpl& operator=(const MDnsSocketFactoryImpl&) = delete;
48
Tsuyoshi Horo07c3f0e2022-06-16 07:30:4749 ~MDnsSocketFactoryImpl() override = default;
vitalybuka@chromium.org95b331b42013-12-02 06:26:3150
Qingsi Wang5410ef0b2019-03-05 20:26:4751 void CreateSockets(
52 std::vector<std::unique_ptr<DatagramServerSocket>>* sockets) override;
vitalybuka@chromium.org95b331b42013-12-02 06:26:3153
54 private:
Keishi Hattori0e45c022021-11-27 09:25:5255 const raw_ptr<NetLog> net_log_;
vitalybuka@chromium.org95b331b42013-12-02 06:26:3156};
57
noamsml@chromium.org245b164e2013-06-13 22:31:4258// A connection to the network for multicast DNS clients. It reads data into
59// DnsResponse objects and alerts the delegate that a packet has been received.
noamsml@chromium.orgba77c27f2013-07-02 22:34:3260class NET_EXPORT_PRIVATE MDnsConnection {
noamsml@chromium.org245b164e2013-06-13 22:31:4261 public:
noamsml@chromium.org245b164e2013-06-13 22:31:4262 class Delegate {
63 public:
64 // Handle an mDNS packet buffered in |response| with a size of |bytes_read|.
65 virtual void HandlePacket(DnsResponse* response, int bytes_read) = 0;
66 virtual void OnConnectionError(int error) = 0;
Tsuyoshi Horo07c3f0e2022-06-16 07:30:4767 virtual ~Delegate() = default;
noamsml@chromium.org245b164e2013-06-13 22:31:4268 };
69
vitalybuka@chromium.orge4411fbe2013-09-26 21:10:1170 explicit MDnsConnection(MDnsConnection::Delegate* delegate);
Peter Boström293b1342021-09-22 17:31:4371
72 MDnsConnection(const MDnsConnection&) = delete;
73 MDnsConnection& operator=(const MDnsConnection&) = delete;
74
noamsml@chromium.org245b164e2013-06-13 22:31:4275 virtual ~MDnsConnection();
76
Eric Orthe857ebb2019-03-13 23:02:0777 // Succeeds if at least one of the socket handlers succeeded.
78 int Init(MDnsSocketFactory* socket_factory);
vitalybuka20859742014-09-22 23:42:3079 void Send(const scoped_refptr<IOBuffer>& buffer, unsigned size);
noamsml@chromium.org245b164e2013-06-13 22:31:4280
81 private:
82 class SocketHandler {
83 public:
Qingsi Wang5410ef0b2019-03-05 20:26:4784 SocketHandler(std::unique_ptr<DatagramServerSocket> socket,
vitalybuka@chromium.org95b331b42013-12-02 06:26:3185 MDnsConnection* connection);
Peter Boström293b1342021-09-22 17:31:4386
87 SocketHandler(const SocketHandler&) = delete;
88 SocketHandler& operator=(const SocketHandler&) = delete;
89
noamsml@chromium.org245b164e2013-06-13 22:31:4290 ~SocketHandler();
noamsml@chromium.org245b164e2013-06-13 22:31:4291
vitalybuka@chromium.org95b331b42013-12-02 06:26:3192 int Start();
vitalybuka20859742014-09-22 23:42:3093 void Send(const scoped_refptr<IOBuffer>& buffer, unsigned size);
noamsml@chromium.org245b164e2013-06-13 22:31:4294
95 private:
vitalybuka@chromium.org03dd94252013-09-01 23:25:3196 int DoLoop(int rv);
noamsml@chromium.org245b164e2013-06-13 22:31:4297 void OnDatagramReceived(int rv);
98
99 // Callback for when sending a query has finished.
100 void SendDone(int rv);
101
Qingsi Wang5410ef0b2019-03-05 20:26:47102 std::unique_ptr<DatagramServerSocket> socket_;
Keishi Hattori0e45c022021-11-27 09:25:52103 raw_ptr<MDnsConnection> connection_;
noamsml@chromium.org245b164e2013-06-13 22:31:42104 IPEndPoint recv_addr_;
vitalybuka@chromium.org95b331b42013-12-02 06:26:31105 DnsResponse response_;
noamsml@chromium.org245b164e2013-06-13 22:31:42106 IPEndPoint multicast_addr_;
Tsuyoshi Horodbef87992022-06-09 01:39:41107 bool send_in_progress_ = false;
Brett Wilsonc6a0c822017-09-12 00:04:29108 base::queue<std::pair<scoped_refptr<IOBuffer>, unsigned>> send_queue_;
noamsml@chromium.org245b164e2013-06-13 22:31:42109 };
110
111 // Callback for handling a datagram being received on either ipv4 or ipv6.
112 void OnDatagramReceived(DnsResponse* response,
113 const IPEndPoint& recv_addr,
114 int bytes_read);
115
vitalybuka20859742014-09-22 23:42:30116 void PostOnError(SocketHandler* loop, int rv);
117 void OnError(int rv);
noamsml@chromium.org245b164e2013-06-13 22:31:42118
vitalybuka@chromium.orge4411fbe2013-09-26 21:10:11119 // Only socket handlers which successfully bound and started are kept.
danakj22f90e72016-04-16 01:55:40120 std::vector<std::unique_ptr<SocketHandler>> socket_handlers_;
noamsml@chromium.org245b164e2013-06-13 22:31:42121
Keishi Hattori0e45c022021-11-27 09:25:52122 raw_ptr<Delegate> delegate_;
noamsml@chromium.org245b164e2013-06-13 22:31:42123
Jeremy Romand54000b22019-07-08 18:40:16124 base::WeakPtrFactory<MDnsConnection> weak_ptr_factory_{this};
noamsml@chromium.org245b164e2013-06-13 22:31:42125};
126
127class MDnsListenerImpl;
128
noamsml@chromium.orgba77c27f2013-07-02 22:34:32129class NET_EXPORT_PRIVATE MDnsClientImpl : public MDnsClient {
noamsml@chromium.org245b164e2013-06-13 22:31:42130 public:
noamsml@chromium.org21df16962013-07-01 17:39:53131 // The core object exists while the MDnsClient is listening, and is deleted
132 // whenever the number of listeners reaches zero. The deletion happens
133 // asychronously, so destroying the last listener does not immediately
134 // invalidate the core.
Dave Tapuska61bdb9e2024-06-17 14:54:02135 class Core final : public MDnsConnection::Delegate {
noamsml@chromium.org245b164e2013-06-13 22:31:42136 public:
tzik08d8d6e2018-07-09 04:11:47137 Core(base::Clock* clock, base::OneShotTimer* timer);
Peter Boström293b1342021-09-22 17:31:43138
139 Core(const Core&) = delete;
140 Core& operator=(const Core&) = delete;
141
dcheng67be2b1f2014-10-27 21:47:29142 ~Core() override;
noamsml@chromium.org245b164e2013-06-13 22:31:42143
Eric Orthe857ebb2019-03-13 23:02:07144 // Initialize the core.
145 int Init(MDnsSocketFactory* socket_factory);
noamsml@chromium.org245b164e2013-06-13 22:31:42146
147 // Send a query with a specific rrtype and name. Returns true on success.
Avi Drissman13fc8932015-12-20 04:40:46148 bool SendQuery(uint16_t rrtype, const std::string& name);
noamsml@chromium.org245b164e2013-06-13 22:31:42149
noamsml@chromium.org21df16962013-07-01 17:39:53150 // Add/remove a listener to the list of listeners.
noamsml@chromium.org245b164e2013-06-13 22:31:42151 void AddListener(MDnsListenerImpl* listener);
152 void RemoveListener(MDnsListenerImpl* listener);
153
154 // Query the cache for records of a specific type and name.
Avi Drissman13fc8932015-12-20 04:40:46155 void QueryCache(uint16_t rrtype,
156 const std::string& name,
noamsml@chromium.org245b164e2013-06-13 22:31:42157 std::vector<const RecordParsed*>* records) const;
158
159 // Parse the response and alert relevant listeners.
dcheng67be2b1f2014-10-27 21:47:29160 void HandlePacket(DnsResponse* response, int bytes_read) override;
noamsml@chromium.org245b164e2013-06-13 22:31:42161
dcheng67be2b1f2014-10-27 21:47:29162 void OnConnectionError(int error) override;
noamsml@chromium.org245b164e2013-06-13 22:31:42163
Eric Orthacdd8ae2019-03-29 22:07:19164 MDnsCache* cache_for_testing() { return &cache_; }
165
noamsml@chromium.org245b164e2013-06-13 22:31:42166 private:
kmarshall3e740be2015-03-02 21:30:44167 FRIEND_TEST_ALL_PREFIXES(MDnsTest, CacheCleanupWithShortTTL);
168
Piotr Pawliczek3318cc92020-07-25 05:10:13169 class ListenerKey {
170 public:
171 ListenerKey(const std::string& name, uint16_t type);
172 ListenerKey(const ListenerKey&) = default;
173 ListenerKey(ListenerKey&&) = default;
174 bool operator<(const ListenerKey& key) const;
175 const std::string& name_lowercase() const { return name_lowercase_; }
176 uint16_t type() const { return type_; }
177
178 private:
179 std::string name_lowercase_;
180 uint16_t type_;
181 };
Trent Apteda250ec3ab2018-08-19 08:52:19182 typedef base::ObserverList<MDnsListenerImpl>::Unchecked ObserverListType;
183 typedef std::map<ListenerKey, std::unique_ptr<ObserverListType>>
brettw236d3172015-06-03 16:31:43184 ListenerMap;
noamsml@chromium.org245b164e2013-06-13 22:31:42185
186 // Alert listeners of an update to the cache.
noamsml@chromium.orgbdd6c3d2014-01-30 08:07:42187 void AlertListeners(MDnsCache::UpdateType update_type,
noamsml@chromium.org245b164e2013-06-13 22:31:42188 const ListenerKey& key, const RecordParsed* record);
189
190 // Schedule a cache cleanup to a specific time, cancelling other cleanups.
191 void ScheduleCleanup(base::Time cleanup);
192
193 // Clean up the cache and schedule a new cleanup.
194 void DoCleanup();
195
196 // Callback for when a record is removed from the cache.
197 void OnRecordRemoved(const RecordParsed* record);
198
noamsml@chromium.org21df16962013-07-01 17:39:53199 void NotifyNsecRecord(const RecordParsed* record);
200
201 // Delete and erase the observer list for |key|. Only deletes the observer
202 // list if is empty.
203 void CleanupObserverList(const ListenerKey& key);
204
noamsml@chromium.org245b164e2013-06-13 22:31:42205 ListenerMap listeners_;
206
noamsml@chromium.org245b164e2013-06-13 22:31:42207 MDnsCache cache_;
208
Keishi Hattori0e45c022021-11-27 09:25:52209 raw_ptr<base::Clock> clock_;
210 raw_ptr<base::OneShotTimer> cleanup_timer_;
noamsml@chromium.org245b164e2013-06-13 22:31:42211 base::Time scheduled_cleanup_;
212
danakj22f90e72016-04-16 01:55:40213 std::unique_ptr<MDnsConnection> connection_;
Dave Tapuska61bdb9e2024-06-17 14:54:02214 base::WeakPtrFactory<Core> weak_ptr_factory_{this};
noamsml@chromium.org245b164e2013-06-13 22:31:42215 };
216
vitalybuka@chromium.org95b331b42013-12-02 06:26:31217 MDnsClientImpl();
Eric Orth026776a2019-01-18 00:13:28218
219 // Test constructor, takes a mock clock and mock timer.
220 MDnsClientImpl(base::Clock* clock,
221 std::unique_ptr<base::OneShotTimer> cleanup_timer);
222
Peter Boström407869b2021-10-07 04:42:48223 MDnsClientImpl(const MDnsClientImpl&) = delete;
224 MDnsClientImpl& operator=(const MDnsClientImpl&) = delete;
225
dcheng67be2b1f2014-10-27 21:47:29226 ~MDnsClientImpl() override;
noamsml@chromium.org245b164e2013-06-13 22:31:42227
228 // MDnsClient implementation:
danakj22f90e72016-04-16 01:55:40229 std::unique_ptr<MDnsListener> CreateListener(
Avi Drissman13fc8932015-12-20 04:40:46230 uint16_t rrtype,
noamsml@chromium.org245b164e2013-06-13 22:31:42231 const std::string& name,
mostynbba063d6032014-10-09 11:01:13232 MDnsListener::Delegate* delegate) override;
noamsml@chromium.org245b164e2013-06-13 22:31:42233
danakj22f90e72016-04-16 01:55:40234 std::unique_ptr<MDnsTransaction> CreateTransaction(
Avi Drissman13fc8932015-12-20 04:40:46235 uint16_t rrtype,
noamsml@chromium.org245b164e2013-06-13 22:31:42236 const std::string& name,
237 int flags,
mostynbba063d6032014-10-09 11:01:13238 const MDnsTransaction::ResultCallback& callback) override;
noamsml@chromium.org245b164e2013-06-13 22:31:42239
Eric Orthe857ebb2019-03-13 23:02:07240 int StartListening(MDnsSocketFactory* socket_factory) override;
dcheng67be2b1f2014-10-27 21:47:29241 void StopListening() override;
242 bool IsListening() const override;
noamsml@chromium.org245b164e2013-06-13 22:31:42243
244 Core* core() { return core_.get(); }
245
246 private:
Keishi Hattori0e45c022021-11-27 09:25:52247 raw_ptr<base::Clock> clock_;
tzik08d8d6e2018-07-09 04:11:47248 std::unique_ptr<base::OneShotTimer> cleanup_timer_;
noamsml@chromium.org245b164e2013-06-13 22:31:42249
Eric Orth6cb27ea2019-05-03 16:31:04250 std::unique_ptr<Core> core_;
noamsml@chromium.org245b164e2013-06-13 22:31:42251};
252
Dave Tapuska61bdb9e2024-06-17 14:54:02253class MDnsListenerImpl final : public MDnsListener {
noamsml@chromium.org245b164e2013-06-13 22:31:42254 public:
Avi Drissman13fc8932015-12-20 04:40:46255 MDnsListenerImpl(uint16_t rrtype,
noamsml@chromium.org245b164e2013-06-13 22:31:42256 const std::string& name,
kmarshall3e740be2015-03-02 21:30:44257 base::Clock* clock,
noamsml@chromium.org245b164e2013-06-13 22:31:42258 MDnsListener::Delegate* delegate,
259 MDnsClientImpl* client);
260
Peter Boström293b1342021-09-22 17:31:43261 MDnsListenerImpl(const MDnsListenerImpl&) = delete;
262 MDnsListenerImpl& operator=(const MDnsListenerImpl&) = delete;
263
dcheng67be2b1f2014-10-27 21:47:29264 ~MDnsListenerImpl() override;
noamsml@chromium.org245b164e2013-06-13 22:31:42265
266 // MDnsListener implementation:
dcheng67be2b1f2014-10-27 21:47:29267 bool Start() override;
noamsml@chromium.org245b164e2013-06-13 22:31:42268
noamsml@chromium.orgbdd6c3d2014-01-30 08:07:42269 // Actively refresh any received records.
dcheng67be2b1f2014-10-27 21:47:29270 void SetActiveRefresh(bool active_refresh) override;
noamsml@chromium.orgbdd6c3d2014-01-30 08:07:42271
dcheng67be2b1f2014-10-27 21:47:29272 const std::string& GetName() const override;
noamsml@chromium.org245b164e2013-06-13 22:31:42273
Avi Drissman13fc8932015-12-20 04:40:46274 uint16_t GetType() const override;
noamsml@chromium.org245b164e2013-06-13 22:31:42275
276 MDnsListener::Delegate* delegate() { return delegate_; }
277
278 // Alert the delegate of a record update.
noamsml@chromium.orgbdd6c3d2014-01-30 08:07:42279 void HandleRecordUpdate(MDnsCache::UpdateType update_type,
280 const RecordParsed* record_parsed);
noamsml@chromium.org21df16962013-07-01 17:39:53281
282 // Alert the delegate of the existence of an Nsec record.
283 void AlertNsecRecord();
284
noamsml@chromium.org245b164e2013-06-13 22:31:42285 private:
noamsml@chromium.orgbdd6c3d2014-01-30 08:07:42286 void ScheduleNextRefresh();
287 void DoRefresh();
288
Avi Drissman13fc8932015-12-20 04:40:46289 uint16_t rrtype_;
noamsml@chromium.org245b164e2013-06-13 22:31:42290 std::string name_;
Keishi Hattori0e45c022021-11-27 09:25:52291 raw_ptr<base::Clock> clock_;
292 raw_ptr<MDnsClientImpl> client_;
293 raw_ptr<MDnsListener::Delegate> delegate_;
noamsml@chromium.org245b164e2013-06-13 22:31:42294
noamsml@chromium.orgbdd6c3d2014-01-30 08:07:42295 base::Time last_update_;
Avi Drissman13fc8932015-12-20 04:40:46296 uint32_t ttl_;
Tsuyoshi Horodbef87992022-06-09 01:39:41297 bool started_ = false;
298 bool active_refresh_ = false;
noamsml@chromium.orgbdd6c3d2014-01-30 08:07:42299
Alex Turner3ae74622020-11-25 15:42:24300 base::CancelableRepeatingClosure next_refresh_;
Dave Tapuska61bdb9e2024-06-17 14:54:02301 base::WeakPtrFactory<MDnsListenerImpl> weak_ptr_factory_{this};
noamsml@chromium.org245b164e2013-06-13 22:31:42302};
303
Dave Tapuska61bdb9e2024-06-17 14:54:02304class MDnsTransactionImpl final : public MDnsTransaction,
305 public MDnsListener::Delegate {
noamsml@chromium.org245b164e2013-06-13 22:31:42306 public:
Avi Drissman13fc8932015-12-20 04:40:46307 MDnsTransactionImpl(uint16_t rrtype,
noamsml@chromium.org245b164e2013-06-13 22:31:42308 const std::string& name,
309 int flags,
310 const MDnsTransaction::ResultCallback& callback,
311 MDnsClientImpl* client);
Peter Boström293b1342021-09-22 17:31:43312
313 MDnsTransactionImpl(const MDnsTransactionImpl&) = delete;
314 MDnsTransactionImpl& operator=(const MDnsTransactionImpl&) = delete;
315
dcheng67be2b1f2014-10-27 21:47:29316 ~MDnsTransactionImpl() override;
noamsml@chromium.org245b164e2013-06-13 22:31:42317
318 // MDnsTransaction implementation:
dcheng67be2b1f2014-10-27 21:47:29319 bool Start() override;
noamsml@chromium.org245b164e2013-06-13 22:31:42320
dcheng67be2b1f2014-10-27 21:47:29321 const std::string& GetName() const override;
Avi Drissman13fc8932015-12-20 04:40:46322 uint16_t GetType() const override;
noamsml@chromium.org245b164e2013-06-13 22:31:42323
324 // MDnsListener::Delegate implementation:
dcheng67be2b1f2014-10-27 21:47:29325 void OnRecordUpdate(MDnsListener::UpdateType update,
326 const RecordParsed* record) override;
327 void OnNsecRecord(const std::string& name, unsigned type) override;
noamsml@chromium.org245b164e2013-06-13 22:31:42328
dcheng67be2b1f2014-10-27 21:47:29329 void OnCachePurged() override;
noamsml@chromium.org245b164e2013-06-13 22:31:42330
331 private:
332 bool is_active() { return !callback_.is_null(); }
333
334 void Reset();
335
336 // Trigger the callback and reset all related variables.
337 void TriggerCallback(MDnsTransaction::Result result,
338 const RecordParsed* record);
339
340 // Internal callback for when a cache record is found.
341 void CacheRecordFound(const RecordParsed* record);
342
343 // Signal the transactionis over and release all related resources.
344 void SignalTransactionOver();
345
noamsml@chromium.orgf3c09992013-06-25 00:40:48346 // Reads records from the cache and calls the callback for every
347 // record read.
348 void ServeRecordsFromCache();
349
350 // Send a query to the network and set up a timeout to time out the
351 // transaction. Returns false if it fails to start listening on the network
352 // or if it fails to send a query.
353 bool QueryAndListen();
354
Avi Drissman13fc8932015-12-20 04:40:46355 uint16_t rrtype_;
noamsml@chromium.org245b164e2013-06-13 22:31:42356 std::string name_;
357 MDnsTransaction::ResultCallback callback_;
358
danakj22f90e72016-04-16 01:55:40359 std::unique_ptr<MDnsListener> listener_;
Steve Kobesf5bea3e2020-07-08 20:15:43360 base::CancelableOnceCallback<void()> timeout_;
noamsml@chromium.org245b164e2013-06-13 22:31:42361
Keishi Hattori0e45c022021-11-27 09:25:52362 raw_ptr<MDnsClientImpl> client_;
noamsml@chromium.org245b164e2013-06-13 22:31:42363
Tsuyoshi Horodbef87992022-06-09 01:39:41364 bool started_ = false;
noamsml@chromium.org245b164e2013-06-13 22:31:42365 int flags_;
Dave Tapuska61bdb9e2024-06-17 14:54:02366 base::WeakPtrFactory<MDnsTransactionImpl> weak_ptr_factory_{this};
noamsml@chromium.org245b164e2013-06-13 22:31:42367};
368
369} // namespace net
370#endif // NET_DNS_MDNS_CLIENT_IMPL_H_