mirror of
https://github.com/go-i2p/go-meta-listener.git
synced 2025-06-08 17:21:46 -04:00
Split up metalistener, fix deadlock in accept routine, I think
This commit is contained in:
68
handler.go
Normal file
68
handler.go
Normal file
@ -0,0 +1,68 @@
|
||||
package meta
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// handleListener runs in a separate goroutine for each added listener
|
||||
// and forwards accepted connections to the connCh channel.
|
||||
func (ml *MetaListener) handleListener(id string, listener net.Listener) {
|
||||
defer func() {
|
||||
log.Printf("Listener goroutine for %s exiting", id)
|
||||
ml.listenerWg.Done()
|
||||
}()
|
||||
|
||||
for {
|
||||
// First check if the MetaListener is closed
|
||||
select {
|
||||
case <-ml.closeCh:
|
||||
log.Printf("MetaListener closed, stopping %s listener", id)
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
// Set a deadline for Accept to prevent blocking indefinitely
|
||||
if deadline, ok := listener.(interface{ SetDeadline(time.Time) error }); ok {
|
||||
deadline.SetDeadline(time.Now().Add(1 * time.Second))
|
||||
}
|
||||
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
// Check if this is a timeout error (which we expect due to our deadline)
|
||||
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if this is any other temporary error
|
||||
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
|
||||
log.Printf("Temporary error in %s listener: %v, retrying in 100ms", id, err)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("Permanent error in %s listener: %v, stopping", id, err)
|
||||
ml.mu.Lock()
|
||||
delete(ml.listeners, id)
|
||||
ml.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// If we reach here, we have a valid connection
|
||||
log.Printf("Listener %s accepted connection from %s", id, conn.RemoteAddr())
|
||||
|
||||
// Try to forward the connection, but don't block indefinitely
|
||||
select {
|
||||
case ml.connCh <- ConnResult{Conn: conn, src: id}:
|
||||
log.Printf("Connection from %s successfully forwarded via %s", conn.RemoteAddr(), id)
|
||||
case <-ml.closeCh:
|
||||
log.Printf("MetaListener closing while forwarding connection, closing connection")
|
||||
conn.Close()
|
||||
return
|
||||
case <-time.After(5 * time.Second):
|
||||
// If we can't forward within 5 seconds, something is seriously wrong
|
||||
log.Printf("WARNING: Connection forwarding timed out, closing connection from %s", conn.RemoteAddr())
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user