1 /* 2 This file is part of Telegram Desktop, 3 the official desktop application for the Telegram messaging service. 4 5 For license and copyright information please follow this link: 6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL 7 */ 8 #pragma once 9 10 #include "base/weak_ptr.h" 11 12 #include <QtCore/QPointer> 13 #include <QtNetwork/QNetworkReply> 14 #include <optional> 15 16 namespace MTP::details { 17 18 [[nodiscard]] const std::vector<QString> &DnsDomains(); 19 [[nodiscard]] QString GenerateDnsRandomPadding(); 20 [[nodiscard]] QByteArray DnsUserAgent(); 21 22 struct DnsEntry { 23 QString data; 24 crl::time TTL = 0; 25 }; 26 27 [[nodiscard]] std::vector<DnsEntry> ParseDnsResponse( 28 const QByteArray &bytes, 29 std::optional<int> typeRestriction = std::nullopt); 30 31 struct ServiceWebRequest { 32 ServiceWebRequest(not_null<QNetworkReply*> reply); 33 ServiceWebRequest(ServiceWebRequest &&other); 34 ServiceWebRequest &operator=(ServiceWebRequest &&other); 35 ~ServiceWebRequest(); 36 37 void destroy(); 38 39 QPointer<QNetworkReply> reply; 40 }; 41 42 class DomainResolver : public QObject { 43 public: 44 DomainResolver(Fn<void( 45 const QString &domain, 46 const QStringList &ips, 47 crl::time expireAt)> callback); 48 49 void resolve(const QString &domain); 50 51 private: 52 enum class Type { 53 Mozilla, 54 Google, 55 }; 56 struct Attempt { 57 Type type; 58 QString data; 59 QString host; 60 }; 61 struct AttemptKey { 62 QString domain; 63 bool ipv6 = false; 64 65 inline bool operator<(const AttemptKey &other) const { 66 return (domain < other.domain) 67 || (domain == other.domain && !ipv6 && other.ipv6); 68 } 69 inline bool operator==(const AttemptKey &other) const { 70 return (domain == other.domain) && (ipv6 == other.ipv6); 71 } 72 }; 73 struct CacheEntry { 74 QStringList ips; 75 crl::time expireAt = 0; 76 }; 77 struct Attempts { 78 std::vector<Attempt> list; 79 base::has_weak_ptr guard; 80 }; 81 82 void resolve(const AttemptKey &key); 83 void sendNextRequest(const AttemptKey &key); 84 void performRequest(const AttemptKey &key, const Attempt &attempt); 85 void checkExpireAndPushResult(const QString &domain); 86 void requestFinished( 87 const AttemptKey &key, 88 not_null<QNetworkReply*> reply); 89 QByteArray finalizeRequest( 90 const AttemptKey &key, 91 not_null<QNetworkReply*> reply); 92 93 Fn<void( 94 const QString &domain, 95 const QStringList &ips, 96 crl::time expireAt)> _callback; 97 98 QNetworkAccessManager _manager; 99 std::map<AttemptKey, Attempts> _attempts; 100 std::map<AttemptKey, std::vector<ServiceWebRequest>> _requests; 101 std::map<AttemptKey, CacheEntry> _cache; 102 crl::time _lastTimestamp = 0; 103 104 }; 105 106 } // namespace MTP::details 107