libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
dnsresolver.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_NETWORK
13#include <cstdint>
14#include <promeki/namespace.h>
15#include <promeki/atomic.h>
16#include <promeki/dnscache.h>
17#include <promeki/dnsconfig.h>
18#include <promeki/dnsrecord.h>
19#include <promeki/duration.h>
20#include <promeki/enums_dns.h>
21#include <promeki/error.h>
22#include <promeki/list.h>
23#include <promeki/map.h>
25#include <promeki/objectbase.h>
26#include <promeki/result.h>
28#include <promeki/string.h>
29#include <promeki/uniqueptr.h>
30
31PROMEKI_NAMESPACE_BEGIN
32
33class DnsResolver;
34class MdnsManager;
35class TcpSocket;
36class UdpSocket;
37class TimerEvent;
38
71class DnsLookup : public ObjectBase {
72 PROMEKI_OBJECT(DnsLookup, ObjectBase)
73 public:
89 DnsLookup(DnsResolver *resolver, const String &name,
90 const DnsRecordType &type,
91 const DnsRecordClass &klass = DnsRecordClass::In);
92
93 ~DnsLookup() override;
94
96 const String &name() const { return _name; }
97
99 const DnsRecordType &type() const { return _type; }
100
102 const DnsRecordClass &klass() const { return _klass; }
103
111 const DnsRcode &rcode() const { return _rcode; }
112
123 void cancel();
124
126 bool isActive() const { return _active.value(); }
127
129 PROMEKI_SIGNAL(answered, List<DnsRecord>);
130
132 PROMEKI_SIGNAL(failed, Error);
133
134 protected:
136 void timerEvent(TimerEvent *e) override;
137
138 private:
139 friend class DnsResolver;
140
141 DnsResolver *_resolver = nullptr;
142 String _name;
143 DnsRecordType _type = DnsRecordType::A;
144 DnsRecordClass _klass = DnsRecordClass::In;
145 DnsRcode _rcode = DnsRcode::NoError;
146 Atomic<bool> _active;
147 Atomic<bool> _emitted;
148};
149
202class DnsResolver : public ObjectBase {
203 PROMEKI_OBJECT(DnsResolver, ObjectBase)
204 public:
206 static constexpr int MaxCnameDepth = 16;
207
209 static constexpr uint16_t Edns0UdpSize = 1232;
210
212 static constexpr int64_t DefaultAttemptTimeoutMs = 3000;
213
225 static DnsResolver *defaultInstance();
226
239 explicit DnsResolver(ObjectBase *parent = nullptr);
240
241 ~DnsResolver() override;
242
251 void setNameservers(const List<SocketAddress> &servers);
252
254 List<SocketAddress> nameservers() const;
255
257 void setSearchDomains(const StringList &domains);
258
260 StringList searchDomains() const;
261
263 void setConfig(const DnsConfig &cfg);
264
266 DnsConfig config() const;
267
274 Error reloadSystemConfig();
275
277 DnsCache &cache() { return _cache; }
279 const DnsCache &cache() const { return _cache; }
280
298 void setMdnsManager(MdnsManager *manager);
299
301 MdnsManager *mdnsManager() const;
302
324 void setMdnsRoutingEnabled(bool enable);
325
327 bool mdnsRoutingEnabled() const;
328
345 DnsLookup *lookup(const String &name,
346 const DnsRecordType &type = DnsRecordType::A,
347 const DnsRecordClass &klass = DnsRecordClass::In);
348
374 static Result<List<DnsRecord>> lookupSync(
375 const String &name,
376 const DnsRecordType &type = DnsRecordType::A,
377 const Duration &timeout = Duration::fromSeconds(5));
378
399 static Result<NetworkAddress> resolveSync(
400 const String &host,
401 NetworkAddress::FamilyPreference prefer = NetworkAddress::PreferIPv4,
402 const Duration &timeout = Duration::fromSeconds(5));
403
416 static Result<List<DnsRecord>> lookupReverseSync(
417 const NetworkAddress &addr,
418 const Duration &timeout = Duration::fromSeconds(5));
419
420 private:
421 friend class DnsLookup;
422
423 struct Inflight;
424
425 Error openSocketsIfNeeded();
426 void closeSockets();
427 void beginLookup(DnsLookup *lookup);
428 void beginAttempt(Inflight *flight);
429 bool isMdnsName(const String &name) const;
430 Error beginMdnsLookup(Inflight *flight);
431 void handleMdnsPacket(Inflight *flight, const Buffer &data);
432 MdnsManager *effectiveMdnsManager();
433 void onLookupTimeout(DnsLookup *lookup);
434 void failLookup(DnsLookup *lookup, Error err);
435 void succeedLookup(DnsLookup *lookup, const List<DnsRecord> &records);
436 void handleSocketReadable(UdpSocket *sock);
437 void processResponseBytes(const uint8_t *data, size_t len);
438 void followCname(Inflight *flight, const String &target);
439 void beginTcpFallback(Inflight *flight);
440 void removeInflight(DnsLookup *lookup);
441 uint16_t allocateTransactionId();
442 List<String> expandSearch(const String &name) const;
443 Error sendQueryUdp(Inflight *flight);
444 static List<DnsRecord> filterAnswerRecords(
445 const class DnsPacket &pkt,
446 const String &name, uint16_t type, uint16_t klass);
447 static Duration soaMinimumFromAuthority(const class DnsPacket &pkt);
448
449 mutable Mutex _cfgMtx;
450 DnsConfig _config;
451 DnsCache _cache;
452 UniquePtr<UdpSocket> _socketV4;
453 UniquePtr<UdpSocket> _socketV6;
454 int _ioHandleV4 = -1;
455 int _ioHandleV6 = -1;
456
457 // mDNS routing — populated lazily via
458 // @ref effectiveMdnsManager. @c _mdnsManager is the
459 // explicit override; when null we fall back to
460 // @ref Application::mdnsManager. The observer handle
461 // is registered with the manager on first .local.
462 // lookup and unregistered when the resolver dies.
463 MdnsManager *_mdnsManager = nullptr;
464 int _mdnsObserverHandle = -1;
465 bool _mdnsRoutingEnabled = true;
466
467 // In-flight bookkeeping: keyed by transaction id.
468 // The Inflight owns the timer; lookup ownership stays
469 // with the parent (this resolver). An Inflight is
470 // created when @ref beginLookup posts to our loop and
471 // destroyed when the lookup completes or is
472 // cancelled.
473 Map<uint16_t, Inflight *> _inflight;
474 Map<DnsLookup *, Inflight *> _byLookup;
475 uint16_t _nextTxId = 0;
476};
477
478PROMEKI_NAMESPACE_END
479
480#endif // PROMEKI_ENABLE_NETWORK