mirror of
https://github.com/fatedier/frp.git
synced 2026-10-19 19:13:32 +08:00
KCPListener hands accepted sessions to a consumer through an unbuffered channel, but its accept goroutine wrote to that channel without watching for shutdown. A Close racing with a handoff left the goroutine blocked forever, holding the session it was about to deliver, because closing the underlying listener does not unblock a send. The close flag it read was also written by Close without synchronisation. Watch a done channel in the handoff and close the connection that was never delivered, so the goroutine can exit and the session is released. Accept now returns ErrKCPListenerClosed as soon as the listener is closed instead of blocking on the channel, and the close state is a done channel guarded by sync.Once. A ready handoff can still win the race with Close; the session then belongs to the caller of Accept, matching how WebsocketListener behaves. Tests cover a pending handoff that is cancelled by Close and a blocked Accept that is woken by it.