mirror of
https://github.com/go-i2p/go-meta-listener.git
synced 2025-06-07 10:01:39 -04:00
90 lines
1.9 KiB
Go
90 lines
1.9 KiB
Go
package meta
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
)
|
|
|
|
// Accept implements the net.Listener Accept method.
|
|
// It returns the next connection from any of the managed listeners.
|
|
func (ml *MetaListener) Accept() (net.Conn, error) {
|
|
// Check if already closed before entering the select loop
|
|
ml.mu.RLock()
|
|
if ml.isClosed {
|
|
ml.mu.RUnlock()
|
|
return nil, ErrListenerClosed
|
|
}
|
|
ml.mu.RUnlock()
|
|
|
|
for {
|
|
select {
|
|
case result, ok := <-ml.connCh:
|
|
if !ok {
|
|
return nil, ErrListenerClosed
|
|
}
|
|
// Access RemoteAddr() directly on the connection
|
|
return result, nil
|
|
case <-ml.closeCh:
|
|
// Double-check the closed state under lock to ensure consistency
|
|
closed := ml.isClosed
|
|
if closed {
|
|
return nil, ErrListenerClosed
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close implements the net.Listener Close method.
|
|
// It closes all managed listeners and releases resources.
|
|
func (ml *MetaListener) Close() error {
|
|
ml.mu.Lock()
|
|
|
|
if ml.isClosed {
|
|
ml.mu.Unlock()
|
|
return nil
|
|
}
|
|
|
|
log.Printf("Closing MetaListener with %d listeners", len(ml.listeners))
|
|
ml.isClosed = true
|
|
|
|
// Signal all goroutines to stop
|
|
close(ml.closeCh)
|
|
|
|
// Close all listeners
|
|
var errs []error
|
|
for id, listener := range ml.listeners {
|
|
if err := listener.Close(); err != nil {
|
|
log.Printf("Error closing %s listener: %v", id, err)
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
|
|
ml.mu.Unlock()
|
|
|
|
// Wait for all listener goroutines to exit
|
|
ml.listenerWg.Wait()
|
|
log.Printf("All listener goroutines have exited")
|
|
|
|
// Return combined errors if any
|
|
if len(errs) > 0 {
|
|
return fmt.Errorf("errors closing listeners: %v", errs)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Addr implements the net.Listener Addr method.
|
|
// It returns a MetaAddr representing all managed listeners.
|
|
func (ml *MetaListener) Addr() net.Addr {
|
|
ml.mu.RLock()
|
|
defer ml.mu.RUnlock()
|
|
|
|
addresses := make([]net.Addr, 0, len(ml.listeners))
|
|
for _, listener := range ml.listeners {
|
|
addresses = append(addresses, listener.Addr())
|
|
}
|
|
|
|
return &MetaAddr{addresses: addresses}
|
|
}
|