Abort mux srflx gather on close#940
Conversation
8628863 to
caf5678
Compare
There was a problem hiding this comment.
Pull request overview
This PR aims to prevent agent shutdown deadlocks under early Close() by making server-reflexive (srflx) gathering abortable: it propagates context.Context through STUN/XOR-mapped address discovery and ensures blocked mux writes can be aborted during close (continuing the work from #934).
Changes:
- Add context-aware write plumbing in
UDPMuxDefaultso a canceled context can abort a blockedWriteTo. - Introduce
GetXORMappedAddrContextforUniversalUDPMuxDefaultand use it during srflx gathering when available. - Extend agent close pre-stop behavior to abort srflx mux writes and add a regression test covering the deadlock scenario.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| udp_mux.go | Adds context-aware write path (writeToContext / startWriteContext) to support aborting blocked writes on cancellation. |
| udp_mux_universal.go | Adds GetXORMappedAddrContext, routes STUN writes through context-aware mux writing, and avoids time.After allocation by using a timer. |
| gather.go | Uses a helper to prefer context-aware XOR-mapped address lookup during srflx gathering with UDPMux. |
| agent.go | Replaces the close pre-stop hook to also abort srflx mux writes during shutdown. |
| agent_test.go | Adds a regression test that validates close aborts a blocked srflx gather write. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #940 +/- ##
==========================================
- Coverage 88.33% 88.21% -0.12%
==========================================
Files 46 46
Lines 6080 6129 +49
==========================================
+ Hits 5371 5407 +36
- Misses 487 497 +10
- Partials 222 225 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
caf5678 to
a64e521
Compare
ec9247a to
79bedca
Compare
0bb1d45 to
4e5a0c8
Compare
4e5a0c8 to
7dd5cb0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
udp_mux_universal.go:263
writeSTUNcurrently sends a new STUN BindingRequest even when there is already an entry inxorMappedMapfor the same server. That contradicts the nearby comment (“we already sent a STUN request”) and can generate a burst of duplicate STUN requests when multiple goroutines callGetXORMappedAddr*concurrently for the same STUN server. Consider reusing the existingwaitAddrReceivedchannel when the map entry already exists, and only sending a packet when creating a new entry; also delete/close the newly-created entry if the initial write fails so callers don’t end up waiting on a never-fulfilled pending entry.
// If record present in the map, we already sent a STUN request,
// just wait when waitAddrReceived will be closed
addrMap, ok := m.xorMappedMap[serverAddr.String()]
if !ok {
addrMap = &xorMapped{
| onWrite: func() { | ||
| mux.mu.Lock() | ||
| mappedAddr := mux.xorMappedMap[serverAddr.String()] | ||
| mappedAddr.closeWaiters() | ||
| delete(mux.xorMappedMap, serverAddr.String()) | ||
| mux.mu.Unlock() | ||
| }, | ||
| } | ||
| mux = &UniversalUDPMuxDefault{ | ||
| UDPMuxDefault: &UDPMuxDefault{}, | ||
| params: UniversalUDPMuxParams{ | ||
| UDPConn: pc, | ||
| }, | ||
| xorMappedMap: map[string]*xorMapped{ | ||
| serverAddr.String(): { | ||
| waitAddrReceived: waitCh, | ||
| expiresAt: time.Now().Add(time.Minute), | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| addr, err := mux.GetXORMappedAddr(serverAddr, time.Second) |
There was a problem hiding this comment.
Hmm that's not possible without doing an extraction and a refactor to the actual code, I'll try to do it later with future cleanups.
boks1971
left a comment
There was a problem hiding this comment.
lgtm! but, I am not able to quite follow the abort write loop in writeToContext. Would be good to get more 👀 on this.
Thank you for the review, And sorry for not adding comments to explain it. I'll add more comments. This path is only for stun-writes and doesn't affect normal writes, because we don't use cancellable contexts with non stun writes. So,
for a good path:
For aborting:
For blocked aborting:
|
7dd5cb0 to
badee80
Compare
badee80 to
1e87163
Compare
Description
Makes srflx gather abort-able and passes context in more code, this can deadlock under early close for full-ice agents. continues after #934
did refactor GetXORMappedAddr to make the linter happy.