aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/coroutine/dns/helpers.cpp
blob: 21d17b5d6748e948e63cc223ec96631ffac9afed (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include "helpers.h"
#include "coro.h"
#include "async.h"
#include "cache.h"

#include <util/digest/city.h>
#include <util/generic/hash_set.h>

using namespace NAddr;
using namespace NAsyncDns;

namespace {
    typedef ui64 TAddrHash;

    inline TAddrHash Hash(const IRemoteAddrRef& addr) {
        return CityHash64((const char*)addr->Addr(), addr->Len());
    }

    inline IRemoteAddrRef ConstructIP4(void* data, ui16 port) {
        return new TIPv4Addr(TIpAddress(*(ui32*)data, port));
    }

    inline IRemoteAddrRef ConstructIP6(void* data, ui16 port) {
        sockaddr_in6 res;

        Zero(res);

        res.sin6_family = AF_INET6;
        res.sin6_port = HostToInet(port);
        memcpy(&res.sin6_addr.s6_addr, data, sizeof(res.sin6_addr.s6_addr));

        return new TIPv6Addr(res);
    }

    inline IRemoteAddrRef Construct(const hostent* h, void* data, ui16 port) {
        switch (h->h_addrtype) {
            case AF_INET:
                return ConstructIP4(data, port);

            case AF_INET6:
                return ConstructIP6(data, port);
        }

        //real shit happens
        abort();
    }

    template <class It, class T>
    static bool FindByHash(It b, It e, T t) {
        while (b != e) {
            if (Hash(*b) == t) {
                return true;
            }

            ++b;
        }

        return false;
    }

    inline size_t LstLen(char** lst) noexcept {
        size_t ret = 0;

        while (*lst) {
            ++ret;
            ++lst;
        }

        return ret;
    }
}

void TResolveAddr::OnComplete(const TResult& r) {
    const hostent* h = r.Result;

    if (!h) {
        Status.push_back(r.Status);

        return;
    }

    char** lst = h->h_addr_list;

    typedef THashSet<TAddrHash> THashes;
    TAutoPtr<THashes> hashes;

    if ((Result.size() + LstLen(lst)) > 8) {
        hashes.Reset(new THashes());

        for (const auto& it : Result) {
            hashes->insert(Hash(it));
        }
    }

    while (*lst) {
        IRemoteAddrRef addr = Construct(h, *lst, Port);

        if (!hashes) {
            if (!FindByHash(Result.begin(), Result.end(), Hash(addr))) {
                Result.push_back(addr);
            }
        } else {
            const TAddrHash h = Hash(addr);

            if (hashes->find(h) == hashes->end()) {
                hashes->insert(h);
                Result.push_back(addr);
            }
        }

        ++lst;
    }
}

void NAsyncDns::ResolveAddr(TContResolver& resolver, const TString& host, ui16 port, TAddrs& result) {
    TResolveAddr cb(port);

    resolver.Resolve(TNameRequest(host.data(), AF_UNSPEC, &cb));

    if (cb.Result) {
        for (auto status : cb.Status) {
            //we have some results, so skip empty responses for aaaa requests
            CheckPartialAsyncStatus(status);
        }
    } else {
        for (auto status : cb.Status) {
            CheckAsyncStatus(status);
        }
    }

    cb.Result.swap(result);
}

void NAsyncDns::ResolveAddr(TContResolver& resolver, const TString& addr, TAddrs& result) {
    ResolveAddr(resolver, addr, 80, result);
}

void NAsyncDns::ResolveAddr(TContResolver& resolver, const TString& host, ui16 port, TAddrs& result, TContDnsCache* cache) {
    if (cache) {
        cache->LookupOrResolve(resolver, host, port, result);
    } else {
        ResolveAddr(resolver, host, port, result);
    }
}

void NAsyncDns::ResolveAddr(TContResolver& resolver, const TString& addr, TAddrs& result, TContDnsCache* cache) {
    ResolveAddr(resolver, addr, 80, result, cache);
}