Bail early in listenUDPInPortRange on interface-level errors#896
Conversation
671d794 to
a79c67d
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #896 +/- ##
==========================================
+ Coverage 88.41% 88.49% +0.08%
==========================================
Files 44 45 +1
Lines 5626 5633 +7
==========================================
+ Hits 4974 4985 +11
+ Misses 449 445 -4
Partials 203 203
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
When a network interface disappears (e.g. in Kubernetes with host_network where pod interfaces come and go), ListenUDP fails with EADDRNOTAVAIL for every port in the range. Previously the loop tried all ports before giving up, causing high CPU usage with large port ranges. Now listenUDPInPortRange detects EADDRNOTAVAIL and returns immediately instead of exhausting the entire port range. Uses platform-specific files to handle the errno difference between POSIX (syscall.EADDRNOTAVAIL) and Windows (WSAEADDRNOTAVAIL = 10049). Fixes pion#779 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
71312bf to
268e9ba
Compare
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JoTurk
left a comment
There was a problem hiding this comment.
thank you so much, i think we can merge this once the internal comment is addressed.
| } | ||
|
|
||
| return false | ||
| } |
There was a problem hiding this comment.
Can you please move this to internal?
| // to verify that binding to a non-existent IP bails immediately instead of | ||
| // exhausting the port range. This reproduces the exact scenario from #779. | ||
| func TestListenUDPInPortRange_RealEADDRNOTAVAIL(t *testing.T) { | ||
| // This test requires real kernel bind() semantics. |
There was a problem hiding this comment.
nit: not against AI generated PRs or Claude, but i would rather not having comments of the kind of // does something for something().
There was a problem hiding this comment.
yeah good point, fixed
Move isInterfaceLevelError to internal/netutil and remove verbose test comments.
Summary
host_network: true),listenUDPInPortRangewould try every port in the range before giving up, causing high CPU usageisInterfaceLevelError()to detectEADDRNOTAVAIL— the error the kernel returns when binding to an IP that is no longer assigned to any local interfaceEADDRNOTAVAILinstead of exhausting the entire port rangeEADDRNOTAVAILand WindowsWSAEADDRNOTAVAIL(10049) via platform-specific filesFixes #779
Test plan
TestListenUDPInPortRange_BailsOnEADDRNOTAVAIL— mock test verifying early bail onEADDRNOTAVAILwrapped in real kernel error chain (OpError → SyscallError → Errno)TestListenUDPInPortRange_ContinuesOnPortBusyError— regression guard:EADDRINUSEstill tries all portsTestListenUDPInPortRange_RealEADDRNOTAVAIL— integration test using actual kernelbind()against TEST-NET-1 (192.0.2.1), skipped on WASMDefaultsPortMinTo1024andDefaultsPortMaxToFFFFstill passgolangci-lintpasses with no new issues