mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-07-05 01:24:15 +00:00
Use old value and update in other goroutine
This commit is contained in:
parent
54774ceca6
commit
8b8bd3c40d
1 changed files with 31 additions and 22 deletions
|
@ -12,6 +12,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
@ -76,11 +77,31 @@ func ApplyECH(c *Config, config *tls.Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ECHConfigCache struct {
|
type ECHConfigCache struct {
|
||||||
echConfig []byte
|
echConfig atomic.Pointer[[]byte]
|
||||||
expire time.Time
|
expire *time.Time
|
||||||
updateLock sync.Mutex
|
updateLock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ECHConfigCache) update(domain string, server string) ([]byte, error) {
|
||||||
|
c.updateLock.Lock()
|
||||||
|
defer c.updateLock.Unlock()
|
||||||
|
// Double check cache after acquiring lock
|
||||||
|
if c.expire.After(time.Now()) {
|
||||||
|
errors.LogDebug(context.Background(), "Cache hit for domain after double check: ", domain)
|
||||||
|
return *c.echConfig.Load(), nil
|
||||||
|
}
|
||||||
|
// Query ECH config from DNS server
|
||||||
|
errors.LogDebug(context.Background(), "Trying to query ECH config for domain: ", domain, " with ECH server: ", server)
|
||||||
|
echConfig, ttl, err := dnsQuery(server, domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.echConfig.Store(&echConfig)
|
||||||
|
expire := time.Now().Add(time.Duration(ttl) * time.Second)
|
||||||
|
c.expire = &expire
|
||||||
|
return *c.echConfig.Load(), nil
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
GlobalECHConfigCache map[string]*ECHConfigCache
|
GlobalECHConfigCache map[string]*ECHConfigCache
|
||||||
GlobalECHConfigCacheAccess sync.Mutex
|
GlobalECHConfigCacheAccess sync.Mutex
|
||||||
|
@ -99,7 +120,7 @@ func QueryRecord(domain string, server string) ([]byte, error) {
|
||||||
if echConfigCache != nil && echConfigCache.expire.After(time.Now()) {
|
if echConfigCache != nil && echConfigCache.expire.After(time.Now()) {
|
||||||
errors.LogDebug(context.Background(), "Cache hit for domain: ", domain)
|
errors.LogDebug(context.Background(), "Cache hit for domain: ", domain)
|
||||||
GlobalECHConfigCacheAccess.Unlock()
|
GlobalECHConfigCacheAccess.Unlock()
|
||||||
return echConfigCache.echConfig, nil
|
return *echConfigCache.echConfig.Load(), nil
|
||||||
}
|
}
|
||||||
if echConfigCache == nil {
|
if echConfigCache == nil {
|
||||||
echConfigCache = &ECHConfigCache{}
|
echConfigCache = &ECHConfigCache{}
|
||||||
|
@ -107,26 +128,14 @@ func QueryRecord(domain string, server string) ([]byte, error) {
|
||||||
}
|
}
|
||||||
GlobalECHConfigCacheAccess.Unlock()
|
GlobalECHConfigCacheAccess.Unlock()
|
||||||
|
|
||||||
echConfigCache.updateLock.Lock()
|
// If expire is nil, it means we are in initial state, wait for the query to finish
|
||||||
defer echConfigCache.updateLock.Unlock()
|
// otherwise return old value immediately and update in a goroutine
|
||||||
// Double check cache after acquiring lock
|
if echConfigCache.expire == nil {
|
||||||
if echConfigCache.expire.After(time.Now()) {
|
return echConfigCache.update(domain, server)
|
||||||
errors.LogDebug(context.Background(), "Cache hit for domain after double check: ", domain)
|
} else {
|
||||||
return echConfigCache.echConfig, nil
|
go echConfigCache.update(domain, server)
|
||||||
|
return *echConfigCache.echConfig.Load(), nil
|
||||||
}
|
}
|
||||||
// Query ECH config from DNS server
|
|
||||||
errors.LogDebug(context.Background(), "Trying to query ECH config for domain: ", domain, " with ECH server: ", server)
|
|
||||||
echConfig, ttl, err := dnsQuery(server, domain)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Set minimum TTL to 600 seconds
|
|
||||||
if ttl < 600 {
|
|
||||||
ttl = 600
|
|
||||||
}
|
|
||||||
echConfigCache.echConfig = echConfig
|
|
||||||
echConfigCache.expire = time.Now().Add(time.Second * time.Duration(ttl))
|
|
||||||
return echConfigCache.echConfig, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dnsQuery is the real func for sending type65 query for given domain to given DNS server.
|
// dnsQuery is the real func for sending type65 query for given domain to given DNS server.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue