mirror of
https://github.com/fosrl/gerbil.git
synced 2026-09-07 22:51:28 +02:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f457db7b5 | ||
|
|
6d548ea166 |
@@ -149,6 +149,13 @@ type cachedEndpointState struct {
|
|||||||
PublicKey string
|
PublicKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cachedEndpointEntry wraps cachedEndpointState with a timestamp so the cache
|
||||||
|
// can be expired after a short TTL even when the endpoint fields are unchanged.
|
||||||
|
type cachedEndpointEntry struct {
|
||||||
|
state cachedEndpointState
|
||||||
|
cachedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
// --- End Types ---
|
// --- End Types ---
|
||||||
|
|
||||||
// bufferPool allows reusing buffers to reduce allocations.
|
// bufferPool allows reusing buffers to reduce allocations.
|
||||||
@@ -406,6 +413,9 @@ func (s *UDPProxyServer) packetWorker() {
|
|||||||
logger.Debug("Created endpoint from packet remoteAddr %s: IP=%s, Port=%d", packet.remoteAddr.String(), endpoint.IP, endpoint.Port)
|
logger.Debug("Created endpoint from packet remoteAddr %s: IP=%s, Port=%d", packet.remoteAddr.String(), endpoint.IP, endpoint.Port)
|
||||||
|
|
||||||
// Check if anything meaningful changed before queuing an HTTP notification.
|
// Check if anything meaningful changed before queuing an HTTP notification.
|
||||||
|
// The cache expires after 2.5 s so the server always receives a fresh
|
||||||
|
// timestamp within its 5-second staleness window.
|
||||||
|
const endpointCacheTTL = 2500 * time.Millisecond
|
||||||
cacheKey := endpoint.OlmID + ":" + endpoint.NewtID
|
cacheKey := endpoint.OlmID + ":" + endpoint.NewtID
|
||||||
newState := cachedEndpointState{
|
newState := cachedEndpointState{
|
||||||
OlmID: endpoint.OlmID,
|
OlmID: endpoint.OlmID,
|
||||||
@@ -415,16 +425,19 @@ func (s *UDPProxyServer) packetWorker() {
|
|||||||
Port: endpoint.Port,
|
Port: endpoint.Port,
|
||||||
PublicKey: endpoint.ClientPublicKey,
|
PublicKey: endpoint.ClientPublicKey,
|
||||||
}
|
}
|
||||||
if cached, ok := s.lastEndpointCache.Load(cacheKey); ok && cached.(cachedEndpointState) == newState {
|
if cached, ok := s.lastEndpointCache.Load(cacheKey); ok {
|
||||||
// Endpoint unchanged - skip the HTTP call but still clear stale sessions.
|
entry := cached.(cachedEndpointEntry)
|
||||||
logger.Debug("Endpoint unchanged for %s, skipping notification", cacheKey)
|
if entry.state == newState && time.Since(entry.cachedAt) < endpointCacheTTL {
|
||||||
metrics.RecordHolePunchEvent(relayIfname, "deduplicated")
|
// Endpoint unchanged and cache still fresh - skip the HTTP call.
|
||||||
s.clearSessionsForIP(endpoint.IP)
|
logger.Debug("Endpoint unchanged for %s, skipping notification", cacheKey)
|
||||||
metrics.RecordHolePunchEvent(relayIfname, "success")
|
metrics.RecordHolePunchEvent(relayIfname, "deduplicated")
|
||||||
bufferPool.Put(packet.data[:1500])
|
s.clearSessionsForIP(endpoint.IP)
|
||||||
continue
|
metrics.RecordHolePunchEvent(relayIfname, "success")
|
||||||
|
bufferPool.Put(packet.data[:1500])
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s.lastEndpointCache.Store(cacheKey, newState)
|
s.lastEndpointCache.Store(cacheKey, cachedEndpointEntry{state: newState, cachedAt: time.Now()})
|
||||||
|
|
||||||
// Queue the notification asynchronously so the hot path is not blocked by HTTP.
|
// Queue the notification asynchronously so the hot path is not blocked by HTTP.
|
||||||
select {
|
select {
|
||||||
|
|||||||
Reference in New Issue
Block a user