Integrate BACKBEAT SDK and resolve KACHING license validation

Major integrations and fixes:
- Added BACKBEAT SDK integration for P2P operation timing
- Implemented beat-aware status tracking for distributed operations
- Added Docker secrets support for secure license management
- Resolved KACHING license validation via HTTPS/TLS
- Updated docker-compose configuration for clean stack deployment
- Disabled rollback policies to prevent deployment failures
- Added license credential storage (CHORUS-DEV-MULTI-001)

Technical improvements:
- BACKBEAT P2P operation tracking with phase management
- Enhanced configuration system with file-based secrets
- Improved error handling for license validation
- Clean separation of KACHING and CHORUS deployment stacks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-09-06 07:56:26 +10:00
parent 543ab216f9
commit 9bdcbe0447
4730 changed files with 1480093 additions and 1916 deletions

View File

@@ -0,0 +1,91 @@
package libp2pquic
import (
"context"
ic "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
tpt "github.com/libp2p/go-libp2p/core/transport"
ma "github.com/multiformats/go-multiaddr"
"github.com/quic-go/quic-go"
)
type conn struct {
quicConn quic.Connection
transport *transport
scope network.ConnManagementScope
localPeer peer.ID
localMultiaddr ma.Multiaddr
remotePeerID peer.ID
remotePubKey ic.PubKey
remoteMultiaddr ma.Multiaddr
}
var _ tpt.CapableConn = &conn{}
// Close closes the connection.
// It must be called even if the peer closed the connection in order for
// garbage collection to properly work in this package.
func (c *conn) Close() error {
return c.closeWithError(0, "")
}
func (c *conn) closeWithError(errCode quic.ApplicationErrorCode, errString string) error {
c.transport.removeConn(c.quicConn)
err := c.quicConn.CloseWithError(errCode, errString)
c.scope.Done()
return err
}
// IsClosed returns whether a connection is fully closed.
func (c *conn) IsClosed() bool {
return c.quicConn.Context().Err() != nil
}
func (c *conn) allowWindowIncrease(size uint64) bool {
return c.scope.ReserveMemory(int(size), network.ReservationPriorityMedium) == nil
}
// OpenStream creates a new stream.
func (c *conn) OpenStream(ctx context.Context) (network.MuxedStream, error) {
qstr, err := c.quicConn.OpenStreamSync(ctx)
return &stream{Stream: qstr}, err
}
// AcceptStream accepts a stream opened by the other side.
func (c *conn) AcceptStream() (network.MuxedStream, error) {
qstr, err := c.quicConn.AcceptStream(context.Background())
return &stream{Stream: qstr}, err
}
// LocalPeer returns our peer ID
func (c *conn) LocalPeer() peer.ID { return c.localPeer }
// RemotePeer returns the peer ID of the remote peer.
func (c *conn) RemotePeer() peer.ID { return c.remotePeerID }
// RemotePublicKey returns the public key of the remote peer.
func (c *conn) RemotePublicKey() ic.PubKey { return c.remotePubKey }
// LocalMultiaddr returns the local Multiaddr associated
func (c *conn) LocalMultiaddr() ma.Multiaddr { return c.localMultiaddr }
// RemoteMultiaddr returns the remote Multiaddr associated
func (c *conn) RemoteMultiaddr() ma.Multiaddr { return c.remoteMultiaddr }
func (c *conn) Transport() tpt.Transport { return c.transport }
func (c *conn) Scope() network.ConnScope { return c.scope }
// ConnState is the state of security connection.
func (c *conn) ConnState() network.ConnectionState {
t := "quic-v1"
if _, err := c.LocalMultiaddr().ValueForProtocol(ma.P_QUIC); err == nil {
t = "quic"
}
return network.ConnectionState{Transport: t}
}

View File

@@ -0,0 +1,147 @@
package libp2pquic
import (
"context"
"errors"
"net"
ic "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
tpt "github.com/libp2p/go-libp2p/core/transport"
p2ptls "github.com/libp2p/go-libp2p/p2p/security/tls"
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
ma "github.com/multiformats/go-multiaddr"
"github.com/quic-go/quic-go"
)
// A listener listens for QUIC connections.
type listener struct {
reuseListener quicreuse.Listener
transport *transport
rcmgr network.ResourceManager
privKey ic.PrivKey
localPeer peer.ID
localMultiaddrs map[quic.VersionNumber]ma.Multiaddr
}
func newListener(ln quicreuse.Listener, t *transport, localPeer peer.ID, key ic.PrivKey, rcmgr network.ResourceManager) (listener, error) {
localMultiaddrs := make(map[quic.VersionNumber]ma.Multiaddr)
for _, addr := range ln.Multiaddrs() {
if _, err := addr.ValueForProtocol(ma.P_QUIC_V1); err == nil {
localMultiaddrs[quic.Version1] = addr
}
}
return listener{
reuseListener: ln,
transport: t,
rcmgr: rcmgr,
privKey: key,
localPeer: localPeer,
localMultiaddrs: localMultiaddrs,
}, nil
}
// Accept accepts new connections.
func (l *listener) Accept() (tpt.CapableConn, error) {
for {
qconn, err := l.reuseListener.Accept(context.Background())
if err != nil {
return nil, err
}
c, err := l.setupConn(qconn)
if err != nil {
continue
}
l.transport.addConn(qconn, c)
if l.transport.gater != nil && !(l.transport.gater.InterceptAccept(c) && l.transport.gater.InterceptSecured(network.DirInbound, c.remotePeerID, c)) {
c.closeWithError(errorCodeConnectionGating, "connection gated")
continue
}
// return through active hole punching if any
key := holePunchKey{addr: qconn.RemoteAddr().String(), peer: c.remotePeerID}
var wasHolePunch bool
l.transport.holePunchingMx.Lock()
holePunch, ok := l.transport.holePunching[key]
if ok && !holePunch.fulfilled {
holePunch.connCh <- c
wasHolePunch = true
holePunch.fulfilled = true
}
l.transport.holePunchingMx.Unlock()
if wasHolePunch {
continue
}
return c, nil
}
}
func (l *listener) setupConn(qconn quic.Connection) (*conn, error) {
remoteMultiaddr, err := quicreuse.ToQuicMultiaddr(qconn.RemoteAddr(), qconn.ConnectionState().Version)
if err != nil {
return nil, err
}
connScope, err := l.rcmgr.OpenConnection(network.DirInbound, false, remoteMultiaddr)
if err != nil {
log.Debugw("resource manager blocked incoming connection", "addr", qconn.RemoteAddr(), "error", err)
return nil, err
}
c, err := l.setupConnWithScope(qconn, connScope, remoteMultiaddr)
if err != nil {
connScope.Done()
qconn.CloseWithError(1, "")
return nil, err
}
return c, nil
}
func (l *listener) setupConnWithScope(qconn quic.Connection, connScope network.ConnManagementScope, remoteMultiaddr ma.Multiaddr) (*conn, error) {
// The tls.Config used to establish this connection already verified the certificate chain.
// Since we don't have any way of knowing which tls.Config was used though,
// we have to re-determine the peer's identity here.
// Therefore, this is expected to never fail.
remotePubKey, err := p2ptls.PubKeyFromCertChain(qconn.ConnectionState().TLS.PeerCertificates)
if err != nil {
return nil, err
}
remotePeerID, err := peer.IDFromPublicKey(remotePubKey)
if err != nil {
return nil, err
}
if err := connScope.SetPeer(remotePeerID); err != nil {
log.Debugw("resource manager blocked incoming connection for peer", "peer", remotePeerID, "addr", qconn.RemoteAddr(), "error", err)
return nil, err
}
localMultiaddr, found := l.localMultiaddrs[qconn.ConnectionState().Version]
if !found {
return nil, errors.New("unknown QUIC version:" + qconn.ConnectionState().Version.String())
}
return &conn{
quicConn: qconn,
transport: l.transport,
scope: connScope,
localPeer: l.localPeer,
localMultiaddr: localMultiaddr,
remoteMultiaddr: remoteMultiaddr,
remotePeerID: remotePeerID,
remotePubKey: remotePubKey,
}, nil
}
// Close closes the listener.
func (l *listener) Close() error {
return l.reuseListener.Close()
}
// Addr returns the address of this listener.
func (l *listener) Addr() net.Addr {
return l.reuseListener.Addr()
}

View File

@@ -0,0 +1,55 @@
package libp2pquic
import (
"errors"
"github.com/libp2p/go-libp2p/core/network"
"github.com/quic-go/quic-go"
)
const (
reset quic.StreamErrorCode = 0
)
type stream struct {
quic.Stream
}
var _ network.MuxedStream = &stream{}
func (s *stream) Read(b []byte) (n int, err error) {
n, err = s.Stream.Read(b)
if err != nil && errors.Is(err, &quic.StreamError{}) {
err = network.ErrReset
}
return n, err
}
func (s *stream) Write(b []byte) (n int, err error) {
n, err = s.Stream.Write(b)
if err != nil && errors.Is(err, &quic.StreamError{}) {
err = network.ErrReset
}
return n, err
}
func (s *stream) Reset() error {
s.Stream.CancelRead(reset)
s.Stream.CancelWrite(reset)
return nil
}
func (s *stream) Close() error {
s.Stream.CancelRead(reset)
return s.Stream.Close()
}
func (s *stream) CloseRead() error {
s.Stream.CancelRead(reset)
return nil
}
func (s *stream) CloseWrite() error {
return s.Stream.Close()
}

View File

@@ -0,0 +1,399 @@
package libp2pquic
import (
"context"
"crypto/tls"
"errors"
"fmt"
"math/rand"
"net"
"sync"
"time"
"github.com/libp2p/go-libp2p/core/connmgr"
ic "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/pnet"
tpt "github.com/libp2p/go-libp2p/core/transport"
p2ptls "github.com/libp2p/go-libp2p/p2p/security/tls"
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
logging "github.com/ipfs/go-log/v2"
ma "github.com/multiformats/go-multiaddr"
mafmt "github.com/multiformats/go-multiaddr-fmt"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/quic-go/quic-go"
)
var log = logging.Logger("quic-transport")
var ErrHolePunching = errors.New("hole punching attempted; no active dial")
var HolePunchTimeout = 5 * time.Second
const errorCodeConnectionGating = 0x47415445 // GATE in ASCII
// The Transport implements the tpt.Transport interface for QUIC connections.
type transport struct {
privKey ic.PrivKey
localPeer peer.ID
identity *p2ptls.Identity
connManager *quicreuse.ConnManager
gater connmgr.ConnectionGater
rcmgr network.ResourceManager
holePunchingMx sync.Mutex
holePunching map[holePunchKey]*activeHolePunch
rndMx sync.Mutex
rnd rand.Rand
connMx sync.Mutex
conns map[quic.Connection]*conn
listenersMu sync.Mutex
// map of UDPAddr as string to a virtualListeners
listeners map[string][]*virtualListener
}
var _ tpt.Transport = &transport{}
type holePunchKey struct {
addr string
peer peer.ID
}
type activeHolePunch struct {
connCh chan tpt.CapableConn
fulfilled bool
}
// NewTransport creates a new QUIC transport
func NewTransport(key ic.PrivKey, connManager *quicreuse.ConnManager, psk pnet.PSK, gater connmgr.ConnectionGater, rcmgr network.ResourceManager) (tpt.Transport, error) {
if len(psk) > 0 {
log.Error("QUIC doesn't support private networks yet.")
return nil, errors.New("QUIC doesn't support private networks yet")
}
localPeer, err := peer.IDFromPrivateKey(key)
if err != nil {
return nil, err
}
identity, err := p2ptls.NewIdentity(key)
if err != nil {
return nil, err
}
if rcmgr == nil {
rcmgr = &network.NullResourceManager{}
}
return &transport{
privKey: key,
localPeer: localPeer,
identity: identity,
connManager: connManager,
gater: gater,
rcmgr: rcmgr,
conns: make(map[quic.Connection]*conn),
holePunching: make(map[holePunchKey]*activeHolePunch),
rnd: *rand.New(rand.NewSource(time.Now().UnixNano())),
listeners: make(map[string][]*virtualListener),
}, nil
}
// Dial dials a new QUIC connection
func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (_c tpt.CapableConn, _err error) {
if ok, isClient, _ := network.GetSimultaneousConnect(ctx); ok && !isClient {
return t.holePunch(ctx, raddr, p)
}
scope, err := t.rcmgr.OpenConnection(network.DirOutbound, false, raddr)
if err != nil {
log.Debugw("resource manager blocked outgoing connection", "peer", p, "addr", raddr, "error", err)
return nil, err
}
c, err := t.dialWithScope(ctx, raddr, p, scope)
if err != nil {
scope.Done()
return nil, err
}
return c, nil
}
func (t *transport) dialWithScope(ctx context.Context, raddr ma.Multiaddr, p peer.ID, scope network.ConnManagementScope) (tpt.CapableConn, error) {
if err := scope.SetPeer(p); err != nil {
log.Debugw("resource manager blocked outgoing connection for peer", "peer", p, "addr", raddr, "error", err)
return nil, err
}
tlsConf, keyCh := t.identity.ConfigForPeer(p)
pconn, err := t.connManager.DialQUIC(ctx, raddr, tlsConf, t.allowWindowIncrease)
if err != nil {
return nil, err
}
// Should be ready by this point, don't block.
var remotePubKey ic.PubKey
select {
case remotePubKey = <-keyCh:
default:
}
if remotePubKey == nil {
pconn.CloseWithError(1, "")
return nil, errors.New("p2p/transport/quic BUG: expected remote pub key to be set")
}
localMultiaddr, err := quicreuse.ToQuicMultiaddr(pconn.LocalAddr(), pconn.ConnectionState().Version)
if err != nil {
pconn.CloseWithError(1, "")
return nil, err
}
c := &conn{
quicConn: pconn,
transport: t,
scope: scope,
localPeer: t.localPeer,
localMultiaddr: localMultiaddr,
remotePubKey: remotePubKey,
remotePeerID: p,
remoteMultiaddr: raddr,
}
if t.gater != nil && !t.gater.InterceptSecured(network.DirOutbound, p, c) {
pconn.CloseWithError(errorCodeConnectionGating, "connection gated")
return nil, fmt.Errorf("secured connection gated")
}
t.addConn(pconn, c)
return c, nil
}
func (t *transport) addConn(conn quic.Connection, c *conn) {
t.connMx.Lock()
t.conns[conn] = c
t.connMx.Unlock()
}
func (t *transport) removeConn(conn quic.Connection) {
t.connMx.Lock()
delete(t.conns, conn)
t.connMx.Unlock()
}
func (t *transport) holePunch(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.CapableConn, error) {
network, saddr, err := manet.DialArgs(raddr)
if err != nil {
return nil, err
}
addr, err := net.ResolveUDPAddr(network, saddr)
if err != nil {
return nil, err
}
tr, err := t.connManager.TransportForDial(network, addr)
if err != nil {
return nil, err
}
defer tr.DecreaseCount()
ctx, cancel := context.WithTimeout(ctx, HolePunchTimeout)
defer cancel()
key := holePunchKey{addr: addr.String(), peer: p}
t.holePunchingMx.Lock()
if _, ok := t.holePunching[key]; ok {
t.holePunchingMx.Unlock()
return nil, fmt.Errorf("already punching hole for %s", addr)
}
connCh := make(chan tpt.CapableConn, 1)
t.holePunching[key] = &activeHolePunch{connCh: connCh}
t.holePunchingMx.Unlock()
var timer *time.Timer
defer func() {
if timer != nil {
timer.Stop()
}
}()
payload := make([]byte, 64)
var punchErr error
loop:
for i := 0; ; i++ {
t.rndMx.Lock()
_, err := t.rnd.Read(payload)
t.rndMx.Unlock()
if err != nil {
punchErr = err
break
}
if _, err := tr.WriteTo(payload, addr); err != nil {
punchErr = err
break
}
maxSleep := 10 * (i + 1) * (i + 1) // in ms
if maxSleep > 200 {
maxSleep = 200
}
d := 10*time.Millisecond + time.Duration(rand.Intn(maxSleep))*time.Millisecond
if timer == nil {
timer = time.NewTimer(d)
} else {
timer.Reset(d)
}
select {
case c := <-connCh:
t.holePunchingMx.Lock()
delete(t.holePunching, key)
t.holePunchingMx.Unlock()
return c, nil
case <-timer.C:
case <-ctx.Done():
punchErr = ErrHolePunching
break loop
}
}
// we only arrive here if punchErr != nil
t.holePunchingMx.Lock()
defer func() {
delete(t.holePunching, key)
t.holePunchingMx.Unlock()
}()
select {
case c := <-t.holePunching[key].connCh:
return c, nil
default:
return nil, punchErr
}
}
// Don't use mafmt.QUIC as we don't want to dial DNS addresses. Just /ip{4,6}/udp/quic-v1
var dialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Base(ma.P_QUIC_V1))
// CanDial determines if we can dial to an address
func (t *transport) CanDial(addr ma.Multiaddr) bool {
return dialMatcher.Matches(addr)
}
// Listen listens for new QUIC connections on the passed multiaddr.
func (t *transport) Listen(addr ma.Multiaddr) (tpt.Listener, error) {
var tlsConf tls.Config
tlsConf.GetConfigForClient = func(_ *tls.ClientHelloInfo) (*tls.Config, error) {
// return a tls.Config that verifies the peer's certificate chain.
// Note that since we have no way of associating an incoming QUIC connection with
// the peer ID calculated here, we don't actually receive the peer's public key
// from the key chan.
conf, _ := t.identity.ConfigForPeer("")
return conf, nil
}
tlsConf.NextProtos = []string{"libp2p"}
udpAddr, version, err := quicreuse.FromQuicMultiaddr(addr)
if err != nil {
return nil, err
}
t.listenersMu.Lock()
defer t.listenersMu.Unlock()
listeners := t.listeners[udpAddr.String()]
var underlyingListener *listener
var acceptRunner *acceptLoopRunner
if len(listeners) != 0 {
// We already have an underlying listener, let's use it
underlyingListener = listeners[0].listener
acceptRunner = listeners[0].acceptRunnner
// Make sure our underlying listener is listening on the specified QUIC version
if _, ok := underlyingListener.localMultiaddrs[version]; !ok {
return nil, fmt.Errorf("can't listen on quic version %v, underlying listener doesn't support it", version)
}
} else {
ln, err := t.connManager.ListenQUIC(addr, &tlsConf, t.allowWindowIncrease)
if err != nil {
return nil, err
}
l, err := newListener(ln, t, t.localPeer, t.privKey, t.rcmgr)
if err != nil {
_ = ln.Close()
return nil, err
}
underlyingListener = &l
acceptRunner = &acceptLoopRunner{
acceptSem: make(chan struct{}, 1),
muxer: make(map[quic.VersionNumber]chan acceptVal),
}
}
l := &virtualListener{
listener: underlyingListener,
version: version,
udpAddr: udpAddr.String(),
t: t,
acceptRunnner: acceptRunner,
acceptChan: acceptRunner.AcceptForVersion(version),
}
listeners = append(listeners, l)
t.listeners[udpAddr.String()] = listeners
return l, nil
}
func (t *transport) allowWindowIncrease(conn quic.Connection, size uint64) bool {
// If the QUIC connection tries to increase the window before we've inserted it
// into our connections map (which we do right after dialing / accepting it),
// we have no way to account for that memory. This should be very rare.
// Block this attempt. The connection can request more memory later.
t.connMx.Lock()
c, ok := t.conns[conn]
t.connMx.Unlock()
if !ok {
return false
}
return c.allowWindowIncrease(size)
}
// Proxy returns true if this transport proxies.
func (t *transport) Proxy() bool {
return false
}
// Protocols returns the set of protocols handled by this transport.
func (t *transport) Protocols() []int {
return t.connManager.Protocols()
}
func (t *transport) String() string {
return "QUIC"
}
func (t *transport) Close() error {
return nil
}
func (t *transport) CloseVirtualListener(l *virtualListener) error {
t.listenersMu.Lock()
defer t.listenersMu.Unlock()
var err error
listeners := t.listeners[l.udpAddr]
if len(listeners) == 1 {
// This is the last virtual listener here, so we can close the underlying listener
err = l.listener.Close()
delete(t.listeners, l.udpAddr)
return err
}
for i := 0; i < len(listeners); i++ {
// Swap remove
if l == listeners[i] {
listeners[i] = listeners[len(listeners)-1]
listeners = listeners[:len(listeners)-1]
t.listeners[l.udpAddr] = listeners
break
}
}
return nil
}

View File

@@ -0,0 +1,175 @@
package libp2pquic
import (
"sync"
tpt "github.com/libp2p/go-libp2p/core/transport"
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
ma "github.com/multiformats/go-multiaddr"
"github.com/quic-go/quic-go"
)
const acceptBufferPerVersion = 4
// virtualListener is a listener that exposes a single multiaddr but uses another listener under the hood
type virtualListener struct {
*listener
udpAddr string
version quic.VersionNumber
t *transport
acceptRunnner *acceptLoopRunner
acceptChan chan acceptVal
}
var _ tpt.Listener = &virtualListener{}
func (l *virtualListener) Multiaddr() ma.Multiaddr {
return l.listener.localMultiaddrs[l.version]
}
func (l *virtualListener) Close() error {
l.acceptRunnner.RmAcceptForVersion(l.version, tpt.ErrListenerClosed)
return l.t.CloseVirtualListener(l)
}
func (l *virtualListener) Accept() (tpt.CapableConn, error) {
return l.acceptRunnner.Accept(l.listener, l.version, l.acceptChan)
}
type acceptVal struct {
conn tpt.CapableConn
err error
}
type acceptLoopRunner struct {
acceptSem chan struct{}
muxerMu sync.Mutex
muxer map[quic.VersionNumber]chan acceptVal
muxerClosed bool
}
func (r *acceptLoopRunner) AcceptForVersion(v quic.VersionNumber) chan acceptVal {
r.muxerMu.Lock()
defer r.muxerMu.Unlock()
ch := make(chan acceptVal, acceptBufferPerVersion)
if _, ok := r.muxer[v]; ok {
panic("unexpected chan already found in accept muxer")
}
r.muxer[v] = ch
return ch
}
func (r *acceptLoopRunner) RmAcceptForVersion(v quic.VersionNumber, err error) {
r.muxerMu.Lock()
defer r.muxerMu.Unlock()
if r.muxerClosed {
// Already closed, all versions are removed
return
}
ch, ok := r.muxer[v]
if !ok {
panic("expected chan in accept muxer")
}
ch <- acceptVal{err: err}
delete(r.muxer, v)
}
func (r *acceptLoopRunner) sendErrAndClose(err error) {
r.muxerMu.Lock()
defer r.muxerMu.Unlock()
r.muxerClosed = true
for k, ch := range r.muxer {
select {
case ch <- acceptVal{err: err}:
default:
}
delete(r.muxer, k)
close(ch)
}
}
// innerAccept is the inner logic of the Accept loop. Assume caller holds the
// acceptSemaphore. May return both a nil conn and nil error if it didn't find a
// conn with the expected version
func (r *acceptLoopRunner) innerAccept(l *listener, expectedVersion quic.VersionNumber, bufferedConnChan chan acceptVal) (tpt.CapableConn, error) {
select {
// Check if we have a buffered connection first from an earlier Accept call
case v, ok := <-bufferedConnChan:
if !ok {
return nil, tpt.ErrListenerClosed
}
return v.conn, v.err
default:
}
conn, err := l.Accept()
if err != nil {
r.sendErrAndClose(err)
return nil, err
}
_, version, err := quicreuse.FromQuicMultiaddr(conn.RemoteMultiaddr())
if err != nil {
r.sendErrAndClose(err)
return nil, err
}
if version == expectedVersion {
return conn, nil
}
// This wasn't the version we were expecting, lets queue it up for a
// future Accept call with a different version
r.muxerMu.Lock()
ch, ok := r.muxer[version]
r.muxerMu.Unlock()
if !ok {
// Nothing to handle this connection version. Close it
conn.Close()
return nil, nil
}
// Non blocking
select {
case ch <- acceptVal{conn: conn}:
default:
// accept queue filled up, drop the connection
conn.Close()
log.Warn("Accept queue filled. Dropping connection.")
}
return nil, nil
}
func (r *acceptLoopRunner) Accept(l *listener, expectedVersion quic.VersionNumber, bufferedConnChan chan acceptVal) (tpt.CapableConn, error) {
for {
var conn tpt.CapableConn
var err error
select {
case r.acceptSem <- struct{}{}:
conn, err = r.innerAccept(l, expectedVersion, bufferedConnChan)
<-r.acceptSem
if conn == nil && err == nil {
// Didn't find a conn for the expected version and there was no error, lets try again
continue
}
case v, ok := <-bufferedConnChan:
if !ok {
return nil, tpt.ErrListenerClosed
}
conn = v.conn
err = v.err
}
return conn, err
}
}