NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
dns_client.hpp
浏览该文件的文档.
1#ifndef NEFORCE_NETWORK_DNS_DNS_CLIENT_HPP__
2#define NEFORCE_NETWORK_DNS_DNS_CLIENT_HPP__
3
11
25NEFORCE_BEGIN_NAMESPACE__
26
31
46class NEFORCE_API dns_client {
47public:
52 struct config {
53 string server{"8.8.8.8"};
56 };
57
58private:
66 struct dns_query_op : enable_shared_from_this<dns_query_op> {
67 dns_client* client;
68 string domain;
69 dns_record::raw type;
70 dns_class qclass;
71 function<void(error_code, dns_query_result)> handler;
72 cancellation_slot* cancel_slot{nullptr};
73 atomic<bool> fired_{false};
74 uint16_t query_id_{0};
75 byte_vector query_data_;
76 size_t timer_id_{0};
77 steady_clock::time_point start_time_;
78
79 void start();
80 void on_response(error_code ec, dns_query_result result);
81 void on_timeout();
82 void do_cancel();
83 };
84
85 struct pending_entry {
86 weak_ptr<dns_query_op> op;
87 byte_vector query_data;
88 steady_clock::time_point created_at{steady_clock::now()};
89 };
90
91 config config_{};
92 unordered_map<string, pair<dns_query_result, steady_clock::time_point>> cache_;
93 mutable shared_mutex cache_mutex_;
94 seconds cache_ttl_{300};
95 bool use_tcp_ = false;
96
97 bool recursion_desired_ = true;
98 uint16_t edns_udp_payload_{edns::DEFAULT_UDP_PAYLOAD};
99 bool dnssec_ok_ = false;
100
101 udp_socket shared_socket_;
102 unordered_map<uint16_t, pending_entry> pending_queries_;
103 mutable mutex pending_mutex_;
104 mutable mutex send_mutex_;
105 io_context* ctx_{nullptr};
106 atomic<bool> io_running_{false};
107
108private:
109 void ensure_io_started();
110 void start_io();
111 void stop_io();
112 void register_shared_receive();
113 void on_udp_readable(error_code ec);
114 void process_udp_receive();
115 void dispatch_to_op(uint16_t txid, byte_vector response);
116 void unregister_query(uint16_t txid);
117
118 void send_query(const byte_vector& query);
119 byte_vector send_tcp_query(const byte_vector& query);
120
121 optional<dns_query_result> check_cache(const string& key);
122 void update_cache(const string& key, const dns_query_result& result);
123
124public:
130 dns_client() = default;
131
139 explicit dns_client(config cfg, io_context& ctx, bool use_tcp = false);
140
141 ~dns_client();
142
143 dns_client(const dns_client&) = delete;
144 dns_client& operator=(const dns_client&) = delete;
145 dns_client(dns_client&&) = delete;
146 dns_client& operator=(dns_client&&) = delete;
147
152 void set_config(config cfg) noexcept { config_ = move(cfg); }
153
158 void set_timeout(const milliseconds timeout) noexcept { config_.timeout = timeout; }
159
164 void set_use_tcp(const bool use_tcp) noexcept { use_tcp_ = use_tcp; }
165
170 void set_cache_ttl(const seconds ttl) noexcept { cache_ttl_ = ttl; }
171
176 void set_recursion_desired(const bool rd) { recursion_desired_ = rd; }
177
182 void set_edns_udp_payload(const uint16_t payload_size) noexcept { edns_udp_payload_ = payload_size; }
183
188 void set_dnssec_ok(const bool ok) noexcept { dnssec_ok_ = ok; }
189
193 void clear_cache() noexcept { cache_.clear(); }
194
205
215
224 function<void(error_code, dns_query_result)> handler);
225
235 function<void(error_code, dns_query_result)> handler);
236
245 template <typename Token,
247 void async_query(string_view domain, dns_record::raw type, dns_class qclass, Token&& token) {
248 async_query(domain, type, qclass, function<void(error_code, dns_query_result)>(forward<Token>(token)));
249 }
250
259
267
268#ifdef NEFORCE_STANDARD_20
277#endif
278
285
292
299
306
313
320
327
338
348
361 dns_class qclass = dns_class::INTERNET, bool rd = true, bool edns_enable = true,
362 bool dnssec_ok = false, uint16_t edns_payload = edns::DEFAULT_UDP_PAYLOAD);
363
371 static dns_query_result parse_response(const byte_vector& response, uint16_t expected_id = 0);
372};
373
374
375NEFORCE_BEGIN_INNER__
376
377template <>
378struct future_handler<error_code, dns_query_result> {
380
381 void operator()(error_code ec, dns_query_result result) {
382 if (ec) {
383 promise_->set_exception(make_exception_ptr(system_exception(ec)));
384 } else {
385 promise_->set_value(move(result));
386 }
387 }
388};
389
390NEFORCE_END_INNER__
391
392template <>
393struct async_result<use_future_t, void(error_code, dns_query_result)> {
394 using handler_type = inner::future_handler<error_code, dns_query_result>;
395 using return_type = future<dns_query_result>;
396 handler_type handler_;
397 explicit async_result(use_future_t /*unused*/) { handler_.promise_ = make_shared<promise<dns_query_result>>(); }
398 handler_type get_handler() { return handler_; }
399 return_type get() { return handler_.promise_->get_future(); }
400};
401 // DNS
403
404NEFORCE_END_NAMESPACE__
405#endif // NEFORCE_NETWORK_DNS_DNS_CLIENT_HPP__
异步操作取消槽
auto async_query(string_view domain, dns_record::raw type, dns_class qclass, use_future_t)
异步DNS查询——use_future
void set_dnssec_ok(const bool ok) noexcept
设置是否请求DNSSEC(DO)
void async_query(string_view domain, dns_record::raw type, dns_class qclass, detached_t)
异步DNS查询——detached(即发即忘)
optional< dns_soa_record > resolve_soa(string_view domain)
解析SOA记录(授权区域起始)
dns_client()=default
默认构造函数
dns_query_result query(string_view domain, dns_record::raw type=dns_record::A, dns_class qclass=dns_class::INTERNET)
执行DNS查询
static dns_query_result parse_response(const byte_vector &response, uint16_t expected_id=0)
解析DNS响应消息
void set_use_tcp(const bool use_tcp) noexcept
设置是否使用TCP
void clear_cache() noexcept
清空缓存
vector< string > resolve_mx(string_view domain)
解析MX记录(邮件交换器)
void set_cache_ttl(const seconds ttl) noexcept
设置缓存TTL
vector< dns_query_result > batch_query(const vector< string > &domains, dns_record::raw type=dns_record::A)
批量查询
vector< string > resolve_aaaa(string_view domain)
解析AAAA记录(IPv6地址)
static byte_vector build_query(string_view domain, dns_record::raw type=dns_record::A, dns_class qclass=dns_class::INTERNET, bool rd=true, bool edns_enable=true, bool dnssec_ok=false, uint16_t edns_payload=edns::DEFAULT_UDP_PAYLOAD)
构建DNS查询消息
vector< string > resolve_cname(string_view domain)
解析CNAME记录(别名)
dns_client(config cfg, io_context &ctx, bool use_tcp=false)
构造函数
void async_query(string_view domain, dns_record::raw type, dns_class qclass, function< void(error_code, dns_query_result)> handler)
异步DNS查询——回调完成
void set_config(config cfg) noexcept
设置客户端配置
future< dns_query_result > query_async(const string &domain, dns_record::raw type=dns_record::A, dns_class qclass=dns_class::INTERNET)
异步DNS查询(遗留 API——返回 future)
void async_query(string_view domain, dns_record::raw type, dns_class qclass, Token &&token)
异步DNS查询——任意完成令牌
void set_recursion_desired(const bool rd)
设置是否期望递归查询(RD)
vector< string > resolve_a(string_view domain)
解析A记录(IPv4地址)
vector< string > resolve_txt(string_view domain)
解析TXT记录(文本记录)
void set_edns_udp_payload(const uint16_t payload_size) noexcept
设置EDNS0 UDP载荷大小
void set_timeout(const milliseconds timeout) noexcept
设置超时时间
string reverse_query(string_view ip)
反向查询(从IP获取域名)
auto async_query(string_view domain, dns_record::raw type, dns_class qclass, use_awaitable_t)
异步DNS查询——use_awaitable
void async_query(string_view domain, dns_record::raw type, dns_class qclass, cancellation_slot &slot, function< void(error_code, dns_query_result)> handler)
异步DNS查询——回调完成 + 取消槽
vector< dns_srv_record > resolve_srv(string_view domain)
解析SRV记录(服务定位器)
函数包装器主模板声明
独占future类模板
统一异步操作核心
共享智能指针类模板
动态大小数组容器
时钟类型
DNS协议消息定义
constexpr uint16_t DEFAULT_UDP_PAYLOAD
默认UDP载荷大小(RFC 6891 建议值)
异步结果消费者
constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
enable_if_t< is_void_v< T >, future_result_t< T > > get(future< T > &f)
通用future结果获取函数
vector< byte_t > byte_vector
字节向量类型别名
unsigned short uint16_t
16位无符号整数类型
dns_class
DNS查询类枚举
duration< int64_t > seconds
秒持续时间
duration< int64_t, milli > milliseconds
毫秒持续时间
exception_ptr make_exception_ptr(Ex ex) noexcept
创建异常指针
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
basic_string_view< char > string_view
字符字符串视图
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名
统一异步操作核心
可选值类型
网络端口定义和转换工具
异步结果生产者
共享互斥锁支持
fire-and-forget 完成令牌
milliseconds timeout
查询超时时间
string server
DNS服务器地址
ports port
DNS服务器端口
raw
DNS记录类型枚举
启用从this创建共享指针的基类
网络端口封装类
@ DNS
DNS协议端口
协程 awaitable 完成令牌
返回 future<T> 的完成令牌
UDP Socket实现
无序映射容器
协程 awaitable 完成令牌
弱智能指针实现