Switch to experimental yggquic branch

This commit is contained in:
Neil Alexander
2025-11-27 00:09:06 +00:00
parent 890ef4ada9
commit c890e29508
3 changed files with 18 additions and 154 deletions

6
go.mod
View File

@@ -5,7 +5,6 @@ go 1.22
toolchain go1.23.0
require (
github.com/Arceliar/ironwood v0.0.0-20241213013129-743fe2fccbd3
github.com/emersion/go-imap v1.2.1
github.com/emersion/go-imap-idle v0.0.0-20210907174914-db2568431445
github.com/emersion/go-message v0.17.0
@@ -14,14 +13,15 @@ require (
github.com/fatih/color v1.18.0
github.com/gologme/log v1.3.0
github.com/mattn/go-sqlite3 v1.14.24
github.com/quic-go/quic-go v0.48.2
github.com/yggdrasil-network/yggdrasil-go v0.5.12
github.com/yggdrasil-network/yggquic v0.0.0-20251127000438-f4f94a6def24
go.uber.org/atomic v1.11.0
golang.org/x/crypto v0.31.0
golang.org/x/term v0.27.0
)
require (
github.com/Arceliar/ironwood v0.0.0-20241213013129-743fe2fccbd3 // indirect
github.com/Arceliar/phony v0.0.0-20220903101357-530938a4b13d // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/bits-and-blooms/bloom/v3 v3.7.0 // indirect
@@ -32,7 +32,9 @@ require (
github.com/hjson/hjson-go/v4 v4.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/neilalexander/generique v0.0.0-20251127000013-def6a5bd842a // indirect
github.com/onsi/ginkgo/v2 v2.13.0 // indirect
github.com/quic-go/quic-go v0.48.2 // indirect
github.com/wlynxg/anet v0.0.5 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect

4
go.sum
View File

@@ -54,6 +54,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/neilalexander/generique v0.0.0-20251127000013-def6a5bd842a h1:iV/ivYwvXCsNOEFIc4YjQNbq+pmTqhON/rFQcjYLEPs=
github.com/neilalexander/generique v0.0.0-20251127000013-def6a5bd842a/go.mod h1:dJzRxTIvxTW+LULsKqkBmaYRrXiGbee6mvvUPoj/Pvk=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
@@ -73,6 +75,8 @@ github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
github.com/yggdrasil-network/yggdrasil-go v0.5.12 h1:SaQ8d59JP+uFy+nOWXTx1ETM5r2uCfe1Gt/d+IodHJw=
github.com/yggdrasil-network/yggdrasil-go v0.5.12/go.mod h1:u4DU6dpTfWmVs8r0WjW1T3UpGyeUh9vRrS8zngvncwM=
github.com/yggdrasil-network/yggquic v0.0.0-20251127000438-f4f94a6def24 h1:G7+Q8WCBRqSEidXz0jMcTIPibo7SImRbrvPHRsMsYM4=
github.com/yggdrasil-network/yggquic v0.0.0-20251127000438-f4f94a6def24/go.mod h1:AbOaTarCfQS5wB/YuUtAho9UeBhBEYgEylK+9SyPiwM=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=

View File

@@ -9,45 +9,23 @@
package transport
import (
"context"
"crypto/ed25519"
"crypto/tls"
"encoding/hex"
"fmt"
"log"
"net"
"regexp"
"sync"
"time"
iwt "github.com/Arceliar/ironwood/types"
"github.com/fatih/color"
gologme "github.com/gologme/log"
"github.com/quic-go/quic-go"
"github.com/yggdrasil-network/yggdrasil-go/src/config"
"github.com/yggdrasil-network/yggdrasil-go/src/core"
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
"github.com/yggdrasil-network/yggquic"
)
type YggdrasilTransport struct {
listener *quic.Listener
yggdrasil net.PacketConn
transport *quic.Transport
tlsConfig *tls.Config
quicConfig *quic.Config
incoming chan *yggdrasilSession
sessions sync.Map // string -> quic.Connection
dials sync.Map // string -> *yggdrasilDial
}
type yggdrasilSession struct {
quic.Connection
quic.Stream
}
type yggdrasilDial struct {
context.Context
context.CancelFunc
yggquic *yggquic.YggdrasilTransport
}
func NewYggdrasilTransport(log *log.Logger, sk ed25519.PrivateKey, pk ed25519.PublicKey, peers []string, mcast bool, mcastregexp string) (*YggdrasilTransport, error) {
@@ -96,140 +74,20 @@ func NewYggdrasilTransport(log *log.Logger, sk ed25519.PrivateKey, pk ed25519.Pu
}
}
tr := &YggdrasilTransport{
tlsConfig: &tls.Config{
ServerName: hex.EncodeToString(ygg.PublicKey()),
Certificates: []tls.Certificate{
*cfg.Certificate,
},
InsecureSkipVerify: true,
},
quicConfig: &quic.Config{
HandshakeIdleTimeout: time.Second * 5,
MaxIdleTimeout: time.Second * 60,
},
transport: &quic.Transport{
Conn: ygg,
},
yggdrasil: ygg,
incoming: make(chan *yggdrasilSession, 1),
yq, err := yggquic.New(ygg, *cfg.Certificate, nil)
if err != nil {
panic(err)
}
if tr.listener, err = tr.transport.Listen(tr.tlsConfig, tr.quicConfig); err != nil {
return nil, fmt.Errorf("quic.Listen: %w", err)
}
go tr.connectionAcceptLoop()
return tr, nil
}
func (t *YggdrasilTransport) connectionAcceptLoop() {
for {
qc, err := t.listener.Accept(context.TODO())
if err != nil {
return
}
host := qc.RemoteAddr().String()
if eqc, ok := t.sessions.LoadAndDelete(host); ok {
eqc := eqc.(quic.Connection)
_ = eqc.CloseWithError(0, "Connection replaced")
}
t.sessions.Store(host, qc)
if dial, ok := t.dials.LoadAndDelete(host); ok {
dial := dial.(*yggdrasilDial)
dial.CancelFunc()
}
go t.streamAcceptLoop(qc)
}
}
func (t *YggdrasilTransport) streamAcceptLoop(qc quic.Connection) {
host := qc.RemoteAddr().String()
defer qc.CloseWithError(0, "Timed out") // nolint:errcheck
defer t.sessions.Delete(host)
for {
qs, err := qc.AcceptStream(context.Background())
if err != nil {
break
}
t.incoming <- &yggdrasilSession{qc, qs}
}
return &YggdrasilTransport{
yggquic: yq,
}, nil
}
func (t *YggdrasilTransport) Dial(host string) (net.Conn, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
var retry bool
retry:
qc, ok := t.sessions.Load(host)
if !ok {
if dial, ok := t.dials.Load(host); ok {
<-dial.(*yggdrasilDial).Done()
}
if qc, ok = t.sessions.Load(host); !ok {
dialctx, dialcancel := context.WithCancel(ctx)
defer dialcancel()
t.dials.Store(host, &yggdrasilDial{dialctx, dialcancel})
defer t.dials.Delete(host)
addr := make(iwt.Addr, ed25519.PublicKeySize)
k, err := hex.DecodeString(host)
if err != nil {
return nil, err
}
copy(addr, k)
if qc, err = t.transport.Dial(dialctx, addr, t.tlsConfig, t.quicConfig); err != nil {
return nil, err
}
qc := qc.(quic.Connection)
t.sessions.Store(host, qc)
go t.streamAcceptLoop(qc)
}
}
if qc == nil {
return nil, net.ErrClosed
} else {
qc := qc.(quic.Connection)
qs, err := qc.OpenStreamSync(ctx)
if err != nil {
if !retry {
retry = true
goto retry
}
return nil, err
}
// For some reason this is needed to kick the stream
_, err = qs.Write([]byte(" "))
return &yggdrasilSession{qc, qs}, err
}
return t.yggquic.Dial("yggdrasil", host)
}
func (t *YggdrasilTransport) Listener() net.Listener {
return &yggdrasilListener{t}
}
type yggdrasilListener struct {
*YggdrasilTransport
}
func (t *yggdrasilListener) Accept() (net.Conn, error) {
return <-t.incoming, nil
}
func (t *yggdrasilListener) Addr() net.Addr {
return t.listener.Addr()
}
func (t *yggdrasilListener) Close() error {
if err := t.listener.Close(); err != nil {
return err
}
return t.yggdrasil.Close()
return t.yggquic
}