@ -5,7 +5,6 @@ package derphttp
import (
import (
"context"
"context"
"net/netip"
"sync"
"sync"
"time"
"time"
@ -35,9 +34,14 @@ var testHookWatchLookConnectResult func(connectError error, wasSelfConnect bool)
// To force RunWatchConnectionLoop to return quickly, its ctx needs to be
// To force RunWatchConnectionLoop to return quickly, its ctx needs to be
// closed, and c itself needs to be closed.
// closed, and c itself needs to be closed.
//
//
// It is a fatal error to call this on an already-started Client without q having
// It is a fatal error to call this on an already-started Client without having
// initialized Client.WatchConnectionChanges to true.
// initialized Client.WatchConnectionChanges to true.
func ( c * Client ) RunWatchConnectionLoop ( ctx context . Context , ignoreServerKey key . NodePublic , infoLogf logger . Logf , add func ( key . NodePublic , netip . AddrPort ) , remove func ( key . NodePublic ) ) {
//
// If the DERP connection breaks and reconnects, remove will be called for all
// previously seen peers, with Reason type PeerGoneReasonSynthetic. Those
// clients are likely still connected and their add message will appear after
// reconnect.
func ( c * Client ) RunWatchConnectionLoop ( ctx context . Context , ignoreServerKey key . NodePublic , infoLogf logger . Logf , add func ( derp . PeerPresentMessage ) , remove func ( derp . PeerGoneMessage ) ) {
if ! c . WatchConnectionChanges {
if ! c . WatchConnectionChanges {
if c . isStarted ( ) {
if c . isStarted ( ) {
panic ( "invalid use of RunWatchConnectionLoop on already-started Client without setting Client.RunWatchConnectionLoop" )
panic ( "invalid use of RunWatchConnectionLoop on already-started Client without setting Client.RunWatchConnectionLoop" )
@ -62,7 +66,7 @@ func (c *Client) RunWatchConnectionLoop(ctx context.Context, ignoreServerKey key
}
}
logf ( "reconnected; clearing %d forwarding mappings" , len ( present ) )
logf ( "reconnected; clearing %d forwarding mappings" , len ( present ) )
for k := range present {
for k := range present {
remove ( k)
remove ( derp. PeerGoneMessage { Peer : k, Reason : derp . PeerGoneReasonMeshConnBroke } )
}
}
present = map [ key . NodePublic ] bool { }
present = map [ key . NodePublic ] bool { }
}
}
@ -84,13 +88,7 @@ func (c *Client) RunWatchConnectionLoop(ctx context.Context, ignoreServerKey key
} )
} )
defer timer . Stop ( )
defer timer . Stop ( )
updatePeer := func ( k key . NodePublic , ipPort netip . AddrPort , isPresent bool ) {
updatePeer := func ( k key . NodePublic , isPresent bool ) {
if isPresent {
add ( k , ipPort )
} else {
remove ( k )
}
mu . Lock ( )
mu . Lock ( )
defer mu . Unlock ( )
defer mu . Unlock ( )
if isPresent {
if isPresent {
@ -148,7 +146,8 @@ func (c *Client) RunWatchConnectionLoop(ctx context.Context, ignoreServerKey key
}
}
switch m := m . ( type ) {
switch m := m . ( type ) {
case derp . PeerPresentMessage :
case derp . PeerPresentMessage :
updatePeer ( m . Key , m . IPPort , true )
add ( m )
updatePeer ( m . Key , true )
case derp . PeerGoneMessage :
case derp . PeerGoneMessage :
switch m . Reason {
switch m . Reason {
case derp . PeerGoneReasonDisconnected :
case derp . PeerGoneReasonDisconnected :
@ -160,7 +159,8 @@ func (c *Client) RunWatchConnectionLoop(ctx context.Context, ignoreServerKey key
logf ( "Recv: peer %s not at server %s for unknown reason %v" ,
logf ( "Recv: peer %s not at server %s for unknown reason %v" ,
key . NodePublic ( m . Peer ) . ShortString ( ) , c . ServerPublicKey ( ) . ShortString ( ) , m . Reason )
key . NodePublic ( m . Peer ) . ShortString ( ) , c . ServerPublicKey ( ) . ShortString ( ) , m . Reason )
}
}
updatePeer ( key . NodePublic ( m . Peer ) , netip . AddrPort { } , false )
remove ( m )
updatePeer ( m . Peer , false )
default :
default :
continue
continue
}
}