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,23 @@
package quicreuse
import (
"net"
"time"
"github.com/quic-go/quic-go"
)
var quicConfig = &quic.Config{
MaxIncomingStreams: 256,
MaxIncomingUniStreams: 5, // allow some unidirectional streams, in case we speak WebTransport
MaxStreamReceiveWindow: 10 * (1 << 20), // 10 MB
MaxConnectionReceiveWindow: 15 * (1 << 20), // 15 MB
RequireAddressValidation: func(net.Addr) bool {
// TODO(#1535): require source address validation when under load
return false
},
KeepAlivePeriod: 15 * time.Second,
Versions: []quic.VersionNumber{quic.Version1},
// We don't use datagrams (yet), but this is necessary for WebTransport
EnableDatagrams: true,
}

View File

@@ -0,0 +1,224 @@
package quicreuse
import (
"context"
"crypto/tls"
"errors"
"net"
"sync"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/quic-go/quic-go"
quiclogging "github.com/quic-go/quic-go/logging"
)
type ConnManager struct {
reuseUDP4 *reuse
reuseUDP6 *reuse
enableReuseport bool
enableMetrics bool
serverConfig *quic.Config
clientConfig *quic.Config
quicListenersMu sync.Mutex
quicListeners map[string]quicListenerEntry
srk quic.StatelessResetKey
tokenKey quic.TokenGeneratorKey
}
type quicListenerEntry struct {
refCount int
ln *quicListener
}
func NewConnManager(statelessResetKey quic.StatelessResetKey, tokenKey quic.TokenGeneratorKey, opts ...Option) (*ConnManager, error) {
cm := &ConnManager{
enableReuseport: true,
quicListeners: make(map[string]quicListenerEntry),
srk: statelessResetKey,
tokenKey: tokenKey,
}
for _, o := range opts {
if err := o(cm); err != nil {
return nil, err
}
}
quicConf := quicConfig.Clone()
quicConf.Tracer = func(ctx context.Context, p quiclogging.Perspective, ci quic.ConnectionID) *quiclogging.ConnectionTracer {
var tracer *quiclogging.ConnectionTracer
if qlogTracerDir != "" {
tracer = qloggerForDir(qlogTracerDir, p, ci)
}
return tracer
}
serverConfig := quicConf.Clone()
cm.clientConfig = quicConf
cm.serverConfig = serverConfig
if cm.enableReuseport {
cm.reuseUDP4 = newReuse(&statelessResetKey, &tokenKey)
cm.reuseUDP6 = newReuse(&statelessResetKey, &tokenKey)
}
return cm, nil
}
func (c *ConnManager) getReuse(network string) (*reuse, error) {
switch network {
case "udp4":
return c.reuseUDP4, nil
case "udp6":
return c.reuseUDP6, nil
default:
return nil, errors.New("invalid network: must be either udp4 or udp6")
}
}
func (c *ConnManager) ListenQUIC(addr ma.Multiaddr, tlsConf *tls.Config, allowWindowIncrease func(conn quic.Connection, delta uint64) bool) (Listener, error) {
netw, host, err := manet.DialArgs(addr)
if err != nil {
return nil, err
}
laddr, err := net.ResolveUDPAddr(netw, host)
if err != nil {
return nil, err
}
c.quicListenersMu.Lock()
defer c.quicListenersMu.Unlock()
key := laddr.String()
entry, ok := c.quicListeners[key]
if !ok {
tr, err := c.transportForListen(netw, laddr)
if err != nil {
return nil, err
}
ln, err := newQuicListener(tr, c.serverConfig)
if err != nil {
return nil, err
}
key = tr.LocalAddr().String()
entry = quicListenerEntry{ln: ln}
}
l, err := entry.ln.Add(tlsConf, allowWindowIncrease, func() { c.onListenerClosed(key) })
if err != nil {
if entry.refCount <= 0 {
entry.ln.Close()
}
return nil, err
}
entry.refCount++
c.quicListeners[key] = entry
return l, nil
}
func (c *ConnManager) onListenerClosed(key string) {
c.quicListenersMu.Lock()
defer c.quicListenersMu.Unlock()
entry := c.quicListeners[key]
entry.refCount = entry.refCount - 1
if entry.refCount <= 0 {
delete(c.quicListeners, key)
entry.ln.Close()
} else {
c.quicListeners[key] = entry
}
}
func (c *ConnManager) transportForListen(network string, laddr *net.UDPAddr) (refCountedQuicTransport, error) {
if c.enableReuseport {
reuse, err := c.getReuse(network)
if err != nil {
return nil, err
}
return reuse.TransportForListen(network, laddr)
}
conn, err := net.ListenUDP(network, laddr)
if err != nil {
return nil, err
}
return &singleOwnerTransport{
packetConn: conn,
Transport: quic.Transport{
Conn: conn,
StatelessResetKey: &c.srk,
TokenGeneratorKey: &c.tokenKey,
},
}, nil
}
func (c *ConnManager) DialQUIC(ctx context.Context, raddr ma.Multiaddr, tlsConf *tls.Config, allowWindowIncrease func(conn quic.Connection, delta uint64) bool) (quic.Connection, error) {
naddr, v, err := FromQuicMultiaddr(raddr)
if err != nil {
return nil, err
}
netw, _, err := manet.DialArgs(raddr)
if err != nil {
return nil, err
}
quicConf := c.clientConfig.Clone()
quicConf.AllowConnectionWindowIncrease = allowWindowIncrease
if v == quic.Version1 {
// The endpoint has explicit support for QUIC v1, so we'll only use that version.
quicConf.Versions = []quic.VersionNumber{quic.Version1}
} else {
return nil, errors.New("unknown QUIC version")
}
tr, err := c.TransportForDial(netw, naddr)
if err != nil {
return nil, err
}
conn, err := tr.Dial(ctx, naddr, tlsConf, quicConf)
if err != nil {
tr.DecreaseCount()
return nil, err
}
return conn, nil
}
func (c *ConnManager) TransportForDial(network string, raddr *net.UDPAddr) (refCountedQuicTransport, error) {
if c.enableReuseport {
reuse, err := c.getReuse(network)
if err != nil {
return nil, err
}
return reuse.TransportForDial(network, raddr)
}
var laddr *net.UDPAddr
switch network {
case "udp4":
laddr = &net.UDPAddr{IP: net.IPv4zero, Port: 0}
case "udp6":
laddr = &net.UDPAddr{IP: net.IPv6zero, Port: 0}
}
conn, err := net.ListenUDP(network, laddr)
if err != nil {
return nil, err
}
return &singleOwnerTransport{Transport: quic.Transport{Conn: conn, StatelessResetKey: &c.srk}, packetConn: conn}, nil
}
func (c *ConnManager) Protocols() []int {
return []int{ma.P_QUIC_V1}
}
func (c *ConnManager) Close() error {
if !c.enableReuseport {
return nil
}
if err := c.reuseUDP6.Close(); err != nil {
return err
}
return c.reuseUDP4.Close()
}

View File

@@ -0,0 +1,219 @@
package quicreuse
import (
"context"
"crypto/tls"
"errors"
"fmt"
"io"
"net"
"strings"
"sync"
"github.com/libp2p/go-libp2p/core/transport"
ma "github.com/multiformats/go-multiaddr"
"github.com/quic-go/quic-go"
)
type Listener interface {
Accept(context.Context) (quic.Connection, error)
Addr() net.Addr
Multiaddrs() []ma.Multiaddr
io.Closer
}
type protoConf struct {
ln *listener
tlsConf *tls.Config
allowWindowIncrease func(conn quic.Connection, delta uint64) bool
}
type quicListener struct {
l *quic.Listener
transport refCountedQuicTransport
running chan struct{}
addrs []ma.Multiaddr
protocolsMu sync.Mutex
protocols map[string]protoConf
}
func newQuicListener(tr refCountedQuicTransport, quicConfig *quic.Config) (*quicListener, error) {
localMultiaddrs := make([]ma.Multiaddr, 0, 2)
a, err := ToQuicMultiaddr(tr.LocalAddr(), quic.Version1)
if err != nil {
return nil, err
}
localMultiaddrs = append(localMultiaddrs, a)
cl := &quicListener{
protocols: map[string]protoConf{},
running: make(chan struct{}),
transport: tr,
addrs: localMultiaddrs,
}
tlsConf := &tls.Config{
SessionTicketsDisabled: true, // This is set for the config for client, but we set it here as well: https://github.com/quic-go/quic-go/issues/4029
GetConfigForClient: func(info *tls.ClientHelloInfo) (*tls.Config, error) {
cl.protocolsMu.Lock()
defer cl.protocolsMu.Unlock()
for _, proto := range info.SupportedProtos {
if entry, ok := cl.protocols[proto]; ok {
conf := entry.tlsConf
if conf.GetConfigForClient != nil {
return conf.GetConfigForClient(info)
}
return conf, nil
}
}
return nil, fmt.Errorf("no supported protocol found. offered: %+v", info.SupportedProtos)
},
}
quicConf := quicConfig.Clone()
quicConf.AllowConnectionWindowIncrease = cl.allowWindowIncrease
ln, err := tr.Listen(tlsConf, quicConf)
if err != nil {
return nil, err
}
cl.l = ln
go cl.Run() // This go routine shuts down once the underlying quic.Listener is closed (or returns an error).
return cl, nil
}
func (l *quicListener) allowWindowIncrease(conn quic.Connection, delta uint64) bool {
l.protocolsMu.Lock()
defer l.protocolsMu.Unlock()
conf, ok := l.protocols[conn.ConnectionState().TLS.NegotiatedProtocol]
if !ok {
return false
}
return conf.allowWindowIncrease(conn, delta)
}
func (l *quicListener) Add(tlsConf *tls.Config, allowWindowIncrease func(conn quic.Connection, delta uint64) bool, onRemove func()) (Listener, error) {
l.protocolsMu.Lock()
defer l.protocolsMu.Unlock()
if len(tlsConf.NextProtos) == 0 {
return nil, errors.New("no ALPN found in tls.Config")
}
for _, proto := range tlsConf.NextProtos {
if _, ok := l.protocols[proto]; ok {
return nil, fmt.Errorf("already listening for protocol %s", proto)
}
}
ln := newSingleListener(l.l.Addr(), l.addrs, func() {
l.protocolsMu.Lock()
for _, proto := range tlsConf.NextProtos {
delete(l.protocols, proto)
}
l.protocolsMu.Unlock()
onRemove()
}, l.running)
for _, proto := range tlsConf.NextProtos {
l.protocols[proto] = protoConf{
ln: ln,
tlsConf: tlsConf,
allowWindowIncrease: allowWindowIncrease,
}
}
return ln, nil
}
func (l *quicListener) Run() error {
defer close(l.running)
defer l.transport.DecreaseCount()
for {
conn, err := l.l.Accept(context.Background())
if err != nil {
if errors.Is(err, quic.ErrServerClosed) || strings.Contains(err.Error(), "use of closed network connection") {
return transport.ErrListenerClosed
}
return err
}
proto := conn.ConnectionState().TLS.NegotiatedProtocol
l.protocolsMu.Lock()
ln, ok := l.protocols[proto]
if !ok {
l.protocolsMu.Unlock()
return fmt.Errorf("negotiated unknown protocol: %s", proto)
}
ln.ln.add(conn)
l.protocolsMu.Unlock()
}
}
func (l *quicListener) Close() error {
err := l.l.Close()
<-l.running // wait for Run to return
return err
}
const queueLen = 16
// A listener for a single ALPN protocol (set).
type listener struct {
queue chan quic.Connection
acceptLoopRunning chan struct{}
addr net.Addr
addrs []ma.Multiaddr
remove func()
closeOnce sync.Once
}
var _ Listener = &listener{}
func newSingleListener(addr net.Addr, addrs []ma.Multiaddr, remove func(), running chan struct{}) *listener {
return &listener{
queue: make(chan quic.Connection, queueLen),
acceptLoopRunning: running,
remove: remove,
addr: addr,
addrs: addrs,
}
}
func (l *listener) add(c quic.Connection) {
select {
case l.queue <- c:
default:
c.CloseWithError(1, "queue full")
}
}
func (l *listener) Accept(ctx context.Context) (quic.Connection, error) {
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-l.acceptLoopRunning:
return nil, transport.ErrListenerClosed
case c, ok := <-l.queue:
if !ok {
return nil, transport.ErrListenerClosed
}
return c, nil
}
}
func (l *listener) Addr() net.Addr {
return l.addr
}
func (l *listener) Multiaddrs() []ma.Multiaddr {
return l.addrs
}
func (l *listener) Close() error {
l.closeOnce.Do(func() {
l.remove()
close(l.queue)
// drain the queue
for conn := range l.queue {
conn.CloseWithError(1, "closing")
}
})
return nil
}

View File

@@ -0,0 +1,18 @@
package quicreuse
type Option func(*ConnManager) error
func DisableReuseport() Option {
return func(m *ConnManager) error {
m.enableReuseport = false
return nil
}
}
// EnableMetrics enables Prometheus metrics collection.
func EnableMetrics() Option {
return func(m *ConnManager) error {
m.enableMetrics = true
return nil
}
}

View File

@@ -0,0 +1,58 @@
package quicreuse
import (
"errors"
"net"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/quic-go/quic-go"
)
var (
quicV1MA = ma.StringCast("/quic-v1")
)
func ToQuicMultiaddr(na net.Addr, version quic.VersionNumber) (ma.Multiaddr, error) {
udpMA, err := manet.FromNetAddr(na)
if err != nil {
return nil, err
}
switch version {
case quic.Version1:
return udpMA.Encapsulate(quicV1MA), nil
default:
return nil, errors.New("unknown QUIC version")
}
}
func FromQuicMultiaddr(addr ma.Multiaddr) (*net.UDPAddr, quic.VersionNumber, error) {
var version quic.VersionNumber
var partsBeforeQUIC []ma.Multiaddr
ma.ForEach(addr, func(c ma.Component) bool {
switch c.Protocol().Code {
case ma.P_QUIC_V1:
version = quic.Version1
return false
default:
partsBeforeQUIC = append(partsBeforeQUIC, &c)
return true
}
})
if len(partsBeforeQUIC) == 0 {
return nil, version, errors.New("no addr before QUIC component")
}
if version == 0 {
// Not found
return nil, version, errors.New("unknown QUIC version")
}
netAddr, err := manet.ToNetAddr(ma.Join(partsBeforeQUIC...))
if err != nil {
return nil, version, err
}
udpAddr, ok := netAddr.(*net.UDPAddr)
if !ok {
return nil, 0, errors.New("not a *net.UDPAddr")
}
return udpAddr, version, nil
}

View File

@@ -0,0 +1,353 @@
package quicreuse
import (
"context"
"crypto/tls"
"net"
"sync"
"time"
"github.com/google/gopacket/routing"
"github.com/libp2p/go-netroute"
"github.com/quic-go/quic-go"
)
type refCountedQuicTransport interface {
LocalAddr() net.Addr
// Used to send packets directly around QUIC. Useful for hole punching.
WriteTo([]byte, net.Addr) (int, error)
Close() error
// count transport reference
DecreaseCount()
IncreaseCount()
Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *quic.Config) (quic.Connection, error)
Listen(tlsConf *tls.Config, conf *quic.Config) (*quic.Listener, error)
}
type singleOwnerTransport struct {
quic.Transport
// Used to write packets directly around QUIC.
packetConn net.PacketConn
}
func (c *singleOwnerTransport) IncreaseCount() {}
func (c *singleOwnerTransport) DecreaseCount() {
c.Transport.Close()
}
func (c *singleOwnerTransport) LocalAddr() net.Addr {
return c.Transport.Conn.LocalAddr()
}
func (c *singleOwnerTransport) Close() error {
// TODO(when we drop support for go 1.19) use errors.Join
c.Transport.Close()
return c.packetConn.Close()
}
func (c *singleOwnerTransport) WriteTo(b []byte, addr net.Addr) (int, error) {
return c.Transport.WriteTo(b, addr)
}
// Constant. Defined as variables to simplify testing.
var (
garbageCollectInterval = 30 * time.Second
maxUnusedDuration = 10 * time.Second
)
type refcountedTransport struct {
quic.Transport
// Used to write packets directly around QUIC.
packetConn net.PacketConn
mutex sync.Mutex
refCount int
unusedSince time.Time
}
func (c *refcountedTransport) IncreaseCount() {
c.mutex.Lock()
c.refCount++
c.unusedSince = time.Time{}
c.mutex.Unlock()
}
func (c *refcountedTransport) Close() error {
// TODO(when we drop support for go 1.19) use errors.Join
c.Transport.Close()
return c.packetConn.Close()
}
func (c *refcountedTransport) WriteTo(b []byte, addr net.Addr) (int, error) {
return c.Transport.WriteTo(b, addr)
}
func (c *refcountedTransport) LocalAddr() net.Addr {
return c.Transport.Conn.LocalAddr()
}
func (c *refcountedTransport) DecreaseCount() {
c.mutex.Lock()
c.refCount--
if c.refCount == 0 {
c.unusedSince = time.Now()
}
c.mutex.Unlock()
}
func (c *refcountedTransport) ShouldGarbageCollect(now time.Time) bool {
c.mutex.Lock()
defer c.mutex.Unlock()
return !c.unusedSince.IsZero() && c.unusedSince.Add(maxUnusedDuration).Before(now)
}
type reuse struct {
mutex sync.Mutex
closeChan chan struct{}
gcStopChan chan struct{}
routes routing.Router
unicast map[string] /* IP.String() */ map[int] /* port */ *refcountedTransport
// globalListeners contains transports that are listening on 0.0.0.0 / ::
globalListeners map[int]*refcountedTransport
// globalDialers contains transports that we've dialed out from. These transports are listening on 0.0.0.0 / ::
// On Dial, transports are reused from this map if no transport is available in the globalListeners
// On Listen, transports are reused from this map if the requested port is 0, and then moved to globalListeners
globalDialers map[int]*refcountedTransport
statelessResetKey *quic.StatelessResetKey
tokenGeneratorKey *quic.TokenGeneratorKey
}
func newReuse(srk *quic.StatelessResetKey, tokenKey *quic.TokenGeneratorKey) *reuse {
r := &reuse{
unicast: make(map[string]map[int]*refcountedTransport),
globalListeners: make(map[int]*refcountedTransport),
globalDialers: make(map[int]*refcountedTransport),
closeChan: make(chan struct{}),
gcStopChan: make(chan struct{}),
statelessResetKey: srk,
tokenGeneratorKey: tokenKey,
}
go r.gc()
return r
}
func (r *reuse) gc() {
defer func() {
r.mutex.Lock()
for _, tr := range r.globalListeners {
tr.Close()
}
for _, tr := range r.globalDialers {
tr.Close()
}
for _, trs := range r.unicast {
for _, tr := range trs {
tr.Close()
}
}
r.mutex.Unlock()
close(r.gcStopChan)
}()
ticker := time.NewTicker(garbageCollectInterval)
defer ticker.Stop()
for {
select {
case <-r.closeChan:
return
case <-ticker.C:
now := time.Now()
r.mutex.Lock()
for key, tr := range r.globalListeners {
if tr.ShouldGarbageCollect(now) {
tr.Close()
delete(r.globalListeners, key)
}
}
for key, tr := range r.globalDialers {
if tr.ShouldGarbageCollect(now) {
tr.Close()
delete(r.globalDialers, key)
}
}
for ukey, trs := range r.unicast {
for key, tr := range trs {
if tr.ShouldGarbageCollect(now) {
tr.Close()
delete(trs, key)
}
}
if len(trs) == 0 {
delete(r.unicast, ukey)
// If we've dropped all transports with a unicast binding,
// assume our routes may have changed.
if len(r.unicast) == 0 {
r.routes = nil
} else {
// Ignore the error, there's nothing we can do about
// it.
r.routes, _ = netroute.New()
}
}
}
r.mutex.Unlock()
}
}
}
func (r *reuse) TransportForDial(network string, raddr *net.UDPAddr) (*refcountedTransport, error) {
var ip *net.IP
// Only bother looking up the source address if we actually _have_ non 0.0.0.0 listeners.
// Otherwise, save some time.
r.mutex.Lock()
router := r.routes
r.mutex.Unlock()
if router != nil {
_, _, src, err := router.Route(raddr.IP)
if err == nil && !src.IsUnspecified() {
ip = &src
}
}
r.mutex.Lock()
defer r.mutex.Unlock()
tr, err := r.transportForDialLocked(network, ip)
if err != nil {
return nil, err
}
tr.IncreaseCount()
return tr, nil
}
func (r *reuse) transportForDialLocked(network string, source *net.IP) (*refcountedTransport, error) {
if source != nil {
// We already have at least one suitable transport...
if trs, ok := r.unicast[source.String()]; ok {
// ... we don't care which port we're dialing from. Just use the first.
for _, tr := range trs {
return tr, nil
}
}
}
// Use a transport listening on 0.0.0.0 (or ::).
// Again, we don't care about the port number.
for _, tr := range r.globalListeners {
return tr, nil
}
// Use a transport we've previously dialed from
for _, tr := range r.globalDialers {
return tr, nil
}
// We don't have a transport that we can use for dialing.
// Dial a new connection from a random port.
var addr *net.UDPAddr
switch network {
case "udp4":
addr = &net.UDPAddr{IP: net.IPv4zero, Port: 0}
case "udp6":
addr = &net.UDPAddr{IP: net.IPv6zero, Port: 0}
}
conn, err := net.ListenUDP(network, addr)
if err != nil {
return nil, err
}
tr := &refcountedTransport{Transport: quic.Transport{
Conn: conn,
StatelessResetKey: r.statelessResetKey,
TokenGeneratorKey: r.tokenGeneratorKey,
}, packetConn: conn}
r.globalDialers[conn.LocalAddr().(*net.UDPAddr).Port] = tr
return tr, nil
}
func (r *reuse) TransportForListen(network string, laddr *net.UDPAddr) (*refcountedTransport, error) {
r.mutex.Lock()
defer r.mutex.Unlock()
// Check if we can reuse a transport we have already dialed out from.
// We reuse a transport from globalDialers when the requested port is 0 or the requested
// port is already in the globalDialers.
// If we are reusing a transport from globalDialers, we move the globalDialers entry to
// globalListeners
if laddr.IP.IsUnspecified() {
var rTr *refcountedTransport
var localAddr *net.UDPAddr
if laddr.Port == 0 {
// the requested port is 0, we can reuse any transport
for _, tr := range r.globalDialers {
rTr = tr
localAddr = rTr.LocalAddr().(*net.UDPAddr)
delete(r.globalDialers, localAddr.Port)
break
}
} else if _, ok := r.globalDialers[laddr.Port]; ok {
rTr = r.globalDialers[laddr.Port]
localAddr = rTr.LocalAddr().(*net.UDPAddr)
delete(r.globalDialers, localAddr.Port)
}
// found a match
if rTr != nil {
rTr.IncreaseCount()
r.globalListeners[localAddr.Port] = rTr
return rTr, nil
}
}
conn, err := net.ListenUDP(network, laddr)
if err != nil {
return nil, err
}
localAddr := conn.LocalAddr().(*net.UDPAddr)
tr := &refcountedTransport{
Transport: quic.Transport{
Conn: conn,
StatelessResetKey: r.statelessResetKey,
},
packetConn: conn,
}
tr.IncreaseCount()
// Deal with listen on a global address
if localAddr.IP.IsUnspecified() {
// The kernel already checked that the laddr is not already listen
// so we need not check here (when we create ListenUDP).
r.globalListeners[localAddr.Port] = tr
return tr, nil
}
// Deal with listen on a unicast address
if _, ok := r.unicast[localAddr.IP.String()]; !ok {
r.unicast[localAddr.IP.String()] = make(map[int]*refcountedTransport)
// Assume the system's routes may have changed if we're adding a new listener.
// Ignore the error, there's nothing we can do.
r.routes, _ = netroute.New()
}
// The kernel already checked that the laddr is not already listen
// so we need not check here (when we create ListenUDP).
r.unicast[localAddr.IP.String()][localAddr.Port] = tr
return tr, nil
}
func (r *reuse) Close() error {
close(r.closeChan)
<-r.gcStopChan
return nil
}

View File

@@ -0,0 +1,94 @@
package quicreuse
import (
"bufio"
"fmt"
"io"
"os"
"time"
golog "github.com/ipfs/go-log/v2"
"github.com/klauspost/compress/zstd"
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/logging"
"github.com/quic-go/quic-go/qlog"
)
var log = golog.Logger("quic-utils")
// QLOGTracer holds a qlog tracer dir, if qlogging is enabled (enabled using the QLOGDIR environment variable).
// Otherwise it is an empty string.
var qlogTracerDir string
func init() {
qlogTracerDir = os.Getenv("QLOGDIR")
}
func qloggerForDir(qlogDir string, p logging.Perspective, ci quic.ConnectionID) *logging.ConnectionTracer {
// create the QLOGDIR, if it doesn't exist
if err := os.MkdirAll(qlogDir, 0777); err != nil {
log.Errorf("creating the QLOGDIR failed: %s", err)
return nil
}
return qlog.NewConnectionTracer(newQlogger(qlogDir, p, ci), p, ci)
}
// The qlogger logs qlog events to a temporary file: .<name>.qlog.swp.
// When it is closed, it compresses the temporary file and saves it as <name>.qlog.zst.
// It is not possible to compress on the fly, as compression algorithms keep a lot of internal state,
// which can easily exhaust the host system's memory when running a few hundred QUIC connections in parallel.
type qlogger struct {
f *os.File // QLOGDIR/.log_xxx.qlog.swp
filename string // QLOGDIR/log_xxx.qlog.zst
*bufio.Writer // buffering the f
}
func newQlogger(qlogDir string, role logging.Perspective, connID quic.ConnectionID) io.WriteCloser {
t := time.Now().UTC().Format("2006-01-02T15-04-05.999999999UTC")
r := "server"
if role == logging.PerspectiveClient {
r = "client"
}
finalFilename := fmt.Sprintf("%s%clog_%s_%s_%s.qlog.zst", qlogDir, os.PathSeparator, t, r, connID)
filename := fmt.Sprintf("%s%c.log_%s_%s_%s.qlog.swp", qlogDir, os.PathSeparator, t, r, connID)
f, err := os.Create(filename)
if err != nil {
log.Errorf("unable to create qlog file %s: %s", filename, err)
return nil
}
return &qlogger{
f: f,
filename: finalFilename,
// The size of a qlog file for a raw file download is ~2/3 of the amount of data transferred.
// bufio.NewWriter creates a buffer with a buffer of only 4 kB, leading to a large number of syscalls.
Writer: bufio.NewWriterSize(f, 128<<10),
}
}
func (l *qlogger) Close() error {
defer os.Remove(l.f.Name())
defer l.f.Close()
if err := l.Writer.Flush(); err != nil {
return err
}
if _, err := l.f.Seek(0, io.SeekStart); err != nil { // set the read position to the beginning of the file
return err
}
f, err := os.Create(l.filename)
if err != nil {
return err
}
defer f.Close()
buf := bufio.NewWriterSize(f, 128<<10)
c, err := zstd.NewWriter(buf, zstd.WithEncoderLevel(zstd.SpeedFastest), zstd.WithWindowSize(32*1024))
if err != nil {
return err
}
if _, err := io.Copy(c, l.f); err != nil {
return err
}
if err := c.Close(); err != nil {
return err
}
return buf.Flush()
}