@ -82,11 +82,11 @@ type extension struct {
logf logger . Logf
bus * eventbus . Bus
mu sync . Mutex // guards the following fields
shutdown bool
mu sync . Mutex // guards the following fields
shutdown bool
port * int // ipn.Prefs.RelayServerPort, nil if disabled
disconnectFromBusCh chan struct { } // non-nil if consumeEventbusTopics is running, closed to signal it to return
busDoneCh chan struct { } // non-nil if consumeEventbusTopics is running, closed when it returns
eventSubs * eventbus . Monitor // nil if not connected to eventbus
debugSessionsCh chan chan [ ] status . ServerSession // non-nil if consumeEventbusTopics is running
hasNodeAttrDisableRelayServer bool // tailcfg.NodeAttrDisableRelayServer
}
@ -119,15 +119,13 @@ func (e *extension) handleBusLifetimeLocked() {
if ! busShouldBeRunning {
e . disconnectFromBusLocked ( )
return
}
if e . busDoneCh != nil {
} else if e . eventSubs != nil {
return // already running
}
port := * e . port
e . disconnectFromBusCh = make ( chan struct { } )
e . busDoneCh = make ( chan struct { } )
ec := e . bus . Client ( "relayserver.extension" )
e . debugSessionsCh = make ( chan chan [ ] status . ServerSession )
go e . consumeEventbusTopics ( port)
e . eventSubs = ptr . To ( ec . Monitor ( e . consumeEventbusTopics ( ec, * e . port) ) )
}
func ( e * extension ) selfNodeViewChanged ( nodeView tailcfg . NodeView ) {
@ -175,77 +173,72 @@ var overrideAddrs = sync.OnceValue(func() (ret []netip.Addr) {
// consumeEventbusTopics serves endpoint allocation requests over the eventbus.
// It also serves [relayServer] debug information on a channel.
// consumeEventbusTopics must never acquire [extension.mu], which can be held by
// other goroutines while waiting to receive on [extension.busDoneCh ] or the
// consumeEventbusTopics must never acquire [extension.mu], which can be held
// by other goroutines while waiting to receive on [extension.eventSubs ] or the
// inner [extension.debugSessionsCh] channel.
func ( e * extension ) consumeEventbusTopics ( port int ) {
defer close ( e . busDoneCh )
func ( e * extension ) consumeEventbusTopics ( ec * eventbus . Client , port int ) func ( * eventbus . Client ) {
reqSub := eventbus . Subscribe [ magicsock . UDPRelayAllocReq ] ( ec )
respPub := eventbus . Publish [ magicsock . UDPRelayAllocResp ] ( ec )
debugSessionsCh := e . debugSessionsCh
eventClient := e . bus . Client ( "relayserver.extension" )
reqSub := eventbus . Subscribe [ magicsock . UDPRelayAllocReq ] ( eventClient )
respPub := eventbus . Publish [ magicsock . UDPRelayAllocResp ] ( eventClient )
defer eventClient . Close ( )
var rs relayServer // lazily initialized
defer func ( ) {
if rs != nil {
rs . Close ( )
}
} ( )
for {
select {
case <- e . disconnectFromBusCh :
return
case <- eventClient . Done ( ) :
return
case respCh := <- e . debugSessionsCh :
if rs == nil {
// Don't initialize the server simply for a debug request.
respCh <- nil
continue
return func ( ec * eventbus . Client ) {
var rs relayServer // lazily initialized
defer func ( ) {
if rs != nil {
rs . Close ( )
}
sessions := rs . GetSessions ( )
respCh <- sessions
case req := <- reqSub . Events ( ) :
if rs == nil {
var err error
rs , err = udprelay . NewServer ( e . logf , port , overrideAddrs ( ) )
} ( )
for {
select {
case <- ec . Done ( ) :
return
case respCh := <- debugSessionsCh :
if rs == nil {
// Don't initialize the server simply for a debug request.
respCh <- nil
continue
}
sessions := rs . GetSessions ( )
respCh <- sessions
case req := <- reqSub . Events ( ) :
if rs == nil {
var err error
rs , err = udprelay . NewServer ( e . logf , port , overrideAddrs ( ) )
if err != nil {
e . logf ( "error initializing server: %v" , err )
continue
}
}
se , err := rs . AllocateEndpoint ( req . Message . ClientDisco [ 0 ] , req . Message . ClientDisco [ 1 ] )
if err != nil {
e . logf ( "error initializing server: %v" , err )
e . logf ( "error allocating endpoint : %v", err )
continue
}
}
se , err := rs . AllocateEndpoint ( req . Message . ClientDisco [ 0 ] , req . Message . ClientDisco [ 1 ] )
if err != nil {
e . logf ( "error allocating endpoint: %v" , err )
continue
}
respPub . Publish ( magicsock . UDPRelayAllocResp {
ReqRxFromNodeKey : req . RxFromNodeKey ,
ReqRxFromDiscoKey : req . RxFromDiscoKey ,
Message : & disco . AllocateUDPRelayEndpointResponse {
Generation : req . Message . Generation ,
UDPRelayEndpoint : disco . UDPRelayEndpoint {
ServerDisco : se . ServerDisco ,
ClientDisco : se . ClientDisco ,
LamportID : se . LamportID ,
VNI : se . VNI ,
BindLifetime : se . BindLifetime . Duration ,
SteadyStateLifetime : se . SteadyStateLifetime . Duration ,
AddrPorts : se . AddrPorts ,
respPub . Publish ( magicsock . UDPRelayAllocResp {
ReqRxFromNodeKey : req . RxFromNodeKey ,
ReqRxFromDiscoKey : req . RxFromDiscoKey ,
Message : & disco . AllocateUDPRelayEndpointResponse {
Generation : req . Message . Generation ,
UDPRelayEndpoint : disco . UDPRelayEndpoint {
ServerDisco : se . ServerDisco ,
ClientDisco : se . ClientDisco ,
LamportID : se . LamportID ,
VNI : se . VNI ,
BindLifetime : se . BindLifetime . Duration ,
SteadyStateLifetime : se . SteadyStateLifetime . Duration ,
AddrPorts : se . AddrPorts ,
} ,
} ,
} ,
} )
} )
}
}
}
}
func ( e * extension ) disconnectFromBusLocked ( ) {
if e . busDoneCh != nil {
close ( e . disconnectFromBusCh )
<- e . busDoneCh
e . busDoneCh = nil
e . disconnectFromBusCh = nil
if e . eventSubs != nil {
e . eventSubs . Close ( )
e . eventSubs = nil
e . debugSessionsCh = nil
}
}
@ -270,7 +263,7 @@ func (e *extension) serverStatus() status.ServerStatus {
UDPPort : nil ,
Sessions : nil ,
}
if e . port == nil || e . busDoneCh == nil {
if e . port == nil || e . eventSubs == nil {
return st
}
st . UDPPort = ptr . To ( * e . port )
@ -281,7 +274,7 @@ func (e *extension) serverStatus() status.ServerStatus {
resp := <- ch
st . Sessions = resp
return st
case <- e . busDoneCh :
case <- e . eventSubs. Done ( ) :
return st
}
}