Reset sessions when coordinates change

This commit is contained in:
Neil Alexander 2020-08-06 14:30:56 +01:00
parent 71198eb303
commit f15a96bec0
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
4 changed files with 52 additions and 33 deletions

View file

@ -50,7 +50,7 @@ type Node struct {
listener quic.Listener
tlsConfig *tls.Config
quicConfig *quic.Config
sessions sync.Map // string -> quic.Session
sessions sync.Map // string -> *session
sessionCount atomic.Uint32
sessionFunc func(address string)
coords sync.Map // string -> yggdrasil.Coords
@ -94,6 +94,24 @@ func Setup(instanceName, storageDirectory string) (*Node, error) {
}
}
n.core.SetCoordChangeCallback(func(old, new yggdrasil.Coords) {
fmt.Println("COORDINATE CHANGE!")
fmt.Println("Old:", old)
fmt.Println("New:", new)
n.coords.Range(func(k, _ interface{}) bool {
fmt.Println("Deleting cached coords for", k)
n.coords.Delete(k)
return true
})
n.sessions.Range(func(k, v interface{}) bool {
if s, ok := v.(*session); ok {
fmt.Println("Killing session", k)
s.kill()
}
return true
})
})
n.config.Peers = []string{}
n.config.AdminListen = "none"
n.config.MulticastInterfaces = []string{}
@ -127,7 +145,7 @@ func Setup(instanceName, storageDirectory string) (*Node, error) {
MaxIncomingStreams: 0,
MaxIncomingUniStreams: 0,
KeepAlive: true,
MaxIdleTimeout: time.Minute * 5,
MaxIdleTimeout: time.Minute * 30,
HandshakeTimeout: time.Second * 15,
}
copy(n.quicConfig.StatelessResetKey, n.EncryptionPublicKey())

View file

@ -38,20 +38,23 @@ type session struct {
node *Node
session quic.Session
address string
cancel chan struct{}
context context.Context
cancel context.CancelFunc
}
func (n *Node) newSession(sess quic.Session, address string) *session {
ctx, cancel := context.WithCancel(context.TODO())
return &session{
node: n,
session: sess,
address: address,
cancel: make(chan struct{}),
context: ctx,
cancel: cancel,
}
}
func (s *session) kill() {
close(s.cancel)
s.cancel()
}
func (n *Node) listenFromYgg() {
@ -85,23 +88,17 @@ func (n *Node) listenFromYgg() {
func (s *session) listenFromQUIC() {
if existing, ok := s.node.sessions.Load(s.address); ok {
if existingSession, ok := existing.(session); ok {
if existingSession, ok := existing.(*session); ok {
fmt.Println("Killing existing session to replace", s.address)
existingSession.kill()
}
}
s.node.sessionCount.Inc()
s.node.sessions.Store(s.address, s.session)
s.node.sessions.Store(s.address, s)
defer s.node.sessions.Delete(s.address)
defer s.node.sessionCount.Dec()
for {
select {
case <-s.cancel:
_ = s.session.CloseWithError(0, "killed")
return
default:
ctx, cancel := context.WithTimeout(context.TODO(), s.node.quicConfig.MaxIdleTimeout)
defer cancel()
st, err := s.session.AcceptStream(ctx)
st, err := s.session.AcceptStream(s.context)
if err != nil {
s.node.log.Println("session.AcceptStream:", err)
return
@ -109,7 +106,6 @@ func (s *session) listenFromQUIC() {
s.node.incoming <- QUICStream{st, s.session}
}
}
}
// Implements net.Listener
func (n *Node) Accept() (net.Conn, error) {
@ -135,7 +131,7 @@ func (n *Node) Dial(network, address string) (net.Conn, error) {
// nolint:gocyclo
func (n *Node) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
s, ok1 := n.sessions.Load(address)
session, ok2 := s.(quic.Session)
session, ok2 := s.(*session)
if !ok1 || !ok2 {
// First of all, check if we think we know the coords of this
// node. If we do then we'll try to dial to it directly. This
@ -214,17 +210,17 @@ func (n *Node) DialContext(ctx context.Context, network, address string) (net.Co
return nil, fmt.Errorf("should have found session but didn't")
}
st, err := session.OpenStream()
st, err := session.session.OpenStream()
if err != nil {
n.log.Println("session.OpenStream:", err)
_ = session.CloseWithError(0, "expected to be able to open session")
_ = session.session.CloseWithError(0, "expected to be able to open session")
return nil, err
}
return QUICStream{st, session}, nil
return QUICStream{st, session.session}, nil
}
func (n *Node) tryDial(address string, coords yggdrasil.Coords) (quic.Session, error) {
session, err := quic.Dial(
func (n *Node) tryDial(address string, coords yggdrasil.Coords) (*session, error) {
quicSession, err := quic.Dial(
n.core, // yggdrasil.PacketConn
coords, // dial address
address, // dial SNI
@ -234,19 +230,20 @@ func (n *Node) tryDial(address string, coords yggdrasil.Coords) (quic.Session, e
if err != nil {
return nil, err
}
if len(session.ConnectionState().PeerCertificates) != 1 {
_ = session.CloseWithError(0, "expected a peer certificate")
if len(quicSession.ConnectionState().PeerCertificates) != 1 {
_ = quicSession.CloseWithError(0, "expected a peer certificate")
return nil, errors.New("didn't receive a peer certificate")
}
if len(session.ConnectionState().PeerCertificates[0].DNSNames) != 1 {
_ = session.CloseWithError(0, "expected a DNS name")
if len(quicSession.ConnectionState().PeerCertificates[0].DNSNames) != 1 {
_ = quicSession.CloseWithError(0, "expected a DNS name")
return nil, errors.New("didn't receive a DNS name")
}
if gotAddress := session.ConnectionState().PeerCertificates[0].DNSNames[0]; address != gotAddress {
_ = session.CloseWithError(0, "you aren't the host I was hoping for")
if gotAddress := quicSession.ConnectionState().PeerCertificates[0].DNSNames[0]; address != gotAddress {
_ = quicSession.CloseWithError(0, "you aren't the host I was hoping for")
return nil, fmt.Errorf("expected %q but dialled %q", address, gotAddress)
}
go n.newSession(session, address).listenFromQUIC()
session := n.newSession(quicSession, address)
go session.listenFromQUIC()
go n.sessionFunc(address)
return session, nil
}

2
go.mod
View file

@ -36,7 +36,7 @@ require (
github.com/uber-go/atomic v1.3.0 // indirect
github.com/uber/jaeger-client-go v2.15.0+incompatible
github.com/uber/jaeger-lib v1.5.0
github.com/yggdrasil-network/yggdrasil-go v0.3.15-0.20200715104113-1046b00c3be3
github.com/yggdrasil-network/yggdrasil-go v0.3.15-0.20200806125501-cd4685a3b4de
go.uber.org/atomic v1.4.0
golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5
golang.org/x/mobile v0.0.0-20200801112145-973feb4309de // indirect

4
go.sum
View file

@ -655,6 +655,10 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:
github.com/yggdrasil-network/yggdrasil-extras v0.0.0-20200525205615-6c8a4a2e8855/go.mod h1:xQdsh08Io6nV4WRnOVTe6gI8/2iTvfLDQ0CYa5aMt+I=
github.com/yggdrasil-network/yggdrasil-go v0.3.15-0.20200715104113-1046b00c3be3 h1:teLoIJgPHysREs8P6GlcS/PgaU9W9+GQndikFCQ1lY0=
github.com/yggdrasil-network/yggdrasil-go v0.3.15-0.20200715104113-1046b00c3be3/go.mod h1:d+Nz6SPeG6kmeSPFL0cvfWfgwEql75fUnZiAONgvyBE=
github.com/yggdrasil-network/yggdrasil-go v0.3.15-0.20200806124633-bd1bdd6be073 h1:Fg4Bszd2qp6eyz/yDMYfB8g2PC1FfNQphGRgZAyD0VU=
github.com/yggdrasil-network/yggdrasil-go v0.3.15-0.20200806124633-bd1bdd6be073/go.mod h1:d+Nz6SPeG6kmeSPFL0cvfWfgwEql75fUnZiAONgvyBE=
github.com/yggdrasil-network/yggdrasil-go v0.3.15-0.20200806125501-cd4685a3b4de h1:p91aw0Mvol825U+5bvV9BBPl+HQxIczj7wxIOxZs70M=
github.com/yggdrasil-network/yggdrasil-go v0.3.15-0.20200806125501-cd4685a3b4de/go.mod h1:d+Nz6SPeG6kmeSPFL0cvfWfgwEql75fUnZiAONgvyBE=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=