github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/multiplexer.go (about)

     1  package quic
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"sync"
     7  
     8  	"github.com/apernet/quic-go/internal/utils"
     9  )
    10  
    11  var (
    12  	connMuxerOnce sync.Once
    13  	connMuxer     multiplexer
    14  )
    15  
    16  type indexableConn interface{ LocalAddr() net.Addr }
    17  
    18  type multiplexer interface {
    19  	AddConn(conn indexableConn)
    20  	RemoveConn(indexableConn) error
    21  }
    22  
    23  // The connMultiplexer listens on multiple net.PacketConns and dispatches
    24  // incoming packets to the connection handler.
    25  type connMultiplexer struct {
    26  	mutex sync.Mutex
    27  
    28  	conns  map[string] /* LocalAddr().String() */ indexableConn
    29  	logger utils.Logger
    30  }
    31  
    32  var _ multiplexer = &connMultiplexer{}
    33  
    34  func getMultiplexer() multiplexer {
    35  	connMuxerOnce.Do(func() {
    36  		connMuxer = &connMultiplexer{
    37  			conns:  make(map[string]indexableConn),
    38  			logger: utils.DefaultLogger.WithPrefix("muxer"),
    39  		}
    40  	})
    41  	return connMuxer
    42  }
    43  
    44  func (m *connMultiplexer) index(addr net.Addr) string {
    45  	return addr.Network() + " " + addr.String()
    46  }
    47  
    48  func (m *connMultiplexer) AddConn(c indexableConn) {
    49  	m.mutex.Lock()
    50  	defer m.mutex.Unlock()
    51  
    52  	connIndex := m.index(c.LocalAddr())
    53  	p, ok := m.conns[connIndex]
    54  	if ok {
    55  		// Panics if we're already listening on this connection.
    56  		// This is a safeguard because we're introducing a breaking API change, see
    57  		// https://github.com/apernet/quic-go/issues/3727 for details.
    58  		// We'll remove this at a later time, when most users of the library have made the switch.
    59  		panic("connection already exists") // TODO: write a nice message
    60  	}
    61  	m.conns[connIndex] = p
    62  }
    63  
    64  func (m *connMultiplexer) RemoveConn(c indexableConn) error {
    65  	m.mutex.Lock()
    66  	defer m.mutex.Unlock()
    67  
    68  	connIndex := m.index(c.LocalAddr())
    69  	if _, ok := m.conns[connIndex]; !ok {
    70  		return fmt.Errorf("cannote remove connection, connection is unknown")
    71  	}
    72  
    73  	delete(m.conns, connIndex)
    74  	return nil
    75  }