doc-fix: clarify UDP listener handles multi-source peers

No runtime change — the listener already uses net.ListenUDP +
ReadFromUDP, which is the unconnected-socket pattern that accepts
datagrams from any source. nginx reloads (new workers with fresh
ephemeral source ports) are handled transparently.

- udp.go: expanded comment on Run() explaining the design choice and
  contrasting with the `nc -k -u -l` latching quirk (which is an nc
  bug, not a kernel behaviour).
- udp_test.go: new TestUDPListenerMultipleSources regresses against
  the multi-worker scenario by sending from three independent
  ListenPacket sockets (three different ephemeral source ports).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-17 10:39:34 +02:00
parent 143aad9063
commit 589030cb00
2 changed files with 63 additions and 0 deletions

View File

@@ -33,6 +33,14 @@ func NewUDPListener(addr string, v4bits, v6bits int, ch chan<- LogRecord) *UDPLi
func (u *UDPListener) SetProm(p *PromStore) { u.prom = p }
// Run listens until ctx is cancelled.
//
// The socket is unconnected (ListenUDP + ReadFromUDP), so every datagram is
// accepted regardless of its source address. This matters across nginx
// reloads: the old worker processes hold their own ephemeral send sockets,
// and the fresh worker set opens brand-new ones. The listener reads them
// all. (Contrast with `nc -k -u -l`, which latches onto the first peer's
// address and silently drops packets from anyone else — that is an `nc`
// quirk, not a kernel behaviour, and does not apply here.)
func (u *UDPListener) Run(ctx context.Context) {
laddr, err := net.ResolveUDPAddr("udp", u.addr)
if err != nil {