@ -30,8 +30,9 @@ import (
//
// [relayManager] methods can be called by [Conn] and [endpoint] while their .mu
// mutexes are held. Therefore, in order to avoid deadlocks, [relayManager] must
// never attempt to acquire those mutexes, including synchronous calls back
// towards [Conn] or [endpoint] methods that acquire them.
// never attempt to acquire those mutexes synchronously from its runLoop(),
// including synchronous calls back towards [Conn] or [endpoint] methods that
// acquire them.
type relayManager struct {
initOnce sync . Once
@ -584,9 +585,37 @@ func (r *relayManager) handleNewServerEndpointRunLoop(newServerEndpoint newRelay
byServerDisco [ newServerEndpoint . se . ServerDisco ] = work
r . handshakeWorkByServerDiscoVNI [ sdv ] = work
if newServerEndpoint . server . IsValid ( ) {
// Send CallMeMaybeVia to the remote peer if we allocated this endpoint.
go r . sendCallMeMaybeVia ( work . ep , work . se )
}
go r . handshakeServerEndpoint ( work )
}
// sendCallMeMaybeVia sends a [disco.CallMeMaybeVia] to ep over DERP. It must be
// called as part of a goroutine independent from runLoop(), for 2 reasons:
// 1. it acquires ep.mu (refer to [relayManager] docs for reasoning)
// 2. it makes a networking syscall, which can introduce unwanted backpressure
func ( r * relayManager ) sendCallMeMaybeVia ( ep * endpoint , se udprelay . ServerEndpoint ) {
ep . mu . Lock ( )
derpAddr := ep . derpAddr
ep . mu . Unlock ( )
epDisco := ep . disco . Load ( )
if epDisco == nil || ! derpAddr . IsValid ( ) {
return
}
callMeMaybeVia := & disco . CallMeMaybeVia {
ServerDisco : se . ServerDisco ,
LamportID : se . LamportID ,
VNI : se . VNI ,
BindLifetime : se . BindLifetime . Duration ,
SteadyStateLifetime : se . SteadyStateLifetime . Duration ,
AddrPorts : se . AddrPorts ,
}
ep . c . sendDiscoMessage ( epAddr { ap : derpAddr } , ep . publicKey , epDisco . key , callMeMaybeVia , discoVerboseLog )
}
func ( r * relayManager ) handshakeServerEndpoint ( work * relayHandshakeWork ) {
done := relayEndpointHandshakeWorkDoneEvent { work : work }
r . ensureDiscoInfoFor ( work )
@ -779,8 +808,9 @@ func (r *relayManager) allocateSingleServer(ctx context.Context, wg *sync.WaitGr
se , err := doAllocate ( ctx , server , [ 2 ] key . DiscoPublic { ep . c . discoPublic , remoteDisco . key } )
if err == nil {
relayManagerInputEvent ( r , ctx , & r . newServerEndpointCh , newRelayServerEndpointEvent {
ep : ep ,
se : se ,
ep : ep ,
se : se ,
server : server , // we allocated this endpoint (vs CallMeMaybeVia reception), mark it as such
} )
return
}