41class GNet::ResolverImp :
private FutureEventHandler
44 ResolverImp( Resolver & , EventState ,
const Location & ,
const Resolver::Config & ) ;
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 Resolver * m_resolver ;
78 std::unique_ptr<FutureEvent> m_future_event ;
79 Timer<ResolverImp> m_timer ;
81 ResolverFuture m_future ;
82 G::threading::thread_type m_thread ;
83 static
std::
size_t m_zcount ;
86std::
size_t GNet::ResolverImp::m_zcount = 0U ;
88GNet::ResolverImp::ResolverImp( Resolver & resolver , EventState es , const Location & location , const Resolver::Config & config ) :
89 m_resolver(&resolver) ,
90 m_future_event(
std::make_unique<FutureEvent>(static_cast<FutureEventHandler&>(*this),es)) ,
91 m_timer(*this,&ResolverImp::onTimeout,es) ,
92 m_location(location) ,
93 m_future(location.host(),location.service(),location.family(),config)
95 G_ASSERT( G::threading::works() ) ;
97 m_thread = G::threading::thread_type( ResolverImp::start ,
this , m_future_event->handle() ) ;
100GNet::ResolverImp::~ResolverImp()
105 if( m_thread.joinable() )
113std::size_t GNet::ResolverImp::zcount() noexcept
118void GNet::ResolverImp::start( ResolverImp * This , HANDLE handle )
noexcept
123 This->m_future.run() ;
133void GNet::ResolverImp::onFutureEvent()
135 G_DEBUG(
"GNet::ResolverImp::onFutureEvent: future event: ptr=" << m_resolver ) ;
137 ResolverFuture::Result result = m_future.get() ;
138 if( !m_future.error() )
139 m_location.update( result.address ) ;
141 if( m_thread.joinable() )
144 Resolver * resolver = m_resolver ;
145 m_resolver = nullptr ;
147 resolver->done( std::string(m_future.reason()) , Location(m_location) ) ;
150bool GNet::ResolverImp::zombify()
152 m_resolver = nullptr ;
153 m_timer.startTimer( 0U ) ;
158void GNet::ResolverImp::onTimeout()
160 if( m_thread.joinable() )
162 m_timer.startTimer( 1U ) ;
174 m_callback(callback) ,
182 if( m_imp && m_imp->zombify() )
184 G_DEBUG(
"GNet::Resolver::dtor: zcount=" << ResolverImp::zcount() ) ;
185 if( ResolverImp::zcount() == 100U )
186 G_WARNING_ONCE(
"GNet::Resolver::dtor: large number of threads waiting for dns results" ) ;
189 GDEF_IGNORE_RETURN m_imp.release() ;
195 return resolve(location,{}).first ;
202 G_DEBUG(
"GNet::Resolver::resolve: resolve request [" << location.
displayString() <<
"]"
203 <<
" (" << location.
family() <<
")" ) ;
206 Result result = future.
get() ;
209 G_DEBUG(
"GNet::Resolver::resolve: resolve error [" << future.
reason() <<
"]" ) ;
210 return {future.
reason(),{}} ;
214 G_DEBUG(
"GNet::Resolver::resolve: resolve result [" << result.address.displayString() <<
"]" ) ;
215 location.
update( result.address ) ;
216 return {{},result.canonicalName} ;
222 int family ,
const Config & config )
225 G_DEBUG(
"GNet::Resolver::resolve: resolve-request [" << host <<
"/"
226 << service <<
"/" << (family==AF_UNSPEC?
"ip":(family==AF_INET?
"ipv4":
"ipv6")) <<
"]" ) ;
231 G_DEBUG(
"GNet::Resolver::resolve: resolve result: list of " << list.size() ) ;
240 if( !async() )
throw Error(
"not multi-threaded" ) ;
241 if( busy() )
throw BusyError() ;
242 G_DEBUG(
"GNet::Resolver::start: resolve start [" << location.
displayString() <<
"]" ) ;
243 m_imp = std::make_unique<ResolverImp>( *
this , m_es , location , config ) ;
246void GNet::Resolver::done(
const std::string & error ,
const Location & location )
249 G_DEBUG(
"GNet::Resolver::done: resolve done: error=[" << error <<
"] "
252 m_callback.onResolved( error , location ) ;
257 return m_imp != nullptr ;
262 if( G::threading::works() )
268 G_DEBUG(
"GNet::Resolver::async: not multi-threaded: using synchronous domain name lookup");
273GNet::Resolver::Config::Config()
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 lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
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.
std::string service() const
Returns the remote service name derived from the constructor parameter.
void update(const Address &address)
Updates the address, typically after doing a name lookup on host() and service().
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...
Result get()
Returns the resolved address after run() has completed.
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().
ResolverFuture & run() noexcept
Does the synchronous name resolution and stores the result.
Resolver(Callback &, EventState)
Constructor taking a callback interface reference.
static std::pair< std::string, std::string > resolve(Location &, const Config &)
Does synchronous name resolution.
void start(const Location &, const Config &={})
Starts asynchronous name-to-address resolution.
static bool async()
Returns true if the resolver supports asynchronous operation.
bool busy() const
Returns true if there is a pending resolve request.
Result structure for GNet::ResolverFuture::get().
An interface used for GNet::Resolver callbacks.
A configuration structure for GNet::Resolver.
A RAII class to temporarily block signal delivery.