github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/oovendor/quic-go/multiplexer.go (about)

     1  package quic
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net"
     7  	"sync"
     8  
     9  	"github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/internal/utils"
    10  	"github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/logging"
    11  )
    12  
    13  var (
    14  	connMuxerOnce sync.Once
    15  	connMuxer     multiplexer
    16  )
    17  
    18  type indexableConn interface {
    19  	LocalAddr() net.Addr
    20  }
    21  
    22  type multiplexer interface {
    23  	AddConn(c net.PacketConn, connIDLen int, statelessResetKey []byte, tracer logging.Tracer) (packetHandlerManager, error)
    24  	RemoveConn(indexableConn) error
    25  }
    26  
    27  type connManager struct {
    28  	connIDLen         int
    29  	statelessResetKey []byte
    30  	tracer            logging.Tracer
    31  	manager           packetHandlerManager
    32  }
    33  
    34  // The connMultiplexer listens on multiple net.PacketConns and dispatches
    35  // incoming packets to the session handler.
    36  type connMultiplexer struct {
    37  	mutex sync.Mutex
    38  
    39  	conns                   map[string] /* LocalAddr().String() */ connManager
    40  	newPacketHandlerManager func(net.PacketConn, int, []byte, logging.Tracer, utils.Logger) (packetHandlerManager, error) // so it can be replaced in the tests
    41  
    42  	logger utils.Logger
    43  }
    44  
    45  var _ multiplexer = &connMultiplexer{}
    46  
    47  func getMultiplexer() multiplexer {
    48  	connMuxerOnce.Do(func() {
    49  		connMuxer = &connMultiplexer{
    50  			conns:                   make(map[string]connManager),
    51  			logger:                  utils.DefaultLogger.WithPrefix("muxer"),
    52  			newPacketHandlerManager: newPacketHandlerMap,
    53  		}
    54  	})
    55  	return connMuxer
    56  }
    57  
    58  func (m *connMultiplexer) AddConn(
    59  	c net.PacketConn,
    60  	connIDLen int,
    61  	statelessResetKey []byte,
    62  	tracer logging.Tracer,
    63  ) (packetHandlerManager, error) {
    64  	m.mutex.Lock()
    65  	defer m.mutex.Unlock()
    66  
    67  	addr := c.LocalAddr()
    68  	connIndex := addr.Network() + " " + addr.String()
    69  	p, ok := m.conns[connIndex]
    70  	if !ok {
    71  		manager, err := m.newPacketHandlerManager(c, connIDLen, statelessResetKey, tracer, m.logger)
    72  		if err != nil {
    73  			return nil, err
    74  		}
    75  		p = connManager{
    76  			connIDLen:         connIDLen,
    77  			statelessResetKey: statelessResetKey,
    78  			manager:           manager,
    79  			tracer:            tracer,
    80  		}
    81  		m.conns[connIndex] = p
    82  	} else {
    83  		if p.connIDLen != connIDLen {
    84  			return nil, fmt.Errorf("cannot use %d byte connection IDs on a connection that is already using %d byte connction IDs", connIDLen, p.connIDLen)
    85  		}
    86  		if statelessResetKey != nil && !bytes.Equal(p.statelessResetKey, statelessResetKey) {
    87  			return nil, fmt.Errorf("cannot use different stateless reset keys on the same packet conn")
    88  		}
    89  		if tracer != p.tracer {
    90  			return nil, fmt.Errorf("cannot use different tracers on the same packet conn")
    91  		}
    92  	}
    93  	return p.manager, nil
    94  }
    95  
    96  func (m *connMultiplexer) RemoveConn(c indexableConn) error {
    97  	m.mutex.Lock()
    98  	defer m.mutex.Unlock()
    99  
   100  	connIndex := c.LocalAddr().Network() + " " + c.LocalAddr().String()
   101  	if _, ok := m.conns[connIndex]; !ok {
   102  		return fmt.Errorf("cannote remove connection, connection is unknown")
   103  	}
   104  
   105  	delete(m.conns, connIndex)
   106  	return nil
   107  }