Fix a logical race that wasn't detectable by -race -- we were closing a connection that was already reestablished.

This commit is contained in:
Eugene Bujak 2018-11-28 17:55:01 +03:00
parent 4eb122e973
commit e4a3564706
2 changed files with 48 additions and 10 deletions

View File

@ -32,6 +32,46 @@ type Server struct {
ServerConfig ServerConfig
} }
// uncomment this block to have tracing of locks
/*
func (s *Server) Lock() {
pc := make([]uintptr, 10) // at least 1 entry needed
runtime.Callers(2, pc)
f := runtime.FuncForPC(pc[0])
file, line := f.FileLine(pc[0])
fmt.Fprintf(os.Stderr, "%s:%d %s() -> Lock() -> in progress\n", path.Base(file), line, path.Base(f.Name()))
s.RWMutex.Lock()
fmt.Fprintf(os.Stderr, "%s:%d %s() -> Lock() -> done\n", path.Base(file), line, path.Base(f.Name()))
}
func (s *Server) RLock() {
pc := make([]uintptr, 10) // at least 1 entry needed
runtime.Callers(2, pc)
f := runtime.FuncForPC(pc[0])
file, line := f.FileLine(pc[0])
fmt.Fprintf(os.Stderr, "%s:%d %s() -> RLock() -> in progress\n", path.Base(file), line, path.Base(f.Name()))
s.RWMutex.RLock()
fmt.Fprintf(os.Stderr, "%s:%d %s() -> RLock() -> done\n", path.Base(file), line, path.Base(f.Name()))
}
func (s *Server) Unlock() {
pc := make([]uintptr, 10) // at least 1 entry needed
runtime.Callers(2, pc)
f := runtime.FuncForPC(pc[0])
file, line := f.FileLine(pc[0])
fmt.Fprintf(os.Stderr, "%s:%d %s() -> Unlock() -> in progress\n", path.Base(file), line, path.Base(f.Name()))
s.RWMutex.Unlock()
fmt.Fprintf(os.Stderr, "%s:%d %s() -> Unlock() -> done\n", path.Base(file), line, path.Base(f.Name()))
}
func (s *Server) RUnlock() {
pc := make([]uintptr, 10) // at least 1 entry needed
runtime.Callers(2, pc)
f := runtime.FuncForPC(pc[0])
file, line := f.FileLine(pc[0])
fmt.Fprintf(os.Stderr, "%s:%d %s() -> RUnlock() -> in progress\n", path.Base(file), line, path.Base(f.Name()))
s.RWMutex.RUnlock()
fmt.Fprintf(os.Stderr, "%s:%d %s() -> RUnlock() -> done\n", path.Base(file), line, path.Base(f.Name()))
}
*/
// The zero ServerConfig is empty and ready for use. // The zero ServerConfig is empty and ready for use.
type ServerConfig struct { type ServerConfig struct {
UDPListenAddr *net.UDPAddr // if nil, then default is is used (port 53 on *) UDPListenAddr *net.UDPAddr // if nil, then default is is used (port 53 on *)
@ -97,16 +137,7 @@ func (s *Server) packetLoop() {
if err != nil { if err != nil {
if isConnClosed(err) { if isConnClosed(err) {
log.Printf("ReadFrom() returned because we're reading from a closed connection, exiting loop") log.Printf("ReadFrom() returned because we're reading from a closed connection, exiting loop")
var err error // don't try to nullify s.udpListen here, because s.udpListen could be already re-bound to listen
s.Lock()
if s.udpListen != nil {
err = s.udpListen.Close()
s.udpListen = nil
}
s.Unlock()
if err != nil {
log.Printf("Failed to close udp connection while exiting loop: %s", err)
}
break break
} }
log.Printf("Got error when reading from udp listen: %s", err) log.Printf("Got error when reading from udp listen: %s", err)

View File

@ -28,6 +28,13 @@ func isConnClosed(err error) bool {
// --------------------- // ---------------------
// debug logging helpers // debug logging helpers
// --------------------- // ---------------------
func _Func() string {
pc := make([]uintptr, 10) // at least 1 entry needed
runtime.Callers(2, pc)
f := runtime.FuncForPC(pc[0])
return path.Base(f.Name())
}
func trace(format string, args ...interface{}) { func trace(format string, args ...interface{}) {
pc := make([]uintptr, 10) // at least 1 entry needed pc := make([]uintptr, 10) // at least 1 entry needed
runtime.Callers(2, pc) runtime.Callers(2, pc)