github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/quic/gquic-go/multiplexer.go (about)

     1  package gquic
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"sync"
     7  
     8  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic/gquic-go/internal/utils"
     9  )
    10  
    11  var (
    12  	connMuxerOnce sync.Once
    13  	connMuxer     multiplexer
    14  )
    15  
    16  type multiplexer interface {
    17  	AddConn(net.PacketConn, int) (packetHandlerManager, error)
    18  }
    19  
    20  type connManager struct {
    21  	connIDLen int
    22  	manager   packetHandlerManager
    23  }
    24  
    25  // The connMultiplexer listens on multiple net.PacketConns and dispatches
    26  // incoming packets to the session handler.
    27  type connMultiplexer struct {
    28  	mutex sync.Mutex
    29  
    30  	conns                   map[net.PacketConn]connManager
    31  	newPacketHandlerManager func(net.PacketConn, int, utils.Logger) packetHandlerManager // so it can be replaced in the tests
    32  
    33  	logger utils.Logger
    34  }
    35  
    36  var _ multiplexer = &connMultiplexer{}
    37  
    38  func getMultiplexer() multiplexer {
    39  	connMuxerOnce.Do(func() {
    40  		connMuxer = &connMultiplexer{
    41  			conns:                   make(map[net.PacketConn]connManager),
    42  			logger:                  utils.DefaultLogger.WithPrefix("muxer"),
    43  			newPacketHandlerManager: newPacketHandlerMap,
    44  		}
    45  	})
    46  	return connMuxer
    47  }
    48  
    49  func (m *connMultiplexer) AddConn(c net.PacketConn, connIDLen int) (packetHandlerManager, error) {
    50  	m.mutex.Lock()
    51  	defer m.mutex.Unlock()
    52  
    53  	p, ok := m.conns[c]
    54  	if !ok {
    55  		manager := m.newPacketHandlerManager(c, connIDLen, m.logger)
    56  		p = connManager{connIDLen: connIDLen, manager: manager}
    57  		m.conns[c] = p
    58  	}
    59  	if p.connIDLen != connIDLen {
    60  		return nil, fmt.Errorf("cannot use %d byte connection IDs on a connection that is already using %d byte connction IDs", connIDLen, p.connIDLen)
    61  	}
    62  	return p.manager, nil
    63  }