#pragma once #include #include #include #include #include #include #include #include namespace ts::dns { class DNSServer; class DNSServerBinding { friend class DNSServer; private: struct BindingBuffer { BindingBuffer* next{nullptr}; sockaddr_storage target{}; size_t size{0}; }; public: DNSServer* server{nullptr}; std::shared_ptr self{nullptr}; sockaddr_storage address{}; int socket{0}; std::string error{}; inline bool active() const { return this->socket != 0; } std::mutex io_lock{}; event* read_event{nullptr}; event* write_event{nullptr}; BindingBuffer* write_buffer_head{nullptr}; BindingBuffer* write_buffer_tail{nullptr}; void send(const sockaddr_storage& /* target */, const void* /* buffer */, size_t /* length */); }; class DNSHandler; class DNSServer { public: DNSServer(std::shared_ptr handler) : handler{std::move(handler)} {}; virtual ~DNSServer(); bool start(const std::vector& /* bindings */, std::string& /* error */); void stop(); [[nodiscard]] const std::vector>& bindings() const { return this->_bindings; } private: std::shared_ptr handler; std::mutex bind_lock{}; std::vector> _bindings; bool started{false}; std::thread event_base_executor{}; struct event* event_base_ticker{nullptr}; struct event_base* event_base{nullptr}; bool bind(DNSServerBinding& /* binding */, std::string& /* error */); void unbind(DNSServerBinding& /* binding */); void event_cb_timer(); static void event_cb_read(evutil_socket_t fd, short, void *binding); static void event_cb_write(evutil_socket_t fd, short, void *binding); void event_executor(); }; }