Fix goroutines memory leak by unbuffered channel blocking (#2136)

* Use buffered channel to avoid goroutine hanging on

A send on an unbuffered channel can proceed if a receiver is ready.

* Balance captivePortalHandler.cancelChannels for Stop
This commit is contained in:
lifenjoiner 2022-06-29 00:28:57 +08:00 committed by GitHub
parent 59ce17e0ab
commit 0e2bb13254
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 16 deletions

View File

@ -84,6 +84,7 @@ func handleColdStartClient(clientPc *net.UDPConn, cancelChannel chan struct{}, i
exit := false exit := false
select { select {
case <-cancelChannel: case <-cancelChannel:
cancelChannel <- struct{}{}
exit = true exit = true
default: default:
} }
@ -95,6 +96,12 @@ func handleColdStartClient(clientPc *net.UDPConn, cancelChannel chan struct{}, i
} }
if err != nil { if err != nil {
dlog.Warn(err) dlog.Warn(err)
select {
case <-cancelChannel:
cancelChannel <- struct{}{}
default:
cancelChannel = make(chan struct{}, 1)
}
return true return true
} }
packet := buffer[:length] packet := buffer[:length]
@ -134,7 +141,6 @@ func addColdStartListener(
for !handleColdStartClient(clientPc, cancelChannel, ipsMap) { for !handleColdStartClient(clientPc, cancelChannel, ipsMap) {
} }
clientPc.Close() clientPc.Close()
cancelChannel <- struct{}{}
}() }()
return nil return nil
} }

View File

@ -316,7 +316,7 @@ func DNSExchange(
) (*dns.Msg, time.Duration, bool, error) { ) (*dns.Msg, time.Duration, bool, error) {
for { for {
cancelChannel := make(chan struct{}) cancelChannel := make(chan struct{})
channel := make(chan DNSExchangeResponse) channel := make(chan DNSExchangeResponse, 6)
var err error var err error
options := 0 options := 0
@ -325,32 +325,32 @@ func DNSExchange(
queryCopy := query.Copy() queryCopy := query.Copy()
queryCopy.Id += uint16(options) queryCopy.Id += uint16(options)
go func(query *dns.Msg, delay time.Duration) { go func(query *dns.Msg, delay time.Duration) {
option := _dnsExchange(proxy, proto, query, serverAddress, relay, 1500) time.Sleep(delay)
option := DNSExchangeResponse{err: errors.New("Canceled")}
select {
case <-cancelChannel:
default:
option = _dnsExchange(proxy, proto, query, serverAddress, relay, 1500)
}
option.fragmentsBlocked = false option.fragmentsBlocked = false
option.priority = 0 option.priority = 0
channel <- option channel <- option
time.Sleep(delay)
select {
case <-cancelChannel:
return
default:
}
}(queryCopy, time.Duration(200*tries)*time.Millisecond) }(queryCopy, time.Duration(200*tries)*time.Millisecond)
options++ options++
} }
queryCopy := query.Copy() queryCopy := query.Copy()
queryCopy.Id += uint16(options) queryCopy.Id += uint16(options)
go func(query *dns.Msg, delay time.Duration) { go func(query *dns.Msg, delay time.Duration) {
option := _dnsExchange(proxy, proto, query, serverAddress, relay, 480) time.Sleep(delay)
option := DNSExchangeResponse{err: errors.New("Canceled")}
select {
case <-cancelChannel:
default:
option = _dnsExchange(proxy, proto, query, serverAddress, relay, 480)
}
option.fragmentsBlocked = true option.fragmentsBlocked = true
option.priority = 1 option.priority = 1
channel <- option channel <- option
time.Sleep(delay)
select {
case <-cancelChannel:
return
default:
}
}(queryCopy, time.Duration(250*tries)*time.Millisecond) }(queryCopy, time.Duration(250*tries)*time.Millisecond)
options++ options++
} }