@@ -126,9 +126,9 @@ func (c *cres) copy() *cres {
126
126
anscopy = c .ans .Copy ()
127
127
}
128
128
return & cres {
129
- ans : anscopy ,
129
+ ans : anscopy , // may be nil
130
130
s : copySummary (c .s ),
131
- expiry : c .expiry ,
131
+ expiry : c .expiry , // may be zero
132
132
bumps : c .bumps ,
133
133
}
134
134
}
@@ -290,7 +290,7 @@ func asResponse(q *dns.Msg, v *cres, fresh bool) (a *dns.Msg, s *x.DNSSummary, e
290
290
// github.com/jedisct1/edgedns#correct-support-for-the-dns0x20-extension
291
291
a .Question = q .Question
292
292
if ! fresh { // if the v is not fresh, set the ttl to the minimum
293
- xdns .WithTtl (a , stalettl )
293
+ xdns .WithTtl (a , stalettl ) // only set for Answer records
294
294
}
295
295
return
296
296
}
@@ -312,12 +312,13 @@ func (t *ctransport) hangoverCheckpoint() {
312
312
}
313
313
}
314
314
315
- func (t * ctransport ) fetch (network string , q * dns.Msg , summary * x.DNSSummary , cb * cache , key string ) (r * dns.Msg , err error ) {
315
+ func (t * ctransport ) fetch (network string , q * dns.Msg , summary * x.DNSSummary , cb * cache , key string ) (* dns.Msg , error ) {
316
316
sendRequest := func (fsmm * x.DNSSummary ) (* dns.Msg , error ) {
317
317
fsmm .ID = t .Transport .ID ()
318
318
fsmm .Type = t .Transport .Type ()
319
319
320
320
v , _ := t .reqbarrier .Do (key , func () (* cres , error ) {
321
+ // ans may be nil
321
322
ans , qerr := Req (t .Transport , network , q , fsmm )
322
323
t .hangoverCheckpoint ()
323
324
// cb.put no-ops when ans is nil or xdns.Len(ans) is 0
@@ -326,32 +327,38 @@ func (t *ctransport) fetch(network string, q *dns.Msg, summary *x.DNSSummary, cb
326
327
return & cres {ans : ans , s : copySummary (fsmm )}, qerr
327
328
})
328
329
330
+ err := v .Err
331
+
329
332
cachedres , fresh := cb .freshCopy (key ) // always prefer value from cache
330
- if cachedres == nil { // use barrier response
331
- cachedres = v .Val .copy () // never nil, even on errs ; but cres.ans may be nil
333
+ if cachedres == nil { // v.Val may be uncacheable (ex: rcode != 0)
334
+ cachedres = v .Val .copy () // v.Val (cres) never nil ; but cres.ans may be nil
332
335
log .D ("cache: barrier: empty(k: %s); barrier: %s" , key , v .String ())
333
336
} else if ! fresh { // expect fresh values, except on verrs
334
337
log .W ("cache: barrier: stale(k: %s); barrier: %s (cache: %s)" , key , v .String (), cachedres .String ())
335
338
}
336
339
340
+ // nil ans when Transport returns err (no servfail) and cache is empty
341
+ hasans := cachedres .ans != nil
337
342
// if there's no network connectivity (in hangover for 10s) don't
338
343
// return cached/barriered response, instead return an error
339
- if ! t .hangover .Within (ttl10s ) {
340
- log .D ("cache: barrier: hangover(k: %s); discard ans" , key )
341
- err := errors .Join (v .Err , errHangover )
344
+ inhangover := t .hangover .Exceeds (ttl10s )
345
+ if inhangover {
346
+ err = errors .Join (err , errHangover )
347
+ log .D ("cache: barrier: hangover(k: %s); discard ans (has? %t)" , key , hasans )
342
348
fillSummary (cachedres .s , fsmm )
343
349
// mimic send fail
344
350
fsmm .Msg = err .Error ()
345
351
fsmm .RCode = dns .RcodeServerFailure
346
352
fsmm .Status = SendFailed
353
+ // do not return any response (stall / drop silently)
347
354
return nil , err
348
355
}
349
356
350
- fres , cachedsmm , ferr := asResponse (q , cachedres , true )
357
+ fres , cachedsmm , ferr := asResponse (q , cachedres , fresh )
351
358
// fill summary regardless of errors
352
359
fillSummary (cachedsmm , fsmm ) // cachedsmm may itself be fsmm
353
360
354
- return fres , errors .Join (v . Err , ferr )
361
+ return fres , errors .Join (err , ferr )
355
362
}
356
363
357
364
// check if underlying transport can connect fine, if not treat cache
@@ -364,9 +371,10 @@ func (t *ctransport) fetch(network string, q *dns.Msg, summary *x.DNSSummary, cb
364
371
365
372
if v , isfresh := cb .freshCopy (key ); trok && v != nil {
366
373
var cachedsummary * x.DNSSummary
374
+ hasans := v .ans != nil
367
375
368
- log .D ("cache: hit(k: %s / stale? %t): %s" , key , ! isfresh , v .str ())
369
- r , cachedsummary , err = asResponse (q , v , isfresh ) // return cached response, may be stale
376
+ log .D ("cache: hit(k: %s / stale? %t / ans? %t ): %s" , key , ! isfresh , hasans , v .str ())
377
+ r , cachedsummary , err : = asResponse (q , v , isfresh ) // return cached response, may be stale
370
378
if err != nil {
371
379
log .W ("cache: hit(k: %s) %s, but err? %v" , key , v .str (), err )
372
380
if err == errCacheResponseMismatch {
@@ -385,7 +393,7 @@ func (t *ctransport) fetch(network string, q *dns.Msg, summary *x.DNSSummary, cb
385
393
fillSummary (cachedsummary , summary )
386
394
summary .Latency = 0 // don't use cached latency
387
395
t .est .Add (0 ) // however, update the estimator
388
- return
396
+ return r , nil
389
397
} // else: fallthrough to sendRequest
390
398
} else {
391
399
log .D ("cache: miss(k: %s): cached? %t, hangover? %t, stale? %t" , key , v != nil , ! trok , ! isfresh )
0 commit comments