2
2
3
3
const net = require ( 'net' ) ;
4
4
const util = require ( 'util' ) ;
5
+ const EventEmitter = require ( 'events' ) . EventEmitter ;
5
6
6
7
const cares = process . binding ( 'cares_wrap' ) ;
7
8
const uv = process . binding ( 'uv' ) ;
@@ -11,6 +12,12 @@ const GetNameInfoReqWrap = cares.GetNameInfoReqWrap;
11
12
12
13
const isIp = net . isIP ;
13
14
15
+ // `resolving` serves as a gate to `setServers()` which is not async
16
+ // friendly, we have to wait for resolutions to finish before changing
17
+ // the servers in c-ares
18
+ const resolving = new EventEmitter ( ) ;
19
+ resolving . count = 0 ;
20
+ resolving . paused = false ;
14
21
15
22
function errnoException ( err , syscall , hostname ) {
16
23
// FIXME(bnoordhuis) Remove this backwards compatibility shite and pass
@@ -56,7 +63,10 @@ function makeAsync(callback) {
56
63
if ( typeof callback !== 'function' ) {
57
64
return callback ;
58
65
}
66
+ resolving . count ++ ;
59
67
return function asyncCallback ( ) {
68
+ if ( -- resolving . count === 0 )
69
+ resolving . emit ( 'empty' ) ;
60
70
if ( asyncCallback . immediately ) {
61
71
// The API already returned, we can invoke the callback immediately.
62
72
callback . apply ( null , arguments ) ;
@@ -164,13 +174,20 @@ exports.lookup = function lookup(hostname, options, callback) {
164
174
req . hostname = hostname ;
165
175
req . oncomplete = all ? onlookupall : onlookup ;
166
176
167
- var err = cares . getaddrinfo ( req , hostname , family , hints ) ;
168
- if ( err ) {
169
- callback ( errnoException ( err , 'getaddrinfo' , hostname ) ) ;
170
- return { } ;
177
+ function enqueue ( ) {
178
+ var err = cares . getaddrinfo ( req , hostname , family , hints ) ;
179
+ if ( err ) {
180
+ callback ( errnoException ( err , 'getaddrinfo' , hostname ) ) ;
181
+ return { } ;
182
+ }
183
+ callback . immediately = true ;
184
+ return req ;
171
185
}
172
186
173
- callback . immediately = true ;
187
+ if ( ! resolving . paused )
188
+ return enqueue ( ) ;
189
+
190
+ resolving . once ( 'ready' , enqueue ) ;
174
191
return req ;
175
192
} ;
176
193
@@ -199,10 +216,18 @@ exports.lookupService = function(host, port, callback) {
199
216
req . port = port ;
200
217
req . oncomplete = onlookupservice ;
201
218
202
- var err = cares . getnameinfo ( req , host , port ) ;
203
- if ( err ) throw errnoException ( err , 'getnameinfo' , host ) ;
219
+ function enqueue ( ) {
220
+ var err = cares . getnameinfo ( req , host , port ) ;
221
+ if ( err ) throw errnoException ( err , 'getnameinfo' , host ) ;
222
+ }
204
223
205
224
callback . immediately = true ;
225
+
226
+ if ( resolving . paused )
227
+ resolving . once ( 'ready' , enqueue ) ;
228
+ else
229
+ return enqueue ( ) ;
230
+
206
231
return req ;
207
232
} ;
208
233
@@ -232,9 +257,19 @@ function resolver(bindingName) {
232
257
hostname : name ,
233
258
oncomplete : onresolve
234
259
} ;
235
- var err = binding ( req , name ) ;
236
- if ( err ) throw errnoException ( err , bindingName ) ;
260
+
261
+ function enqueue ( ) {
262
+ var err = binding ( req , name ) ;
263
+ if ( err ) throw errnoException ( err , bindingName ) ;
264
+ }
265
+
237
266
callback . immediately = true ;
267
+
268
+ if ( resolving . paused )
269
+ resolving . once ( 'ready' , enqueue ) ;
270
+ else
271
+ return enqueue ( ) ;
272
+
238
273
return req ;
239
274
}
240
275
}
@@ -278,7 +313,31 @@ exports.getServers = function() {
278
313
} ;
279
314
280
315
281
- exports . setServers = function ( servers ) {
316
+ exports . setServers = function setServers ( servers ) {
317
+ if ( resolving . paused ) {
318
+ return resolving . once ( 'ready' , function ( ) {
319
+ setServers ( servers ) ;
320
+ } ) ;
321
+ }
322
+
323
+ if ( resolving . count === 0 ) {
324
+ return _setServers ( servers ) ;
325
+ }
326
+
327
+ resolving . paused = true
328
+ resolving . once ( 'empty' , function ( ) {
329
+ setImmediate ( function ( ) {
330
+ try {
331
+ _setServers ( servers ) ;
332
+ } finally {
333
+ resolving . paused = false ;
334
+ resolving . emit ( 'ready' ) ;
335
+ }
336
+ } ) ;
337
+ } ) ;
338
+ }
339
+
340
+ function _setServers ( servers ) {
282
341
// cache the original servers because in the event of an error setting the
283
342
// servers cares won't have any servers available for resolution
284
343
var orig = cares . getServers ( ) ;
@@ -319,7 +378,7 @@ exports.setServers = function(servers) {
319
378
throw new Error ( 'c-ares failed to set servers: "' + err +
320
379
'" [' + servers + ']' ) ;
321
380
}
322
- } ;
381
+ }
323
382
324
383
// uv_getaddrinfo flags
325
384
exports . ADDRCONFIG = cares . AI_ADDRCONFIG ;
0 commit comments