99
1010DnsResolver *DnsResolver::this_ = NULL ;
1111
12- DnsResolver::DnsResolver () : channel_(NULL )
12+ DnsResolver::DnsResolver ()
13+ : bStopCalled_(false )
14+ , bNeedFinish_(false )
15+ , channel_(NULL )
1316{
1417 assert (this_ == NULL );
1518 this_ = this ;
1619 aresLibraryInit_.init ();
20+
21+ thread_ = std::thread (threadFunc, this );
1722}
1823
1924DnsResolver::~DnsResolver ()
2025{
21- cancelAll ( );
26+ assert (bStopCalled_ );
2227 this_ = NULL ;
2328}
2429
@@ -31,106 +36,159 @@ void DnsResolver::setResolveDomainsCallbackHandler(std::function<void(std::map<s
3136void DnsResolver::stop ()
3237{
3338 cancelAll ();
39+
40+ // kick thread
41+ this_->mutex_ .lock ();
42+ bNeedFinish_ = true ;
43+ waitCondition_.notify_all ();
44+ this_->mutex_ .unlock ();
45+
46+ // wait for thread to finish
47+ thread_.join ();
48+ bStopCalled_ = true ;
3449}
3550
3651void DnsResolver::resolveDomains (const std::vector<std::string> &hostnames)
3752{
3853 std::lock_guard<std::mutex> lock (mutex_);
3954
40- // cancel any lookups currently in channel
41- if (!hostnamesInProgress_. empty ()) {
42- ares_cancel (channel_);
43- ares_destroy (channel_);
44- ares_queue_wait_empty (channel_, - 1 );
45- this_-> channel_ = NULL ;
46- } else {
47- assert (channel_ == NULL );
48- }
49- hostnamesInProgress_. clear ();
50- hostinfoResults_. clear ( );
51-
52- struct ares_options options ;
53- int optmask = 0 ;
54- memset (&options, 0 , sizeof (options));
55- optmask |= ARES_OPT_TRIES ;
56- options. tries = 3 ;
57- optmask |= ARES_OPT_EVENT_THREAD ;
58- options. evsys = ARES_EVSYS_DEFAULT ;
59- optmask |= ARES_OPT_MAXTIMEOUTMS ;
60- options. maxtimeout = 5 * 1000 ;
61-
62- int status = ares_init_options (&channel_, &options, optmask);
63- if (status != ARES_SUCCESS) {
64- Logger::instance ().out (" ares_init_options failed: %s" , ares_strerror (status));
65- return ;
66- }
55+ {
56+ // cancel any lookups currently in channel
57+ if (!hostnamesInProgress_. empty ())
58+ {
59+ ares_cancel (channel_);
60+ ares_destroy (channel_) ;
61+ this_-> channel_ = NULL ;
62+ }
63+ else
64+ {
65+ assert (channel_ == NULL );
66+ }
67+ hostnamesInProgress_. clear () ;
68+ hostinfoResults_. clear () ;
69+
70+ struct ares_options options ;
71+ int optmask = 0 ;
72+ memset (&options, 0 , sizeof (options)) ;
73+ optmask |= ARES_OPT_TRIES ;
74+ options. tries = 3 ;
75+
76+ int status = ares_init_options (&channel_, &options, optmask);
77+ if (status != ARES_SUCCESS)
78+ {
79+ Logger::instance ().out (" ares_init_options failed: %s" , ares_strerror (status));
80+ return ;
81+ }
6782
68- for (auto &hostname : hostnames) {
69- hostnamesInProgress_.insert (hostname);
70- }
83+ for (auto &hostname : hostnames)
84+ {
85+ hostnamesInProgress_.insert (hostname);
86+ }
7187
72- // filter for unique hostnames and execute request
73- for (auto &hostname : hostnames) {
74- USER_ARG *userArg = new USER_ARG ();
75- userArg->hostname = hostname;
76- struct ares_addrinfo_hints hints;
77- memset (&hints, 0 , sizeof (hints));
78- hints.ai_family = AF_INET;
79- ares_getaddrinfo (channel_, hostname.c_str (), NULL , &hints, aresLookupFinishedCallback, userArg);
88+ // filter for unique hostnames and execute request
89+ for (auto &hostname : hostnames)
90+ {
91+ USER_ARG *userArg = new USER_ARG ();
92+ userArg->hostname = hostname;
93+ ares_gethostbyname (channel_, hostname.c_str (), AF_INET, aresLookupFinishedCallback, userArg);
94+ }
8095 }
96+
97+ // kick thread
98+ waitCondition_.notify_all ();
8199}
82100
83101void DnsResolver::cancelAll ()
84102{
85103 std::lock_guard<std::mutex> lock (mutex_);
86-
87- if (channel_) {
104+ if (channel_)
105+ {
88106 ares_cancel (channel_);
89107 hostnamesInProgress_.clear ();
90108 ares_destroy (channel_);
91- ares_queue_wait_empty (channel_, -1 );
92109 }
93110 channel_ = NULL ;
94111}
95112
96- void DnsResolver::aresLookupFinishedCallback (void * arg, int status, int /* timeouts*/ , struct ares_addrinfo *result)
97- {
98- if (this_ == nullptr ) {
99- assert (false );
100- return ;
101- };
102-
103- std::lock_guard<std::mutex> lock (this_->mutex_ );
104113
114+ void DnsResolver::aresLookupFinishedCallback (void * arg, int status, int /* timeouts*/ , struct hostent * host)
115+ {
105116 USER_ARG *userArg = static_cast <USER_ARG *>(arg);
106117
107118 // cancel and fail cases
108- if (status == ARES_ECANCELLED) {
119+ if (status == ARES_ECANCELLED)
120+ {
109121 delete userArg;
110122 return ;
111123 }
112124
113125 HostInfo hostInfo;
114126 hostInfo.hostname = userArg->hostname ;
115127
116- if (status != ARES_SUCCESS) {
128+ if (status != ARES_SUCCESS)
129+ {
117130 hostInfo.error = true ;
118- } else {
131+ }
132+ else
133+ {
119134 // add ips
120- for (struct ares_addrinfo_node *node = result->nodes ; node != NULL ; node = node->ai_next ) {
135+ for (char **p = host->h_addr_list ; *p; p++)
136+ {
121137 char addr_buf[46 ] = " ??" ;
122- ares_inet_ntop (node-> ai_family , &(( const struct sockaddr_in *)(( void *)node-> ai_addr ))-> sin_addr , addr_buf, sizeof (addr_buf));
138+ ares_inet_ntop (host-> h_addrtype , *p , addr_buf, sizeof (addr_buf));
123139 hostInfo.addresses .push_back (std::string (addr_buf));
124140 }
125141 }
126142
127143 this_->hostinfoResults_ [hostInfo.hostname ] = hostInfo;
128144 this_->hostnamesInProgress_ .erase (userArg->hostname );
129145
130- if (this_->hostnamesInProgress_ .empty ()) {
146+ if (this_->hostnamesInProgress_ .empty ())
147+ {
131148 this_->resolveDomainsCallback_ (this_->hostinfoResults_ );
132149 }
133150
134151 delete userArg;
135152}
136153
154+ void DnsResolver::threadFunc (void *arg)
155+ {
156+ // BIND_CRASH_HANDLER_FOR_THREAD();
157+ DnsResolver *resolver = static_cast <DnsResolver *>(arg);
158+
159+ while (true )
160+ {
161+ {
162+ std::unique_lock<std::mutex> lockWait (resolver->mutex_ );
163+ if (resolver->bNeedFinish_ )
164+ {
165+ break ;
166+ }
167+
168+ if (resolver->channel_ != NULL && !resolver->processChannel (resolver->channel_ ))
169+ {
170+ resolver->waitCondition_ .wait (lockWait);
171+ }
172+ }
173+ sleep (1 );
174+ }
175+ }
176+
177+ bool DnsResolver::processChannel (ares_channel channel)
178+ {
179+ fd_set read_fds, write_fds;
180+ int res;
181+ int nfds;
182+
183+ FD_ZERO (&read_fds);
184+ FD_ZERO (&write_fds);
185+ nfds = ares_fds (channel, &read_fds, &write_fds);
186+ if (nfds == 0 ) {
187+ return false ;
188+ }
189+ timeval tv;
190+ timeval *tvp = ares_timeout (channel, NULL , &tv);
191+ res = select (nfds, &read_fds, &write_fds, NULL , tvp);
192+ ares_process (channel, &read_fds, &write_fds);
193+ return true ;
194+ }
0 commit comments