summaryrefslogtreecommitdiffstats
path: root/library/cpp/coroutine/dns/async.cpp
diff options
context:
space:
mode:
authorqrort <[email protected]>2022-11-30 23:47:12 +0300
committerqrort <[email protected]>2022-11-30 23:47:12 +0300
commit22f8ae0e3f5d68b92aecccdf96c1d841a0334311 (patch)
treebffa27765faf54126ad44bcafa89fadecb7a73d7 /library/cpp/coroutine/dns/async.cpp
parent332b99e2173f0425444abb759eebcb2fafaa9209 (diff)
validate canons without yatest_common
Diffstat (limited to 'library/cpp/coroutine/dns/async.cpp')
-rw-r--r--library/cpp/coroutine/dns/async.cpp149
1 files changed, 149 insertions, 0 deletions
diff --git a/library/cpp/coroutine/dns/async.cpp b/library/cpp/coroutine/dns/async.cpp
new file mode 100644
index 00000000000..be35135828c
--- /dev/null
+++ b/library/cpp/coroutine/dns/async.cpp
@@ -0,0 +1,149 @@
+#include "async.h"
+
+#include <util/generic/singleton.h>
+#include <util/generic/vector.h>
+
+#include <contrib/libs/c-ares/include/ares.h>
+
+using namespace NAsyncDns;
+
+namespace {
+ struct TAresError: public TDnsError {
+ inline TAresError(int code) {
+ (*this) << ares_strerror(code);
+ }
+ };
+
+ struct TAresInit {
+ inline TAresInit() {
+ const int code = ares_library_init(ARES_LIB_INIT_ALL);
+
+ if (code) {
+ ythrow TAresError(code) << "can not init ares engine";
+ }
+ }
+
+ inline ~TAresInit() {
+ ares_library_cleanup();
+ }
+
+ static inline void InitOnce() {
+ Singleton<TAresInit>();
+ }
+ };
+}
+
+class TAsyncDns::TImpl {
+public:
+ inline TImpl(IPoller* poller, const TOptions& o)
+ : P_(poller)
+ {
+ TAresInit::InitOnce();
+
+ ares_options opts;
+
+ Zero(opts);
+
+ int optflags = 0;
+
+ optflags |= ARES_OPT_FLAGS;
+ opts.flags = ARES_FLAG_STAYOPEN;
+
+ optflags |= ARES_OPT_TIMEOUTMS;
+ opts.timeout = o.TimeOut.MilliSeconds();
+
+ optflags |= ARES_OPT_TRIES;
+ opts.tries = o.Retries;
+
+ optflags |= ARES_OPT_SOCK_STATE_CB;
+ opts.sock_state_cb = (decltype(opts.sock_state_cb))StateCb;
+ static_assert(sizeof(opts.sock_state_cb) == sizeof(&StateCb), "Inconsistent socket state size");
+ opts.sock_state_cb_data = this;
+
+ const int code = ares_init_options(&H_, &opts, optflags);
+
+ if (code) {
+ ythrow TAresError(code) << "can not init ares channel";
+ }
+ }
+
+ inline ~TImpl() {
+ ares_destroy(H_);
+ }
+
+ inline TDuration Timeout() {
+ struct timeval tv;
+ Zero(tv);
+
+ ares_timeout(H_, nullptr, &tv);
+
+ return TDuration(tv);
+ }
+
+ template <class T>
+ inline void ProcessSocket(T s) {
+ ares_process_fd(H_, s, s);
+ }
+
+ inline void ProcessNone() {
+ ProcessSocket(ARES_SOCKET_BAD);
+ }
+
+ inline void AsyncResolve(const TNameRequest& req) {
+ ares_gethostbyname(H_, req.Addr, req.Family, AsyncResolveHostCb, req.CB);
+ }
+
+private:
+ static void StateCb(void* arg, int s, int read, int write) {
+ ((TImpl*)arg)->P_->OnStateChange((SOCKET)s, (bool)read, (bool)write);
+ }
+
+ static void AsyncResolveHostCb(void* arg, int status, int timeouts, hostent* he) {
+ const IHostResult::TResult res = {
+ status, timeouts, he};
+
+ ((IHostResult*)arg)->OnComplete(res);
+ }
+
+private:
+ IPoller* P_;
+ ares_channel H_;
+};
+
+void NAsyncDns::CheckAsyncStatus(int status) {
+ if (status) {
+ ythrow TAresError(status);
+ }
+}
+
+void NAsyncDns::CheckPartialAsyncStatus(int status) {
+ if (status == ARES_ENODATA) {
+ return;
+ }
+
+ CheckAsyncStatus(status);
+}
+
+TAsyncDns::TAsyncDns(IPoller* poller, const TOptions& opts)
+ : I_(new TImpl(poller, opts))
+{
+}
+
+TAsyncDns::~TAsyncDns() {
+}
+
+void TAsyncDns::AsyncResolve(const TNameRequest& req) {
+ I_->AsyncResolve(req);
+}
+
+TDuration TAsyncDns::Timeout() {
+ return I_->Timeout();
+}
+
+void TAsyncDns::ProcessSocket(SOCKET s) {
+ I_->ProcessSocket(s);
+}
+
+void TAsyncDns::ProcessNone() {
+ I_->ProcessNone();
+}