aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Common/CaresPTRResolver.h
blob: 24a5e422ca8bb480dc2f0c36f945f831d844bfd9 (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
#pragma once

#include <span>
#include <poll.h>
#include <mutex>
#include "DNSPTRResolver.h"

using ares_channel = struct ares_channeldata *;

namespace DB
{

    /*
     * Implements reverse DNS resolution using c-ares lib. System reverse DNS resolution via
     * gethostbyaddr or getnameinfo does not work reliably because in some systems
     * it returns all PTR records for a given IP and in others it returns only one.
     * */
    class CaresPTRResolver : public DNSPTRResolver
    {
        friend class DNSPTRResolverProvider;

        /*
         * Allow only DNSPTRProvider to instantiate this class
         * */
        struct provider_token {};

        static constexpr auto C_ARES_POLL_EVENTS = POLLRDNORM | POLLIN;

    public:
        explicit CaresPTRResolver(provider_token);

        /*
         * Library initialization is currently done only once in the constructor. Multiple instances of CaresPTRResolver
         * will be used in the lifetime of ClickHouse, thus it's problematic to have de-init here.
         * In a practical view, it makes little to no sense to de-init a DNS library since DNS requests will happen
         * until the end of the program. Hence, ares_library_cleanup() will not be called.
         * */
        ~CaresPTRResolver() override = default;

        std::unordered_set<std::string> resolve(const std::string & ip) override;

        std::unordered_set<std::string> resolve_v6(const std::string & ip) override;

    private:
        bool wait_and_process(ares_channel channel);

        void cancel_requests(ares_channel channel);

        void resolve(const std::string & ip, std::unordered_set<std::string> & response, ares_channel channel);

        void resolve_v6(const std::string & ip, std::unordered_set<std::string> & response, ares_channel channel);

        std::span<pollfd> get_readable_sockets(int * sockets, pollfd * pollfd, ares_channel channel);

        int64_t calculate_timeout(ares_channel channel);

        void process_possible_timeout(ares_channel channel);

        void process_readable_sockets(std::span<pollfd> readable_sockets, ares_channel channel);
    };
}