diff --git a/github b/github index 14645dc..a1490ab 160000 --- a/github +++ b/github @@ -1 +1 @@ -Subproject commit 14645dca78396c915ad4ad122d532f24fdfd2969 +Subproject commit a1490ab0d97f65e27845fec6daf88be8ed6d1014 diff --git a/native/dns/CMakeLists.txt b/native/dns/CMakeLists.txt index 54421cf..beb0293 100644 --- a/native/dns/CMakeLists.txt +++ b/native/dns/CMakeLists.txt @@ -1,17 +1,26 @@ set(MODULE_NAME "teaclient_dns") -set(SOURCE_FILES ${SOURCE_FILES} src/resolver.cpp src/types.cpp src/response.cpp utils.cpp src/resolver_linux.cpp) +set(SOURCE_FILES ${SOURCE_FILES} src/resolver.cpp src/types.cpp src/response.cpp utils.cpp) +if (WIN32) + set(SOURCE_FILES ${SOURCE_FILES} src/resolver_windows.cpp) +else() + set(SOURCE_FILES ${SOURCE_FILES} src/resolver_linux.cpp src/resolver_windows.cpp) +endif() find_package(Libevent REQUIRED) include_directories(${LIBEVENT_INCLUDE_DIRS}) -find_package(unbound REQUIRED) +if(NOT WIN32) + find_package(unbound REQUIRED) +endif() add_nodejs_module(${MODULE_NAME} binding.cc ${SOURCE_FILES}) -target_link_libraries(${MODULE_NAME} unbound::static ${LIBEVENT_STATIC_LIBRARIES} pthread) - add_executable(DNS-Test ${SOURCE_FILES} test/main.cpp) -target_link_libraries(DNS-Test unbound::static ssl crypto ${LIBEVENT_STATIC_LIBRARIES} pthread) -add_executable(DNS-Test2 test/crash.cpp) -target_link_libraries(DNS-Test2 unbound::static ssl crypto ${LIBEVENT_STATIC_LIBRARIES} pthread) \ No newline at end of file +if (WIN32) + target_link_libraries(${MODULE_NAME} ${LIBEVENT_STATIC_LIBRARIES} Ws2_32.lib Ntdll.lib Dnsapi.lib) + target_link_libraries(DNS-Test ${LIBEVENT_STATIC_LIBRARIES} Ws2_32.lib Ntdll.lib Dnsapi.lib) +else() + target_link_libraries(${MODULE_NAME} unbound::static ${LIBEVENT_STATIC_LIBRARIES} pthread) + target_link_libraries(DNS-Test unbound::static ssl crypto ${LIBEVENT_STATIC_LIBRARIES} pthread) +endif() \ No newline at end of file diff --git a/native/dns/binding.cc b/native/dns/binding.cc index a578b21..85593d6 100644 --- a/native/dns/binding.cc +++ b/native/dns/binding.cc @@ -21,7 +21,11 @@ NAN_METHOD(initialize) { return; } - //evthread_use_pthreads(); +#ifdef WIN32 + evthread_use_windows_threads(); +#else + evthread_use_pthreads(); +#endif resolver = make_unique(); string error; @@ -77,11 +81,11 @@ NAN_METHOD(query_connect_address) { tc::dns::cr(*resolver, tc::dns::ServerAddress{ *host, (uint16_t) port }, [callback = std::move(callback)] (bool success, std::variant data) mutable { - callback.call_cpy(success, success ? "" : std::get(data), !success ? tc::dns::ServerAddress{"", 0} : std::get(data)); + callback.call_cpy(success, success ? "" : std::get(data), !success ? tc::dns::ServerAddress{"", 0} : std::get(data), false); }); } -__attribute__((visibility("default"))) NAN_MODULE_INIT(init) { +NAN_MODULE_INIT(init) { Nan::Set(target, v8::String::NewFromUtf8(Nan::GetCurrentContext()->GetIsolate(), "resolve_cr").ToLocalChecked(), Nan::GetFunction(Nan::New(query_connect_address)).ToLocalChecked() diff --git a/native/dns/src/resolver.cpp b/native/dns/src/resolver.cpp index 306649a..227a8ac 100644 --- a/native/dns/src/resolver.cpp +++ b/native/dns/src/resolver.cpp @@ -4,19 +4,19 @@ #include #include #include -#include -#include #include #include #include #include /* for TSDNS */ -#include #ifdef WIN32 #include #define SOCK_NONBLOCK (0) #define MSG_DONTWAIT (0) #else + #include + #include + #include #include #endif @@ -29,6 +29,77 @@ Resolver::~Resolver() { this->finalize(); } + +bool Resolver::initialize(std::string &error, bool hosts, bool resolv) { + if(this->event.loop_active) + this->finalize(); + + this->event.loop_active = true; + this->event.base = event_base_new(); + if(!this->event.base) { + error = "failed to allcoate event base"; + return false; + } + this->event.loop = std::thread(std::bind(&Resolver::event_loop_runner, this)); + + return this->initialize_platform(error, hosts, resolv); +} + +void Resolver::finalize() { + this->event.loop_active = false; + if(this->event.base) { + auto ret = event_base_loopexit(this->event.base, nullptr); + if(ret != 0) { + cerr << "Failed to exit event base loop: " << ret << endl; + } + } + + { + this->event.condition.notify_one(); + if(this->event.loop.joinable()) + this->event.loop.join(); + } + + { + unique_lock lock(this->request_lock); + auto dns_list = std::move(this->dns_requests); + auto tsdns_list = std::move(this->tsdns_requests); + + for(auto entry : dns_list) { + entry->callback(ResultState::ABORT, 0, nullptr); + this->destroy_dns_request(entry); + } + + for(auto entry : tsdns_list) { + entry->callback(ResultState::ABORT, 0, ""); + this->destroy_tsdns_request(entry); + } + lock.unlock(); + } + + this->finalize_platform(); /* keep the event base allocated until platform depend finalize has been done */ + if(this->event.base) { + event_base_free(this->event.base); + this->event.base = nullptr; + } +} + +void Resolver::event_loop_runner() { + while(true) { + { + unique_lock lock{this->event.lock}; + if(!this->event.loop_active) + break; + + this->event.condition.wait(lock); + if(!this->event.loop_active) + break; + } + + event_base_loop(this->event.base, 0); + } +} + void Resolver::destroy_tsdns_request(Resolver::tsdns_request *request) { assert(this_thread::get_id() == this->event.loop.get_id() || !this->event.loop_active); @@ -58,8 +129,10 @@ void Resolver::destroy_tsdns_request(Resolver::tsdns_request *request) { if(request->socket > 0) { #ifndef WIN32 ::shutdown(request->socket, SHUT_RDWR); -#endif ::close(request->socket); +#else + closesocket(request->socket); +#endif request->socket = 0; } @@ -71,28 +144,42 @@ void Resolver::resolve_tsdns(const char *query, const sockaddr_storage& server_a /* create the socket */ auto socket = ::socket(server_address.ss_family, SOCK_STREAM | SOCK_NONBLOCK, 0); if(socket <= 0) { - callback(ResultState::INITIALISATION_FAILED, -1, "failed to allocate socket: " + to_string(errno) + "/" + strerror(errno)); +#ifdef WIN32 + char buf[1024]; + strerror_s(buf, errno); + std::string strerr{buf}; +#else + std::string strerr{strerror(errno)}; +#endif + callback(ResultState::INITIALISATION_FAILED, -1, "failed to allocate socket: " + to_string(errno) + "/" + strerr); return; } #ifdef WIN32 u_long enabled = 0; - auto non_block_rs = ioctlsocket(this->_socket, FIONBIO, &enabled); + auto non_block_rs = ioctlsocket(socket, FIONBIO, &enabled); if (non_block_rs != NO_ERROR) { - ::close(socket); - callback(ResultState::INITIALISATION_FAILED, -2, "failed to enable nonblock: " + to_string(errno) + "/" + strerror(errno)); +#ifdef WIN32 + char buf[1024]; + strerror_s(buf, errno); + std::string strerr{buf}; +#else + std::string strerr{strerror(errno)}; +#endif + closesocket(socket); + callback(ResultState::INITIALISATION_FAILED, -2, "failed to enable nonblock: " + to_string(errno) + "/" + strerr); return; } -#endif - - int opt = 1; +#else + int opt = 1; setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)); +#endif auto request = new tsdns_request{}; request->resolver = this; request->callback = callback; - request->socket = socket; + request->socket = (int) socket; request->timeout_event = evtimer_new(this->event.base, [](evutil_socket_t, short, void *_request) { auto request = static_cast(_request); request->resolver->evtimer_tsdns_callback(request); @@ -122,23 +209,21 @@ void Resolver::resolve_tsdns(const char *query, const sockaddr_storage& server_a auto error = WSAGetLastError(); if(error != WSAEWOULDBLOCK) { - /* - * TODO! - wchar_t *s = nullptr; - FormatMessageW( + char* s = nullptr; + FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPWSTR)&s, + (LPSTR) &s, 0, nullptr ); - fprintf(stdout, "Connect failed with code %d. Error: %ld/%S\n", result, error, s); - LocalFree(s); - */ - callback(ResultState::TSDNS_CONNECTION_FAIL, -1, "Failed to connect"); + std::string message{s}; + LocalFree(s); + + callback(ResultState::TSDNS_CONNECTION_FAIL, -1, "Failed to connect: " + message); this->destroy_tsdns_request(request); } #else @@ -157,7 +242,7 @@ void Resolver::resolve_tsdns(const char *query, const sockaddr_storage& server_a auto seconds = chrono::floor(timeout); auto microseconds = chrono::ceil(timeout - seconds); - timeval tv{seconds.count(), microseconds.count()}; + timeval tv{(long) seconds.count(), (long) microseconds.count()}; auto errc = event_add(request->timeout_event, &tv); //TODO: Check for error @@ -214,7 +299,7 @@ void Resolver::event_tsdns_write(Resolver::tsdns_request *request) { if(request->write_buffer.empty()) return; - auto written = send(request->socket, request->write_buffer.data(), min(request->write_buffer.size(), 1024UL), MSG_DONTWAIT); + auto written = send(request->socket, request->write_buffer.data(), (int) min(request->write_buffer.size(), 1024UL), MSG_DONTWAIT); if(written < 0) { #ifdef WIN32 auto error = WSAGetLastError(); diff --git a/native/dns/src/resolver.h b/native/dns/src/resolver.h index 2760f8c..30274a9 100644 --- a/native/dns/src/resolver.h +++ b/native/dns/src/resolver.h @@ -9,8 +9,10 @@ #include #include "./types.h" -#ifndef WIN32 -struct ub_ctx; +#ifdef WIN32 + #include +#else + struct ub_ctx; #endif namespace tc::dns { @@ -22,7 +24,8 @@ namespace tc::dns { struct DNSResponseData { #ifdef WIN32 - //IMPLEMENT ME! + bool wide_string{false}; + DNS_QUERY_RESULT data; #else uint8_t* buffer{nullptr}; size_t length{0}; @@ -68,11 +71,10 @@ namespace tc::dns { std::string bogus; uint8_t secure_state{0}; - - std::shared_ptr data{nullptr}; #else - + DNSResponse(std::shared_ptr); #endif + std::shared_ptr data{nullptr}; bool is_parsed{false}; std::string parse_error{}; @@ -93,6 +95,7 @@ namespace tc::dns { DNS_TIMEOUT = 0x10, DNS_FAIL = 0x11, /* error detail is a DNS error code */ + DNS_API_FAIL = 0x12, TSDNS_CONNECTION_FAIL = 0x20, TSDNS_EMPTY_RESPONSE = 0x21, @@ -113,21 +116,59 @@ namespace tc::dns { void resolve_dns(const char* /* name */, const rrtype::value& /* rrtype */, const rrclass::value& /* rrclass */, const std::chrono::microseconds& /* timeout */, const dns_callback_t& /* callback */); void resolve_tsdns(const char* /* name */, const sockaddr_storage& /* server */, const std::chrono::microseconds& /* timeout */, const tsdns_callback_t& /* callback */); private: -#ifndef WIN32 +#ifdef WIN32 + struct dns_request; + struct dns_old_request_data { + /* request might me nullptr if its beeing timeouted */ + struct dns_request* request{nullptr}; /* protected by lock */ + std::mutex* lock{nullptr}; + }; + + struct { + HMODULE libhandle{nullptr}; + + DNS_STATUS (*DnsQueryEx)( + _In_ PDNS_QUERY_REQUEST pQueryRequest, + _Inout_ PDNS_QUERY_RESULT pQueryResults, + _Inout_opt_ PDNS_QUERY_CANCEL pCancelHandle + ) = nullptr; + + DNS_STATUS (*DnsCancelQuery)( + _In_ PDNS_QUERY_CANCEL pCancelHandle + ) = nullptr; + } dnsapi; +#endif + struct dns_request { Resolver* resolver{nullptr}; - int ub_id{0}; - struct ::event* timeout_event{nullptr}; - struct ::event* register_event{nullptr}; - std::string host; dns::rrtype::value rrtype{dns::rrtype::Unassigned}; dns::rrclass::value rrclass{dns::rrclass::IN}; dns_callback_t callback{}; +#ifdef WIN32 + std::wstring whost; + + /* windows 8 or newer */ + DNS_QUERY_REQUEST dns_query; + DNS_QUERY_RESULT dns_result; + DNS_QUERY_CANCEL dns_cancel; + + /* for old stuff */ + //std::thread resolve_thread; + std::mutex* threaded_lock{nullptr}; + struct dns_old_request_data* thread_data{nullptr}; /* protected by threaded_lock */ +#else + + int ub_id{0}; + struct ::event* register_event{nullptr}; +#endif + struct ::event* timeout_event{nullptr}; + struct ::event* processed_event{nullptr}; }; +#ifndef WIN32 struct ub_ctx* ub_ctx = nullptr; #endif struct tsdns_request { @@ -156,21 +197,22 @@ namespace tc::dns { std::vector tsdns_requests{}; -#ifndef WIN32 std::vector dns_requests{}; -#endif std::recursive_mutex request_lock{}; /* this is recursive because due to the instance callback resolve_dns could be called recursively */ -#ifndef WIN32 + bool initialize_platform(std::string& /* error */, bool /* use hosts */, bool /* use resolv */); + void finalize_platform(); + void destroy_dns_request(dns_request*); -#endif void destroy_tsdns_request(tsdns_request*); void event_loop_runner(); -#ifndef WIN32 void evtimer_dns_callback(dns_request* /* request */); +#ifndef WIN32 void ub_callback(dns_request* /* request */, int /* rcode */, void* /* packet */, int /* packet_len */, int /* sec */, char* /* why_bogus */); +#else + void dns_callback(dns_request* /* request */); #endif void evtimer_tsdns_callback(tsdns_request* /* request */); diff --git a/native/dns/src/resolver_linux.cpp b/native/dns/src/resolver_linux.cpp index 99cdefa..9c3a6dc 100644 --- a/native/dns/src/resolver_linux.cpp +++ b/native/dns/src/resolver_linux.cpp @@ -16,18 +16,7 @@ using namespace std; using namespace tc::dns; -bool Resolver::initialize(std::string &error, bool hosts, bool resolv) { - if(this->event.loop_active) - this->finalize(); - - this->event.loop_active = true; - this->event.base = event_base_new(); - if(!this->event.base) { - error = "failed to allcoate event base"; - return false; - } - this->event.loop = std::thread(std::bind(&Resolver::event_loop_runner, this)); - +bool Resolver::initialize_platform(std::string &error, bool hosts, bool resolv) { this->ub_ctx = ub_ctx_create_event(this->event.base); if(!this->ub_ctx) { this->finalize(); @@ -50,63 +39,9 @@ bool Resolver::initialize(std::string &error, bool hosts, bool resolv) { return true; } -void Resolver::finalize() { - this->event.loop_active = false; - if(this->event.base) { - auto ret = event_base_loopexit(this->event.base, nullptr); - if(ret != 0) { - cerr << "Failed to exit event base loop: " << ret << endl; - } - } - - { - this->event.condition.notify_one(); - if(this->event.loop.joinable()) - this->event.loop.join(); - } - - { - unique_lock lock(this->request_lock); - auto dns_list = std::move(this->dns_requests); - auto tsdns_list = std::move(this->tsdns_requests); - - for(auto entry : dns_list) { - ub_cancel(this->ub_ctx, entry->ub_id); - - entry->callback(ResultState::ABORT, 0, nullptr); - this->destroy_dns_request(entry); - } - - for(auto entry : tsdns_list) { - entry->callback(ResultState::ABORT, 0, ""); - this->destroy_tsdns_request(entry); - } - lock.unlock(); - } - +void Resolver::finalize_platform() { ub_ctx_delete((struct ub_ctx*) this->ub_ctx); this->ub_ctx = nullptr; - - if(this->event.base) { - event_base_free(this->event.base); - this->event.base = nullptr; - } -} - -void Resolver::event_loop_runner() { - while(true) { - { - unique_lock lock{this->event.lock}; - if(!this->event.loop_active) - break; - - this->event.condition.wait(lock); - if(!this->event.loop_active) - break; - } - - event_base_loop(this->event.base, 0); - } } //Call only within the event loop! @@ -118,6 +53,9 @@ void Resolver::destroy_dns_request(Resolver::dns_request *request) { this->dns_requests.erase(std::find(this->dns_requests.begin(), this->dns_requests.end(), request), this->dns_requests.end()); } + if(!this->event.loop_active) + ub_cancel(this->ub_ctx, entry->ub_id); + if(request->register_event) { event_del_noblock(request->register_event); event_free(request->register_event); diff --git a/native/dns/src/response.cpp b/native/dns/src/response.cpp index 6a5d531..7691d48 100644 --- a/native/dns/src/response.cpp +++ b/native/dns/src/response.cpp @@ -1,9 +1,14 @@ #include "./response.h" #include "./resolver.h" +#include +#include #ifdef WIN32 - #include + #include #include + #include + #include + #include #else #include #include @@ -12,18 +17,7 @@ using namespace tc::dns::response; using namespace tc::dns::response::rrparser; -inline std::string to_string(const in6_addr& address) { - char buffer[INET6_ADDRSTRLEN]; - if(!inet_ntop(AF_INET6, (void*) &address, buffer, INET6_ADDRSTRLEN)) return ""; - return std::string(buffer); -} - -inline std::string to_string(const in_addr& address) { - char buffer[INET_ADDRSTRLEN]; - if(!inet_ntop(AF_INET, (void*) &address, buffer, INET_ADDRSTRLEN)) return ""; - return std::string(buffer); -} - +#ifndef WIN32 uint16_t DNSHeader::field(int index) const { return ((uint16_t*) this->response->packet_data())[index]; } @@ -36,17 +30,83 @@ DNSResourceRecords::DNSResourceRecords(std::shared_ptr packet, const uint8_t* DNSResourceRecords::payload_data() const { return this->data->buffer + this->offset; } +#else +DNSResourceRecords::DNSResourceRecords(std::shared_ptr data, PDNS_RECORDA rdata) : nrecord{rdata}, data{std::move(data)} { } +bool DNSResourceRecords::is_wide_string() const { + return this->data->wide_string; +} +#endif + +bool A::is_valid() { +#ifdef WIN32 + return true; +#else + return this->handle->payload_length() == 4; +#endif +} + +in_addr A::address() { +#ifdef WIN32 + in_addr result{}; + result.S_un.S_addr = this->handle->native_record()->Data.A.IpAddress; + return result; +#else + //TODO: Attention: Unaligned access + return {*(uint32_t*) this->handle->payload_data()}; +#endif +} + +std::string A::address_string() { +#ifdef WIN32 + struct in_addr address = this->address(); + char buffer[17]; + RtlIpv4AddressToStringA(&address, buffer); + return std::string{buffer}; +#else + auto _1 = this->handle->payload_data()[0], + _2 = this->handle->payload_data()[1], + _3 = this->handle->payload_data()[2], + _4 = this->handle->payload_data()[3]; + return std::to_string(_1) + "." + std::to_string(_2) + "." + std::to_string(_3) + "." + std::to_string(_4); +#endif +} //---------------- AAAA +#ifdef WIN32 +bool AAAA::is_valid() { + return true; +} + std::string AAAA::address_string() { - return to_string(this->address()); + struct in6_addr address = this->address(); + char buffer[47]; + RtlIpv6AddressToStringA(&address, buffer); //Supported for Win7 as well and not only above 8.1 like inet_ntop + return std::string{buffer}; +} + +in6_addr AAAA::address() { + in6_addr result{}; + memcpy(result.u.Byte, this->handle->native_record()->Data.AAAA.Ip6Address.IP6Byte, 16); + return result; +} +#else +bool AAAA::is_valid() { + return this->handle->payload_length() == 16; +} + +std::string AAAA::address_string() { + auto address = this->address(); + + char buffer[INET6_ADDRSTRLEN]; + if(!inet_ntop(AF_INET6, (void*) &address, buffer, INET6_ADDRSTRLEN)) return ""; + return std::string(buffer); } in6_addr AAAA::address() { return { .__in6_u = { .__u6_addr32 = { - //Attention unaligned memory access + //TODO: Attention unaligned memory access ((uint32_t*) this->handle->payload_data())[0], ((uint32_t*) this->handle->payload_data())[1], ((uint32_t*) this->handle->payload_data())[2], @@ -55,8 +115,23 @@ in6_addr AAAA::address() { } }; } +#endif //---------------- SRV +#ifdef WIN32 +bool SRV::is_valid() { return true; } +std::string SRV::target_hostname() { + if(this->handle->is_wide_string()) { + auto result = std::wstring{ ((PDNS_RECORDW) this->handle->native_record())->Data.Srv.pNameTarget }; + return std::string{result.begin(), result.end()}; + } else { + return std::string{ this->handle->native_record()->Data.Srv.pNameTarget }; + } +} +uint16_t SRV::priority() { return this->handle->native_record()->Data.SRV.wPriority; } +uint16_t SRV::weight() { return this->handle->native_record()->Data.SRV.wWeight; } +uint16_t SRV::target_port() { return this->handle->native_record()->Data.SRV.wPort; } +#else bool SRV::is_valid() { if(this->handle->payload_length() < 7) return false; @@ -72,16 +147,35 @@ std::string SRV::target_hostname() { return this->handle->dns_data()->parse_dns_dn(error, index, true); } + +uint16_t SRV::priority() { return ntohs(((uint16_t*) this->handle->payload_data())[0]); } +uint16_t SRV::weight() { return ntohs(((uint16_t*) this->handle->payload_data())[1]); } +uint16_t SRV::target_port() { return ntohs(((uint16_t*) this->handle->payload_data())[2]); } +#endif + //---------------- All types with a name bool named_base::is_valid() { +#ifdef WIN32 + return true; +#else size_t index = this->handle->payload_offset(); std::string error{}; this->handle->dns_data()->parse_dns_dn(error, index, true); return error.empty(); +#endif } std::string named_base::name() { - size_t index = this->handle->payload_offset(); +#ifdef WIN32 + if(this->handle->is_wide_string()) { + auto result = std::wstring{ ((PDNS_RECORDW) this->handle->native_record())->Data.Cname.pNameHost }; + return std::string{result.begin(), result.end()}; + } else { + return std::string{ this->handle->native_record()->Data.Cname.pNameHost }; + } +#else + size_t index = this->handle->payload_offset(); std::string error{}; return this->handle->dns_data()->parse_dns_dn(error, index, true); +#endif } diff --git a/native/dns/src/response.h b/native/dns/src/response.h index 01a9586..dda0e0e 100644 --- a/native/dns/src/response.h +++ b/native/dns/src/response.h @@ -3,13 +3,20 @@ #include #include #include -#include +#ifdef WIN32 + #include + #include + #include +#else + #include +#endif #include "./types.h" +struct in6_addr; namespace tc::dns { class DNSResponse; - class DNSResponseData; + struct DNSResponseData; namespace response { #ifndef WIN32 @@ -57,16 +64,32 @@ namespace tc::dns { friend class tc::dns::DNSResponse; public: [[nodiscard]] inline std::string qname() const { +#ifdef WIN32 + return std::string{this->nrecord->pName}; +#else return this->name; +#endif } [[nodiscard]] inline rrtype::value atype() const { +#ifdef WIN32 + return static_cast(this->nrecord->wType); +#else return this->type; +#endif } [[nodiscard]] inline rrclass::value aclass() const { - return this->klass; +#ifdef WIN32 + return static_cast(1); +#else + return this->klass; +#endif } [[nodiscard]] inline uint16_t attl() const { +#ifdef WIN32 + return (uint16_t) this->nrecord->dwTtl; +#else return this->ttl; +#endif } #ifndef WIN32 @@ -75,6 +98,7 @@ namespace tc::dns { [[nodiscard]] inline size_t payload_offset() const { return this->offset; } #else [[nodiscard]] inline PDNS_RECORDA native_record() const { return this->nrecord; } + [[nodiscard]] bool is_wide_string() const; #endif [[nodiscard]] inline std::shared_ptr dns_data() const { @@ -83,7 +107,7 @@ namespace tc::dns { template [[nodiscard]] inline T parse() const { - if(T::type != this->type) + if(T::type != this->atype()) throw std::logic_error{"parser type mismatch"}; return T{this}; } @@ -134,21 +158,14 @@ namespace tc::dns { } define_parser(A, base, - [[nodiscard]] inline bool is_valid() { return this->handle->payload_length() == 4; } - [[nodiscard]] inline std::string address_string() { - auto _1 = this->handle->payload_data()[0], - _2 = this->handle->payload_data()[1], - _3 = this->handle->payload_data()[2], - _4 = this->handle->payload_data()[3]; - return std::to_string(_1) + "." + std::to_string(_2) + "." + std::to_string(_3) + "." + std::to_string(_4); - } - [[nodiscard]] inline in_addr address() { - return {*(uint32_t*) this->handle->payload_data()}; - } + [[nodiscard]] bool is_valid(); + [[nodiscard]] std::string address_string(); + + [[nodiscard]] in_addr address(); ); define_parser(AAAA, base, - [[nodiscard]] inline bool is_valid() { return this->handle->payload_length() == 16; } + [[nodiscard]] bool is_valid(); [[nodiscard]] std::string address_string(); [[nodiscard]] in6_addr address(); ); @@ -156,9 +173,9 @@ namespace tc::dns { define_parser(SRV, base, [[nodiscard]] bool is_valid(); - [[nodiscard]] inline uint16_t priority() { return ntohs(((uint16_t*) this->handle->payload_data())[0]); } - [[nodiscard]] inline uint16_t weight() { return ntohs(((uint16_t*) this->handle->payload_data())[1]); } - [[nodiscard]] inline uint16_t target_port() { return ntohs(((uint16_t*) this->handle->payload_data())[2]); } + [[nodiscard]] uint16_t priority(); + [[nodiscard]] uint16_t weight(); + [[nodiscard]] uint16_t target_port(); [[nodiscard]] std::string target_hostname(); ); diff --git a/native/dns/src/types.h b/native/dns/src/types.h index 8a81e3d..7813ddc 100644 --- a/native/dns/src/types.h +++ b/native/dns/src/types.h @@ -71,7 +71,7 @@ namespace tc::dns { CSYNC = 62, // Child-To-Parent Synchronization,[RFC7477], ZONEMD = 63, // message digest for DNS zone,[draft-wessels-dns-zone-digest],ZONEMD/zonemd-completed-template //Unassigned = 64-98, - SPF = 99, // [RFC7208], + SPF = 99, // [RFC7208], UINFO = 100, // [IANA-Reserved], UID = 101, // [IANA-Reserved], GID = 102, // [IANA-Reserved], @@ -83,7 +83,7 @@ namespace tc::dns { EUI48 = 108, // an EUI-48 address,[RFC7043],EUI48/eui48-completed-template EUI64 = 109, // an EUI-64 address,[RFC7043],EUI64/eui64-completed-template //Unassigned = 110-248, // , - TKEY = 249, // Transaction Key,[RFC2930], + TKEY = 249, // Transaction Key,[RFC2930], TSIG = 250, // Transaction Signature,[RFC2845], IXFR = 251, // incremental transfer,[RFC1995], AXFR = 252, // transfer of an entire zone,[RFC1035][RFC5936], @@ -96,12 +96,12 @@ namespace tc::dns { DOA = 259, // Digital Object Architecture,[draft-durand-doa-over-dns],DOA/doa-completed-template AMTRELAY = 260, // Automatic Multicast Tunneling Relay,[draft-ietf-mboned-driad-amt-discovery],AMTRELAY/amtrelay-completed-template //Unassigned = 261-32767, - TA = 32768, // DNSSEC Trust Authorities,"[Sam_Weiler][http://cameo.library.cmu.edu/][ Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, + TA = 32768, // DNSSEC Trust Authorities,"[Sam_Weiler][http://cameo.library.cmu.edu/][ Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, // Information Networking Institute, Carnegie Mellon University, April 2004.]", - DLV = 32769, // DNSSEC Lookaside Validation,[RFC4431], + DLV = 32769, // DNSSEC Lookaside Validation,[RFC4431], //Unassigned = 32770-65279,, // , //Private use,65280-65534,,,, - Reserved = 65535, + Reserved = 65535, }; static std::map names; @@ -114,13 +114,17 @@ namespace tc::dns { }; struct rrclass { +#ifdef IN + #undef IN +#endif + enum value : uint32_t { IN = 1, /* Internet */ CH = 3, /* Chaos */ HS = 4, /* Hesiod */ QCLASS_NONE = 254, - QCLASS_ANY = 255 + QCLASS_ANY = 255, }; static std::map names; diff --git a/native/dns/test/main.cpp b/native/dns/test/main.cpp index f77d6ad..b365fe5 100644 --- a/native/dns/test/main.cpp +++ b/native/dns/test/main.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include "../src/response.h" #include "../src/resolver.h" @@ -17,7 +16,20 @@ using namespace std; namespace parser = response::rrparser; int main() { +#ifdef WIN32 + { + WSADATA wsaData; + auto error = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (error != 0) { + wprintf(L"WSAStartup failed with %d\n", error); + return error; + } + } + + evthread_use_windows_threads(); +#else evthread_use_pthreads(); +#endif //evthread_enable_lock_debugging(); std::string error{}; @@ -29,7 +41,7 @@ int main() { } auto begin = chrono::system_clock::now(); - for(int i = 0; i < 250; i++) { + for(int i = 0; i < 1; i++) { cr(resolver, { to_string(i) + "ts.twerion.net", 9922 @@ -45,8 +57,10 @@ int main() { }); } - this_thread::sleep_for(chrono::seconds{8}); + this_thread::sleep_for(chrono::seconds{5}); + cout << "Timeout" << endl; resolver.finalize(); + cout << "Exit" << endl; return 0; } \ No newline at end of file diff --git a/native/dns/utils.cpp b/native/dns/utils.cpp index 730437f..302463e 100644 --- a/native/dns/utils.cpp +++ b/native/dns/utils.cpp @@ -11,122 +11,128 @@ #include #include #include + +#ifndef WIN32 #include +#else +#include +#include +#endif using namespace tc::dns; namespace parser = tc::dns::response::rrparser; //-------------------------- IP-Resolve struct CrIpStatus { - std::mutex pending_lock; - uint8_t pending{0}; + std::mutex pending_lock; + uint8_t pending{0}; - ServerAddress original{"", 0}; + ServerAddress original{"", 0}; - std::tuple a{false, "unset"}; - std::tuple aaaa{false, "unset"}; + std::tuple a{false, "unset"}; + std::tuple aaaa{false, "unset"}; - cr_callback_t callback; - std::function&)> finish_callback; + cr_callback_t callback; + std::function&)> finish_callback; - void one_finished(const std::shared_ptr& _this) { - assert(&*_this == this); + void one_finished(const std::shared_ptr& _this) { + assert(&*_this == this); - std::lock_guard lock{this->pending_lock}; - if(--pending == 0) - this->finish_callback(_this); - } + std::lock_guard lock{this->pending_lock}; + if(--pending == 0) + this->finish_callback(_this); + } }; void cr_ip_finish(const std::shared_ptr& status) { - if(std::get<0>(status->a)) { - status->callback(true, ServerAddress{std::get<1>(status->a), status->original.port}); - } else if(std::get<0>(status->aaaa)) { - status->callback(true, ServerAddress{std::get<1>(status->aaaa), status->original.port}); - } else { - status->callback(false, "failed to resolve an IP for " + status->original.host + ": A{" + std::get<1>(status->a) + "} AAAA{" + std::get<1>(status->aaaa) + "}"); - } + if(std::get<0>(status->a)) { + status->callback(true, ServerAddress{std::get<1>(status->a), status->original.port}); + } else if(std::get<0>(status->aaaa)) { + status->callback(true, ServerAddress{std::get<1>(status->aaaa), status->original.port}); + } else { + status->callback(false, "failed to resolve an IP for " + status->original.host + ": A{" + std::get<1>(status->a) + "} AAAA{" + std::get<1>(status->aaaa) + "}"); + } } void tc::dns::cr_ip(Resolver& resolver, const ServerAddress& address, const cr_callback_t& callback) { - auto status = std::make_shared(); + auto status = std::make_shared(); - status->original = address; - status->finish_callback = cr_ip_finish; - status->callback = callback; + status->original = address; + status->finish_callback = cr_ip_finish; + status->callback = callback; - /* general pending so we could finish our method */ - status->pending++; + /* general pending so we could finish our method */ + status->pending++; - status->pending++; - resolver.resolve_dns(address.host.c_str(), rrtype::A, rrclass::IN, std::chrono::seconds{5}, [status, &resolver](Resolver::ResultState::value state, int code, std::unique_ptr data){ - if(state != 0) { - status->a = {false, "A query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)}; - status->one_finished(status); - return; - } - std::string error; - if(!data->parse(error)) { - status->a = {false, "A query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)}; - status->one_finished(status); - return; - } + status->pending++; + resolver.resolve_dns(address.host.c_str(), rrtype::A, rrclass::IN, std::chrono::seconds{5}, [status, &resolver](Resolver::ResultState::value state, int code, std::unique_ptr data){ + if(state != 0) { + status->a = {false, "A query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)}; + status->one_finished(status); + return; + } + std::string error; + if(!data->parse(error)) { + status->a = {false, "A query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)}; + status->one_finished(status); + return; + } - for(const auto& answer : data->answers()) { - if(answer->atype() != rrtype::A){ - std::cerr << "Received a non A record answer in A query!" << std::endl; - continue; - } + for(const auto& answer : data->answers()) { + if(answer->atype() != rrtype::A){ + std::cerr << "Received a non A record answer in A query!" << std::endl; + continue; + } - auto data = answer->parse(); - if(!data.is_valid()) - continue; + auto data = answer->parse(); + if(!data.is_valid()) + continue; - status->a = {true, data.address_string()}; - status->one_finished(status); - return; - } + status->a = {true, data.address_string()}; + status->one_finished(status); + return; + } - status->a = {false, "empty response"}; - status->one_finished(status); - }); + status->a = {false, "empty response"}; + status->one_finished(status); + }); - status->pending++; - resolver.resolve_dns(address.host.c_str(), rrtype::AAAA, rrclass::IN, std::chrono::seconds{5}, [status, &resolver](Resolver::ResultState::value state, int code, std::unique_ptr data){ - if(state != 0) { - status->aaaa = {false, "AAAA query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)}; - status->one_finished(status); - return; - } + status->pending++; + resolver.resolve_dns(address.host.c_str(), rrtype::AAAA, rrclass::IN, std::chrono::seconds{5}, [status, &resolver](Resolver::ResultState::value state, int code, std::unique_ptr data){ + if(state != 0) { + status->aaaa = {false, "AAAA query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)}; + status->one_finished(status); + return; + } - std::string error; - if(!data->parse(error)) { - status->aaaa = {false, "failed to parse AAAA query reponse: " + error}; - status->one_finished(status); - return; - } + std::string error; + if(!data->parse(error)) { + status->aaaa = {false, "failed to parse AAAA query reponse: " + error}; + status->one_finished(status); + return; + } - for(const auto& answer : data->answers()) { - if(answer->atype() != rrtype::AAAA){ - std::cerr << "Received a non AAAA record answer in AAAA query!" << std::endl; - continue; - } + for(const auto& answer : data->answers()) { + if(answer->atype() != rrtype::AAAA){ + std::cerr << "Received a non AAAA record answer in AAAA query!" << std::endl; + continue; + } - auto data = answer->parse(); - if(!data.is_valid()) - continue; + auto data = answer->parse(); + if(!data.is_valid()) + continue; - status->aaaa = {true, data.address_string()}; - status->one_finished(status); - return; - } + status->aaaa = {true, data.address_string()}; + status->one_finished(status); + return; + } - status->aaaa = {false, "empty response"}; - status->one_finished(status); - return; - }); + status->aaaa = {false, "empty response"}; + status->one_finished(status); + return; + }); - status->one_finished(status); + status->one_finished(status); } //-------------------------- SRV-Resolve @@ -135,205 +141,218 @@ static std::mt19937 srv_rnd(srv_rnd_dev()); /* connect resolve for TS3 srv records */ void tc::dns::cr_srv(Resolver& resolver, const ServerAddress& address, const cr_callback_t& callback, const std::string& application) { - auto query = application + "." + address.host; - resolver.resolve_dns(query.c_str(), rrtype::SRV, rrclass::IN, std::chrono::seconds{5}, [callback, address, &resolver](Resolver::ResultState::value state, int code, std::unique_ptr data){ - if(state != 0) { - callback(false, "SRV query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)); - return; - } + auto query = application + "." + address.host; + resolver.resolve_dns(query.c_str(), rrtype::SRV, rrclass::IN, std::chrono::seconds{5}, [callback, address, &resolver](Resolver::ResultState::value state, int code, std::unique_ptr data){ + if(state != 0) { + callback(false, "SRV query failed. State: " + std::to_string(state) + ", Code: " + std::to_string(code)); + return; + } - std::string error; - if(!data->parse(error)) { - callback(false, "failed to parse srv query reponse: " + error); - return; - } + std::string error; + if(!data->parse(error)) { + callback(false, "failed to parse srv query reponse: " + error); + return; + } - struct SrvEntry { - uint16_t weight; - std::string target; - uint16_t port; - }; - std::map> entries{}; + struct SrvEntry { + uint16_t weight; + std::string target; + uint16_t port; + }; + std::map> entries{}; - auto answers = data->answers(); - for(const auto& answer : answers) { - if(answer->atype() != rrtype::SRV) { - std::cerr << "Received a non SRV record answer in SRV query (" << rrtype::name(answer->atype()) << ")!" << std::endl; - continue; - } + auto answers = data->answers(); + for(const auto& answer : answers) { + if(answer->atype() != rrtype::SRV) { + std::cerr << "Received a non SRV record answer in SRV query (" << rrtype::name(answer->atype()) << ")!" << std::endl; + continue; + } - auto srv = answer->parse(); - entries[srv.priority()].push_back({srv.weight(), srv.target_hostname(), srv.target_port()}); - } + auto srv = answer->parse(); + entries[srv.priority()].push_back({srv.weight(), srv.target_hostname(), srv.target_port()}); + } - if(entries.empty()) { - callback(false, "empty response"); - return; - } + if(entries.empty()) { + callback(false, "empty response"); + return; + } - std::deque> results{}; - for(auto [priority, pentries] : entries) { - int64_t count = 0; - for(const auto& entry : pentries) - count += std::max((size_t) entry.weight, 1UL); + std::deque> results{}; + for(auto [priority, pentries] : entries) { + uint32_t count = 0; + for(const auto& entry : pentries) { + count += max((size_t) entry.weight, 1UL); + } - std::uniform_int_distribution dist(0, count - 1); - auto index = dist(srv_rnd); + std::uniform_int_distribution dist(0, (uint32_t) (count - 1)); + auto index = dist(srv_rnd); - count = 0; - for(const auto& entry : pentries) { - count += std::max((size_t) entry.weight, 1UL); - if(count > index) { - count = -1; - results.emplace_back(priority, entry); - break; - } - } - } - assert(!results.empty()); + count = 0; + for(const auto& entry : pentries) { + count += max((size_t) entry.weight, 1UL); + if(count > index) { + count = -1; + results.emplace_back(priority, entry); + break; + } + } + } + assert(!results.empty()); - std::sort(results.begin(), results.end(), [](const auto& a, const auto& b) { return std::get<0>(a) < std::get<0>(b); }); + std::sort(results.begin(), results.end(), [](const auto& a, const auto& b) { return std::get<0>(a) < std::get<0>(b); }); - //TODO: Resolve backup stuff as well - auto target = std::get<1>(*results.begin()); - cr_ip(resolver, { - target.target, - target.port == 0 ? address.port : target.port - }, [callback](bool success, auto response) { - if(!success) { - //TODO: Use the backup stuff? - callback(false, "failed to resolve dns pointer: " + std::get(response)); - return; - } + //TODO: Resolve backup stuff as well + auto target = std::get<1>(*results.begin()); + cr_ip(resolver, { + target.target, + target.port == 0 ? address.port : target.port + }, [callback](bool success, auto response) { + if(!success) { + //TODO: Use the backup stuff? + callback(false, "failed to resolve dns pointer: " + std::get(response)); + return; + } - callback(true, std::get(response)); - }); - }); + callback(true, std::get(response)); + }); + }); } //-------------------------- TSDNS-Resolve void tc::dns::cr_tsdns(tc::dns::Resolver &resolver, const tc::dns::ServerAddress &address, const tc::dns::cr_callback_t &callback) { - auto root = domain_root(address.host); - cr_srv(resolver, {root, 0}, [&resolver, callback, address](bool success, auto data){ - if(!success) { - callback(false, "failed to resolve tsdns address: " + std::get(data)); - return; - } - auto tsdns_host = std::get(data); + auto root = domain_root(address.host); + cr_srv(resolver, {root, 0}, [&resolver, callback, address](bool success, auto data){ + if(!success) { + callback(false, "failed to resolve tsdns address: " + std::get(data)); + return; + } + auto tsdns_host = std::get(data); - sockaddr_storage tsdns_address{}; - memset(&tsdns_address, 0, sizeof(tsdns_address)); + sockaddr_storage tsdns_address{}; + memset(&tsdns_address, 0, sizeof(tsdns_address)); - auto tsdns_a6 = (sockaddr_in6*) &tsdns_address; - auto tsdns_a4 = (sockaddr_in*) &tsdns_address; - if(inet_pton(AF_INET6, tsdns_host.host.c_str(), &tsdns_a6->sin6_addr) == 1) { - tsdns_a6->sin6_family = AF_INET6; - tsdns_a6->sin6_port = htons(tsdns_host.port == 0 ? 41144 : tsdns_host.port); - } else if(inet_pton(AF_INET, tsdns_host.host.c_str(), &(tsdns_a4->sin_addr)) == 1) { - tsdns_a4->sin_family = AF_INET; - tsdns_a4->sin_port = htons(tsdns_host.port == 0 ? 41144 : tsdns_host.port); - } else { - callback(false, "invalid tsdns host: " + tsdns_host.host); - return; - } + auto tsdns_a6 = (sockaddr_in6*) &tsdns_address; + auto tsdns_a4 = (sockaddr_in*) &tsdns_address; +#ifdef WIN32 + PCSTR terminator{nullptr}; + if(RtlIpv6StringToAddressA(tsdns_host.host.c_str(), &terminator, (in6_addr*) &tsdns_a6->sin6_addr) == 0) +#else + if(inet_pton(AF_INET6, tsdns_host.host.c_str(), &tsdns_a6->sin6_addr) == 1) +#endif + { + tsdns_a6->sin6_family = AF_INET6; + tsdns_a6->sin6_port = htons(tsdns_host.port == 0 ? 41144 : tsdns_host.port); + } +#ifdef WIN32 + else if(RtlIpv4StringToAddressA(tsdns_host.host.c_str(), false, &terminator, (in_addr*) &tsdns_a4->sin_addr) == 0) +#else + else if(inet_pton(AF_INET, tsdns_host.host.c_str(), &(tsdns_a4->sin_addr)) == 1) +#endif + { + tsdns_a4->sin_family = AF_INET; + tsdns_a4->sin_port = htons(tsdns_host.port == 0 ? 41144 : tsdns_host.port); + } else { + callback(false, "invalid tsdns host: " + tsdns_host.host); + return; + } - auto query = address.host; - std::transform(query.begin(), query.end(), query.begin(), tolower); - resolver.resolve_tsdns(query.c_str(), tsdns_address, std::chrono::seconds{5}, [callback, query, address](Resolver::ResultState::value error, int detail, const std::string& response) { - if(error == Resolver::ResultState::SUCCESS) { - if(response == "404") - callback(false, "no record found for " + query); - else { - std::string host{response}; - std::string port{"$PORT"}; + auto query = address.host; + std::transform(query.begin(), query.end(), query.begin(), tolower); + resolver.resolve_tsdns(query.c_str(), tsdns_address, std::chrono::seconds{5}, [callback, query, address](Resolver::ResultState::value error, int detail, const std::string& response) { + if(error == Resolver::ResultState::SUCCESS) { + if(response == "404") + callback(false, "no record found for " + query); + else { + std::string host{response}; + std::string port{"$PORT"}; - //TODO: Backup IP-Addresses? - if(host.find(',') != -1) - host = std::string{host.begin(), host.begin() + host.find(',')}; + //TODO: Backup IP-Addresses? + if(host.find(',') != -1) + host = std::string{host.begin(), host.begin() + host.find(',')}; - auto colon_index = host.rfind(':'); - if(colon_index > 0 && (host[colon_index - 1] == ']' || host.find(':') == colon_index)) { - port = host.substr(colon_index + 1); - host = host.substr(0, colon_index); - } + auto colon_index = host.rfind(':'); + if(colon_index > 0 && (host[colon_index - 1] == ']' || host.find(':') == colon_index)) { + port = host.substr(colon_index + 1); + host = host.substr(0, colon_index); + } - ServerAddress resp{host, 0}; - if(port == "$PORT") { - resp.port = address.port; - } else { - try { - resp.port = stoul(port); - } catch(std::exception& ex) { - callback(false, "failed to parse response: " + response + " Failed to parse port: " + port); - return; - } - } - callback(true, resp); - } - } else { - callback(false, "query failed. Code: " + std::to_string(error) + "," + std::to_string(detail) + ": " + response); - } - }); - }, "_tsdns._tcp"); + ServerAddress resp{host, 0}; + if(port == "$PORT") { + resp.port = address.port; + } else { + try { + resp.port = (uint16_t) stoul(port); + } catch(const std::exception&) { + callback(false, "failed to parse response: " + response + " Failed to parse port: " + port); + return; + } + } + callback(true, resp); + } + } else { + callback(false, "query failed. Code: " + std::to_string(error) + "," + std::to_string(detail) + ": " + response); + } + }); + }, "_tsdns._tcp"); } //-------------------------- Full-Resolve struct CrStatus { - enum State { - PENDING, - FAILED, - SUCCESS - }; + enum State { + PENDING, + FAILED, + SUCCESS + }; - std::recursive_mutex pending_lock; /* do_done could be called recursively because DNS request could answer instant! */ - uint8_t pending{0}; - bool finished{false}; + std::recursive_mutex pending_lock; /* do_done could be called recursively because DNS request could answer instant! */ + uint8_t pending{0}; + bool finished{false}; - tc::dns::ServerAddress address; - tc::dns::cr_callback_t callback; + tc::dns::ServerAddress address; + tc::dns::cr_callback_t callback; - ~CrStatus() { - assert(this->pending == 0); - } + ~CrStatus() { + assert(this->pending == 0); + } - void do_done(const std::shared_ptr& _this) { - std::lock_guard lock{pending_lock}; - this->finished |= this->try_answer(_this); //May invokes next DNS query + void do_done(const std::shared_ptr& _this) { + std::lock_guard lock{pending_lock}; + this->finished |= this->try_answer(_this); //May invokes next DNS query - assert(this->pending > 0); - if(--pending == 0 && !this->finished) { //Order matters we have to decrease pensing! - this->callback(false, "no results"); - this->finished = true; - return; - } - } + assert(this->pending > 0); + if(--pending == 0 && !this->finished) { //Order matters we have to decrease pensing! + this->callback(false, "no results"); + this->finished = true; + return; + } + } - typedef std::tuple&)>> flagged_executor_t; + typedef std::tuple&)>> flagged_executor_t; - flagged_executor_t execute_subsrv_ts; - std::tuple subsrv_ts; + flagged_executor_t execute_subsrv_ts; + std::tuple subsrv_ts; - flagged_executor_t execute_subsrv_ts3; - std::tuple subsrv_ts3; + flagged_executor_t execute_subsrv_ts3; + std::tuple subsrv_ts3; - flagged_executor_t execute_tsdns; - std::tuple tsdns; + flagged_executor_t execute_tsdns; + std::tuple tsdns; - flagged_executor_t execute_subdomain; - std::tuple subdomain; + flagged_executor_t execute_subdomain; + std::tuple subdomain; - //Only after subsrc and tsdns failed - flagged_executor_t execute_rootsrv; - std::tuple rootsrv; + //Only after subsrc and tsdns failed + flagged_executor_t execute_rootsrv; + std::tuple rootsrv; - //Only after subsrc and tsdns failed - flagged_executor_t execute_rootdomain; - std::tuple rootdomain; + //Only after subsrc and tsdns failed + flagged_executor_t execute_rootdomain; + std::tuple rootdomain; - #define try_answer_test(element, executor) \ +#define try_answer_test(element, executor) \ if(std::get<0>(element) == State::SUCCESS) { \ - this->callback(true, std::get<2>(element)); \ + this->call_answer(std::get<2>(element)); \ return true; \ } else if(std::get<0>(element) == State::PENDING) { \ if(!std::get<0>(executor)) { \ @@ -349,149 +368,171 @@ struct CrStatus { return false; \ } - bool try_answer(const std::shared_ptr& _this) { - if(this->finished) - return true; + bool try_answer(const std::shared_ptr& _this) { + if(this->finished) + return true; - try_answer_test(this->subsrv_ts, this->execute_subsrv_ts); - try_answer_test(this->subsrv_ts3, this->execute_subsrv_ts3); - try_answer_test(this->tsdns, this->execute_tsdns); - try_answer_test(this->subdomain, this->execute_subdomain); - try_answer_test(this->rootsrv, this->execute_rootsrv); - try_answer_test(this->rootdomain, this->execute_rootdomain); - return false; - } + try_answer_test(this->subsrv_ts, this->execute_subsrv_ts); + try_answer_test(this->subsrv_ts3, this->execute_subsrv_ts3); + try_answer_test(this->tsdns, this->execute_tsdns); + try_answer_test(this->subdomain, this->execute_subdomain); + try_answer_test(this->rootsrv, this->execute_rootsrv); + try_answer_test(this->rootdomain, this->execute_rootdomain); + return false; + } + + #define answer_log(element, executor) \ + if(!std::get<0>(executor)) \ + std::cout << #element << ": not executed" << std::endl; \ + else if(std::get<0>(element) == State::PENDING) \ + std::cout << #element << ": pending" << std::endl; \ + else if(std::get<0>(element) == State::FAILED) \ + std::cout << #element << ": failed: " << std::get<1>(element) << std::endl; \ + else \ + std::cout << #element << ": success: " << std::get<2>(element).host << ":" << std::get<2>(element).port << std::endl; + + void call_answer(const tc::dns::ServerAddress& data) { + answer_log(this->subsrv_ts, this->execute_subsrv_ts); + answer_log(this->subsrv_ts3, this->execute_subsrv_ts3); + answer_log(this->tsdns, this->execute_tsdns); + answer_log(this->subdomain, this->execute_subdomain); + answer_log(this->rootsrv, this->execute_rootsrv); + answer_log(this->rootdomain, this->execute_rootdomain); + + //TODO: Print data + this->callback(true, data); + } }; void tc::dns::cr(Resolver& resolver, const tc::dns::ServerAddress& address, const tc::dns::cr_callback_t& callback) { - auto status = std::make_shared(); - status->address = address; - status->callback = callback; - status->pending++; + auto status = std::make_shared(); + status->address = address; + status->callback = callback; + status->pending++; - status->execute_subsrv_ts = { - false, - [&resolver](const std::shared_ptr& status) { - //std::cout << "Execute subsrc ts" << std::endl; - status->pending++; - tc::dns::cr_srv(resolver, status->address, [status](bool success, auto data) { - if(success) { - status->subsrv_ts = {CrStatus::SUCCESS, "", std::get(data)}; - } else { - status->subsrv_ts = {CrStatus::FAILED, std::get(data), {}}; - } - status->do_done(status); - }, "_ts._udp"); - } - }; - /* execute */ - std::get<0>(status->execute_subsrv_ts) = true; + status->execute_subsrv_ts = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute subsrc ts" << std::endl; + status->pending++; + tc::dns::cr_srv(resolver, status->address, [status](bool success, auto data) { + if(success) { + status->subsrv_ts = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->subsrv_ts = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }, "_ts._udp"); + } + }; + /* execute */ + std::get<0>(status->execute_subsrv_ts) = true; - status->execute_subsrv_ts3 = { - false, - [&resolver](const std::shared_ptr& status) { - //std::cout << "Execute subsrc ts3" << std::endl; - status->pending++; - tc::dns::cr_srv(resolver, status->address, [status](bool success, auto data) { - if(success) { - status->subsrv_ts3 = {CrStatus::SUCCESS, "", std::get(data)}; - } else { - status->subsrv_ts3 = {CrStatus::FAILED, std::get(data), {}}; - } - status->do_done(status); - }, "_ts3._udp"); - } - }; - /* execute */ - std::get<0>(status->execute_subsrv_ts3) = true; + status->execute_subsrv_ts3 = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute subsrc ts3" << std::endl; + status->pending++; + tc::dns::cr_srv(resolver, status->address, [status](bool success, auto data) { + if(success) { + status->subsrv_ts3 = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->subsrv_ts3 = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }, "_ts3._udp"); + } + }; + /* execute */ + std::get<0>(status->execute_subsrv_ts3) = true; - status->execute_subdomain = { - false, - [&resolver](const std::shared_ptr& status) { - //std::cout << "Execute subdomain" << std::endl; - status->pending++; - tc::dns::cr_ip(resolver, status->address, [status](bool success, auto data) { - if(success) { - status->subdomain = {CrStatus::SUCCESS, "", std::get(data)}; - } else { - status->subdomain = {CrStatus::FAILED, std::get(data), {}}; - } - status->do_done(status); - }); - } - }; - /* execute */ - //Will be autoamticall be executed after the SRV stuff - //std::get<0>(status->execute_subdomain) = true; + status->execute_subdomain = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute subdomain" << std::endl; + status->pending++; + tc::dns::cr_ip(resolver, status->address, [status](bool success, auto data) { + if(success) { + status->subdomain = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->subdomain = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }); + } + }; + /* execute */ + //Will be autoamticall be executed after the SRV stuff + //std::get<0>(status->execute_subdomain) = true; - status->execute_tsdns = { - false, - [&resolver](const std::shared_ptr& status) { - //std::cout << "Execute tsdns" << std::endl; - status->pending++; + status->execute_tsdns = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute tsdns" << std::endl; + status->pending++; - tc::dns::cr_tsdns(resolver, status->address, [status](bool success, auto data) { - if(success) { - status->tsdns = {CrStatus::SUCCESS, "", std::get(data)}; - } else { - status->tsdns = {CrStatus::FAILED, std::get(data), {}}; - } - status->do_done(status); - }); - } - }; - /* execute */ - //Execute the TSDNS request right at the beginning because it could hang sometimes - std::get<0>(status->execute_tsdns) = true; + tc::dns::cr_tsdns(resolver, status->address, [status](bool success, auto data) { + if(success) { + status->tsdns = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->tsdns = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }); + } + }; + /* execute */ + //Execute the TSDNS request right at the beginning because it could hang sometimes + std::get<0>(status->execute_tsdns) = true; - auto root_domain = tc::dns::domain_root(status->address.host); - if(root_domain != status->address.host) { - status->execute_rootsrv = { - false, - [&resolver](const std::shared_ptr& status) { - //std::cout << "Execute root srv" << std::endl; - status->pending++; + auto root_domain = tc::dns::domain_root(status->address.host); + if(root_domain != status->address.host) { + status->execute_rootsrv = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute root srv" << std::endl; + status->pending++; - tc::dns::cr_srv(resolver, { - tc::dns::domain_root(status->address.host), - status->address.port - }, [status](bool success, auto data) { - if(success) { - status->rootsrv = {CrStatus::SUCCESS, "", std::get(data)}; - } else { - status->rootsrv = {CrStatus::FAILED, std::get(data), {}}; - } - status->do_done(status); - }, "_ts3._udp"); - } - }; + tc::dns::cr_srv(resolver, { + tc::dns::domain_root(status->address.host), + status->address.port + }, [status](bool success, auto data) { + if(success) { + status->rootsrv = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->rootsrv = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }, "_ts3._udp"); + } + }; - status->execute_rootdomain = { - false, - [&resolver](const std::shared_ptr& status) { - //std::cout << "Execute root domain" << std::endl; - status->pending++; + status->execute_rootdomain = { + false, + [&resolver](const std::shared_ptr& status) { + //std::cout << "Execute root domain" << std::endl; + status->pending++; - tc::dns::cr_ip(resolver,{ - tc::dns::domain_root(status->address.host), - status->address.port - }, [status](bool success, auto data) { - if(success) { - status->rootdomain = {CrStatus::SUCCESS, "", std::get(data)}; - } else { - status->rootdomain = {CrStatus::FAILED, std::get(data), {}}; - } - status->do_done(status); - }); - } - }; - } + tc::dns::cr_ip(resolver,{ + tc::dns::domain_root(status->address.host), + status->address.port + }, [status](bool success, auto data) { + if(success) { + status->rootdomain = {CrStatus::SUCCESS, "", std::get(data)}; + } else { + status->rootdomain = {CrStatus::FAILED, std::get(data), {}}; + } + status->do_done(status); + }); + } + }; + } - /* Only execute after every executor has been registered! */ - std::get<1>(status->execute_subsrv_ts)(status); - std::get<1>(status->execute_subsrv_ts3)(status); - //std::get<1>(status->execute_subdomain)(status); - std::get<1>(status->execute_tsdns)(status); + /* Only execute after every executor has been registered! */ + std::get<1>(status->execute_subsrv_ts)(status); + std::get<1>(status->execute_subsrv_ts3)(status); + //std::get<1>(status->execute_subdomain)(status); + std::get<1>(status->execute_tsdns)(status); - status->do_done(status); + status->do_done(status); } \ No newline at end of file