diff --git a/include/ircd/net/dns_cache.h b/include/ircd/net/dns_cache.h index 5573ce610..59bd962ff 100644 --- a/include/ircd/net/dns_cache.h +++ b/include/ircd/net/dns_cache.h @@ -11,12 +11,20 @@ /// (internal) DNS cache namespace ircd::net::dns::cache { + struct waiter; using closure = std::function; extern conf::item min_ttl; extern conf::item error_ttl; extern conf::item nxdomain_ttl; + extern ctx::dock dock; + extern ctx::mutex mutex; + extern std::list waiting; + + bool operator==(const waiter &, const waiter &) noexcept; + bool operator!=(const waiter &, const waiter &) noexcept; + string_view make_type(const mutable_buffer &out, const string_view &); string_view make_type(const mutable_buffer &out, const uint16_t &); @@ -27,19 +35,6 @@ namespace ircd::net::dns::cache bool put(const hostport &, const opts &, const uint &code, const string_view &msg = {}); } -/// (internal) DNS cache -namespace ircd::net::dns::cache -{ - struct waiter; - - bool operator==(const waiter &, const waiter &) noexcept; - bool operator!=(const waiter &, const waiter &) noexcept; - - extern std::list waiting; - extern ctx::mutex mutex; - extern ctx::dock dock; -} - /// DNS cache result waiter struct ircd::net::dns::cache::waiter { @@ -54,4 +49,7 @@ struct ircd::net::dns::cache::waiter waiter(const waiter &) = delete; waiter &operator=(waiter &&) = delete; waiter &operator=(const waiter &) = delete; + + static bool call(waiter &, const uint16_t &type, const string_view &tgt, const json::array &rrs); + static size_t call(const uint16_t &type, const string_view &tgt, const json::array &rrs); }; diff --git a/ircd/net_dns_cache.cc b/ircd/net_dns_cache.cc index a6ceb8880..57d6d82ba 100644 --- a/ircd/net_dns_cache.cc +++ b/ircd/net_dns_cache.cc @@ -234,3 +234,79 @@ ircd::net::dns::cache::waiter::waiter(const hostport &hp, this->opts.proto = {}; assert(this->opts.qtype); } + +/// Note complications due to reentrance and other factors: +/// - This function is invoked from several different places on both the +/// timeout and receive contexts, in addition to any evaluator context. +/// - This function calls back to users making DNS queries, and they may +/// conduct another query in their callback frame -- mid-loop in this +/// function. +size_t +ircd::net::dns::cache::waiter::call(const uint16_t &type, + const string_view &tgt, + const json::array &rrs) +{ + const ctx::uninterruptible::nothrow ui; + size_t ret(0), last; do + { + const std::lock_guard lock + { + mutex + }; + + auto it(begin(waiting)); + for(last = ret; it != end(waiting); ++it) + if(call(*it, type, tgt, rrs)) + { + it = waiting.erase(it); + ++ret; + break; + } + } + while(last < ret); + + if(ret) + dock.notify_all(); + + return ret; +} + +bool +ircd::net::dns::cache::waiter::call(waiter &waiter, + const uint16_t &type, + const string_view &tgt, + const json::array &rrs) +try +{ + if(tgt != waiter.key) + return false; + + if(type != waiter.opts.qtype) + return false; + + const hostport &target + { + waiter.opts.qtype == 33? + unmake_SRV_key(waiter.key): + waiter.key, + + waiter.port + }; + + assert(waiter.callback); + waiter.callback(target, rrs); + return true; +} +catch(const std::exception &e) +{ + log::critical + { + log, "callback:%p %s,%s :%s", + (const void *)&waiter, + type, + tgt, + e.what(), + }; + + return true; +} diff --git a/modules/net_dns_cache.cc b/modules/net_dns_cache.cc index 15cd0ff46..7ff4367ab 100644 --- a/modules/net_dns_cache.cc +++ b/modules/net_dns_cache.cc @@ -10,8 +10,6 @@ namespace ircd::net::dns::cache { - static bool call_waiter(const string_view &, const string_view &, const json::array &, waiter &); - static size_t call_waiters(const string_view &, const string_view &, const json::array &); static void handle(const m::event &, m::vm::eval &); static bool put(const string_view &type, const string_view &state_key, const records &rrs); @@ -200,7 +198,7 @@ catch(const http::error &e) const json::value error_records{&error_value, 1}; const json::strung error{error_records}; - call_waiters(type, state_key, error); + waiter::call(rfc1035::qtype.at(lstrip(type, "ircd.dns.rrs.")), state_key, error); return false; } catch(const std::exception &e) @@ -224,7 +222,7 @@ catch(const std::exception &e) const json::value error_value{error_object}; const json::value error_records{&error_value, 1}; const json::strung error{error_records}; - call_waiters(type, state_key, error); + waiter::call(rfc1035::qtype.at(lstrip(type, "ircd.dns.rrs.")), state_key, error); return false; } @@ -327,7 +325,7 @@ catch(const http::error &e) const json::value error_records{&error_value, 1}; const json::strung error{error_records}; - call_waiters(type, state_key, error); + waiter::call(rfc1035::qtype.at(lstrip(type, "ircd.dns.rrs.")), state_key, error); return false; } catch(const std::exception &e) @@ -350,7 +348,7 @@ catch(const std::exception &e) const json::value error_value{error_object}; const json::value error_records{&error_value, 1}; const json::strung error{error_records}; - call_waiters(type, state_key, error); + waiter::call(rfc1035::qtype.at(lstrip(type, "ircd.dns.rrs.")), state_key, error); return false; } @@ -536,7 +534,7 @@ try json::get<"content"_>(event).get("") }; - call_waiters(type, state_key, rrs); + waiter::call(rfc1035::qtype.at(lstrip(type, "ircd.dns.rrs.")), state_key, rrs); } catch(const std::exception &e) { @@ -546,82 +544,6 @@ catch(const std::exception &e) }; } -/// Note complications due to reentrance and other factors: -/// - This function is invoked from several different places on both the -/// timeout and receive contexts, in addition to any evaluator context. -/// - This function calls back to users making DNS queries, and they may -/// conduct another query in their callback frame -- mid-loop in this -/// function. -size_t -ircd::net::dns::cache::call_waiters(const string_view &type, - const string_view &state_key, - const json::array &rrs) -{ - const ctx::uninterruptible::nothrow ui; - size_t ret(0), last; do - { - const std::lock_guard lock - { - mutex - }; - - auto it(begin(waiting)); - for(last = ret; it != end(waiting); ++it) - if(call_waiter(type, state_key, rrs, *it)) - { - it = waiting.erase(it); - ++ret; - break; - } - } - while(last < ret); - - if(ret) - dock.notify_all(); - - return ret; -} - -bool -ircd::net::dns::cache::call_waiter(const string_view &type, - const string_view &state_key, - const json::array &rrs, - waiter &waiter) -try -{ - if(state_key != waiter.key) - return false; - - if(lstrip(type, "ircd.dns.rrs.") != rfc1035::rqtype.at(waiter.opts.qtype)) - return false; - - const hostport &target - { - waiter.opts.qtype == 33? - unmake_SRV_key(waiter.key): - waiter.key, - - waiter.port - }; - - assert(waiter.callback); - waiter.callback(target, rrs); - return true; -} -catch(const std::exception &e) -{ - log::critical - { - log, "callback:%p %s,%s :%s", - (const void *)&waiter, - type, - state_key, - e.what(), - }; - - return true; -} - // // cache room creation //