41class GNet::ResolverImp :
private FutureEventHandler
44 ResolverImp( Resolver & , ExceptionSink ,
const Location & ) ;
47 ~ResolverImp()
override ;
55 static void start( ResolverImp * , HANDLE ) noexcept ;
61 static std::size_t zcount() noexcept ;
65 void onFutureEvent() override ;
68 ResolverImp( const ResolverImp & ) = delete ;
69 ResolverImp( ResolverImp && ) = delete ;
70 ResolverImp & operator=( const ResolverImp & ) = delete ;
71 ResolverImp & operator=( ResolverImp && ) = delete ;
77 using Pair = ResolverFuture::Pair ;
78 Resolver * m_resolver ;
79 std::unique_ptr<FutureEvent> m_future_event ;
80 Timer<ResolverImp> m_timer ;
82 ResolverFuture m_future ;
83 G::threading::thread_type m_thread ;
84 static
std::
size_t m_zcount ;
87std::
size_t GNet::ResolverImp::m_zcount = 0U ;
89GNet::ResolverImp::ResolverImp( Resolver & resolver , ExceptionSink es , const Location & location ) :
90 m_resolver(&resolver) ,
91 m_future_event(
std::make_unique<FutureEvent>(static_cast<FutureEventHandler&>(*this),es)) ,
92 m_timer(*this,&ResolverImp::onTimeout,es) ,
93 m_location(location) ,
94 m_future(location.host(),location.service(),location.family(),false,true)
96 G_ASSERT( G::threading::works() ) ;
98 m_thread = G::threading::thread_type( ResolverImp::start ,
this , m_future_event->handle() ) ;
101GNet::ResolverImp::~ResolverImp()
106 if( m_thread.joinable() )
114std::size_t GNet::ResolverImp::zcount() noexcept
119void GNet::ResolverImp::start( ResolverImp * This , HANDLE handle )
noexcept
124 This->m_future.run() ;
134void GNet::ResolverImp::onFutureEvent()
136 G_DEBUG(
"GNet::ResolverImp::onFutureEvent: future event: ptr=" << m_resolver ) ;
138 Pair result = m_future.get() ;
139 if( !m_future.error() )
140 m_location.update( result.first , result.second ) ;
142 if( m_thread.joinable() )
145 Resolver * resolver = m_resolver ;
146 m_resolver = nullptr ;
148 resolver->done( std::string(m_future.reason()) , Location(m_location) ) ;
151bool GNet::ResolverImp::zombify()
153 m_resolver = nullptr ;
154 m_timer.startTimer( 0U ) ;
159void GNet::ResolverImp::onTimeout()
161 if( m_thread.joinable() )
163 m_timer.startTimer( 1U ) ;
175 m_callback(callback) ,
183 if( m_imp && m_imp->zombify() )
185 G_DEBUG(
"GNet::Resolver::dtor: zcount=" << ResolverImp::zcount() ) ;
186 if( ResolverImp::zcount() == 100U )
187 G_WARNING_ONCE(
"GNet::Resolver::dtor: large number of threads waiting for dns results" ) ;
190 GDEF_IGNORE_RETURN m_imp.release() ;
197 using Pair = ResolverFuture::Pair ;
198 G_DEBUG(
"GNet::Resolver::resolve: resolve request [" << location.
displayString() <<
"]"
199 <<
" (" << location.
family() <<
")" ) ;
202 Pair result = future.
get() ;
205 G_DEBUG(
"GNet::Resolver::resolve: resolve error [" << future.
reason() <<
"]" ) ;
210 G_DEBUG(
"GNet::Resolver::resolve: resolve result [" << result.first.displayString() <<
"]"
211 <<
"[" << result.second <<
"]" ) ;
212 location.
update( result.first , result.second ) ;
219 int family ,
bool dgram )
222 G_DEBUG(
"GNet::Resolver::resolve: resolve-request [" << host <<
"/"
223 << service <<
"/" << (family==AF_UNSPEC?
"ip":(family==AF_INET?
"ipv4":
"ipv6")) <<
"]" ) ;
228 G_DEBUG(
"GNet::Resolver::resolve: resolve result: list of " << list.size() ) ;
237 if( !async() )
throw Error(
"not multi-threaded" ) ;
238 if( busy() )
throw BusyError() ;
239 G_DEBUG(
"GNet::Resolver::start: resolve start [" << location.
displayString() <<
"]" ) ;
240 m_imp = std::make_unique<ResolverImp>( *
this , m_es , location ) ;
243void GNet::Resolver::done(
const std::string & error ,
const Location & location )
246 G_DEBUG(
"GNet::Resolver::done: resolve done: error=[" << error <<
"] "
249 m_callback.onResolved( error , location ) ;
254 return m_imp != nullptr ;
259 if( G::threading::works() )
265 G_DEBUG(
"GNet::Resolver::async: not multi-threaded: using synchronous domain name lookup");
virtual bool running() const =0
Returns true if called from within run().
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
static bool send(HANDLE handle, bool close=true) noexcept
Pokes an event into the main event loop so that the FutureEventHandler callback is called asynchronou...
A class that represents the remote target for out-going client connections.
int family() const
Returns the preferred name resolution address family as passed to the constructor.
std::string displayString() const
Returns a string representation for logging and debug.
void update(const Address &address, const std::string &canonical_name)
Updates the address and canonical name, typically after doing a name lookup on host() and service().
std::string service() const
Returns the remote service name derived from the constructor parameter.
std::string host() const
Returns the remote host name derived from the constructor parameter.
A 'future' shared-state class for asynchronous name resolution that holds parameters and results of a...
bool error() const
Returns true if name resolution failed or no suitable address was returned.
std::string reason() const
Returns the reason for the error().
Pair get()
Returns the resolved address/name pair after run() has completed.
ResolverFuture & run() noexcept
Does the synchronous name resolution and stores the result.
static std::string resolve(Location &)
Does synchronous name resolution.
Resolver(Callback &, ExceptionSink)
Constructor taking a callback interface reference.
static bool async()
Returns true if the resolver supports asynchronous operation.
void start(const Location &)
Starts asynchronous name-to-address resolution.
bool busy() const
Returns true if there is a pending resolve request.
An interface used for GNet::Resolver callbacks.
A RAII class to temporarily block signal delivery.