[client] Move ICE and relay workers into the worker package

Relocate WorkerICE (renamed worker.ICE) and WorkerRelay plus ConnPriority
into client/internal/peer/worker. To break the peer<->worker cycle the
workers no longer take *Conn or ConnConfig: callbacks are passed as plain
functions (Conn's unexported methods as method values), and each worker
receives only the fields it needs (key, ICE config, isController) plus a
small services struct. Context is passed to OnNewOffer instead of stored.

Move the worker connection-status helper the other way, out of the worker
package into peer as worker_status.go (WorkerStatus / AtomicWorkerStatus),
since only Conn uses it.
This commit is contained in:
Zoltan Papp
2026-07-11 20:06:46 +02:00
parent 917e85f648
commit 791e8b33ae
7 changed files with 154 additions and 147 deletions
+58 -53
View File
@@ -97,6 +97,10 @@ type ConnConfig struct {
ICEConfig icemaker.Config ICEConfig icemaker.Config
} }
func (c ConnConfig) IsController() bool {
return c.LocalKey > c.Key
}
// Conn represents a connection to a remote peer. All mutable connection state // Conn represents a connection to a remote peer. All mutable connection state
// is owned by a single event loop goroutine started in Open; external callers // is owned by a single event loop goroutine started in Open; external callers
// and the transport workers communicate with the loop by posting events into // and the transport workers communicate with the loop by posting events into
@@ -120,9 +124,9 @@ type Conn struct {
onDisconnected func(remotePeer string) onDisconnected func(remotePeer string)
rosenpassInitializedPresharedKeyValidator func(peerKey string) bool rosenpassInitializedPresharedKeyValidator func(peerKey string) bool
statusRelay *worker.AtomicWorkerStatus statusRelay *AtomicWorkerStatus
statusICE *worker.AtomicWorkerStatus statusICE *AtomicWorkerStatus
currentConnPriority ConnPriority currentConnPriority worker.ConnPriority
opened bool // this flag is used to prevent close in case of not opened connection opened bool // this flag is used to prevent close in case of not opened connection
// mailbox delivers events to the event loop of the current open // mailbox delivers events to the event loop of the current open
@@ -130,8 +134,8 @@ type Conn struct {
mailbox atomic.Pointer[mailbox] mailbox atomic.Pointer[mailbox]
loopDone chan struct{} loopDone chan struct{}
workerICE *WorkerICE workerICE *worker.ICE
workerRelay *WorkerRelay workerRelay *worker.WorkerRelay
// relayDialInFlight and pendingRelayOffer serialize the blocking relay // relayDialInFlight and pendingRelayOffer serialize the blocking relay
// dials spawned by the event loop, keeping only the newest offer while a // dials spawned by the event loop, keeping only the newest offer while a
@@ -189,10 +193,10 @@ func NewConn(config ConnConfig, services ServiceDependencies) (*Conn, error) {
relayManager: services.RelayManager, relayManager: services.RelayManager,
srWatcher: services.SrWatcher, srWatcher: services.SrWatcher,
portForwardManager: services.PortForwardManager, portForwardManager: services.PortForwardManager,
statusRelay: worker.NewAtomicStatus(), statusRelay: NewAtomicStatus(),
statusICE: worker.NewAtomicStatus(), statusICE: NewAtomicStatus(),
dumpState: dumpState, dumpState: dumpState,
endpointUpdater: NewEndpointUpdater(connLog, config.WgConfig, isController(config)), endpointUpdater: NewEndpointUpdater(connLog, config.WgConfig, config.IsController()),
wgWatcher: wg_watcher.NewWGWatcher(connLog, config.WgConfig.WgInterface, config.Key, dumpState), wgWatcher: wg_watcher.NewWGWatcher(connLog, config.WgConfig.WgInterface, config.Key, dumpState),
metricsRecorder: services.MetricsRecorder, metricsRecorder: services.MetricsRecorder,
} }
@@ -226,11 +230,16 @@ func (conn *Conn) open(engineCtx context.Context, firstPacket []byte) error {
conn.ctx, conn.ctxCancel = context.WithCancel(engineCtx) conn.ctx, conn.ctxCancel = context.WithCancel(engineCtx)
conn.workerRelay = NewWorkerRelay(conn.ctx, conn.Log, isController(conn.config), conn.config, conn, conn.relayManager) conn.workerRelay = worker.NewWorkerRelay(conn.Log, conn.config.Key, conn.config.IsController(), conn.onRelayConnectionIsReady, conn.onRelayDisconnected, conn.relayManager)
if !IsForceRelayed() { if !IsForceRelayed() {
relayIsSupportedLocally := conn.workerRelay.RelayIsSupportedLocally() relayIsSupportedLocally := conn.workerRelay.RelayIsSupportedLocally()
workerICE, err := NewWorkerICE(conn.ctx, conn.Log, conn.config, conn, conn.signaler, conn.iFaceDiscover, conn.statusRecorder, conn.portForwardManager, relayIsSupportedLocally) workerICE, err := worker.NewICE(conn.Log, conn.config.Key, conn.config.ICEConfig, conn.config.IsController(), conn.onICEConnectionIsReady, conn.onICEStateDisconnected, worker.ICEDependencies{
Signaler: conn.signaler,
IFaceDiscover: conn.iFaceDiscover,
StatusRecorder: conn.statusRecorder,
PortForwardManager: conn.portForwardManager,
}, relayIsSupportedLocally)
if err != nil { if err != nil {
return err return err
} }
@@ -507,7 +516,7 @@ func (conn *Conn) releaseEvents(evs []event) {
for _, ev := range evs { for _, ev := range evs {
switch e := ev.(type) { switch e := ev.(type) {
case evRelayReady: case evRelayReady:
if err := e.info.relayedConn.Close(); err != nil { if err := e.info.RelayedConn.Close(); err != nil {
conn.Log.Warnf("failed to close unnecessary relayed connection: %v", err) conn.Log.Warnf("failed to close unnecessary relayed connection: %v", err)
} }
case evClose: case evClose:
@@ -558,7 +567,7 @@ func (conn *Conn) dispatchOfferToICE(offer *signaling.OfferAnswer) {
if conn.workerICE == nil || !conn.handshaker.RemoteICESupported() { if conn.workerICE == nil || !conn.handshaker.RemoteICESupported() {
return return
} }
conn.workerICE.OnNewOffer(offer) conn.workerICE.OnNewOffer(conn.ctx, offer)
} }
// dispatchOfferToRelay runs the blocking relay dial on a helper goroutine. A // dispatchOfferToRelay runs the blocking relay dial on a helper goroutine. A
@@ -572,7 +581,7 @@ func (conn *Conn) dispatchOfferToRelay(offer *signaling.OfferAnswer) {
conn.relayDialInFlight = true conn.relayDialInFlight = true
go func() { go func() {
conn.workerRelay.OnNewOffer(offer) conn.workerRelay.OnNewOffer(conn.ctx, offer)
conn.post(evRelayDialDone{}) conn.post(evRelayDialDone{})
}() }()
} }
@@ -598,7 +607,7 @@ func (conn *Conn) handleGuardTick() {
// handleICEReady starts proxying traffic from/to local WireGuard and sets the // handleICEReady starts proxying traffic from/to local WireGuard and sets the
// connection status to StatusConnected. // connection status to StatusConnected.
func (conn *Conn) handleICEReady(priority ConnPriority, iceConnInfo ICEConnInfo) { func (conn *Conn) handleICEReady(priority worker.ConnPriority, iceConnInfo worker.ICEConnInfo) {
if conn.ctx.Err() != nil { if conn.ctx.Err() != nil {
return return
} }
@@ -707,16 +716,16 @@ func (conn *Conn) handleICEDisconnected(sessionChanged bool) {
conn.Log.Errorf("failed to switch to relay conn: %v", err) conn.Log.Errorf("failed to switch to relay conn: %v", err)
} }
conn.currentConnPriority = Relay conn.currentConnPriority = worker.Relay
} else { } else {
conn.Log.Infof("ICE disconnected, do not switch to Relay. Reset priority to: %s", None.String()) conn.Log.Infof("ICE disconnected, do not switch to Relay. Reset priority to: %s", worker.None.String())
conn.currentConnPriority = None conn.currentConnPriority = worker.None
if err := conn.config.WgConfig.WgInterface.RemoveEndpointAddress(conn.config.WgConfig.RemoteKey); err != nil { if err := conn.config.WgConfig.WgInterface.RemoveEndpointAddress(conn.config.WgConfig.RemoteKey); err != nil {
conn.Log.Errorf("failed to remove wg endpoint: %v", err) conn.Log.Errorf("failed to remove wg endpoint: %v", err)
} }
} }
changed := conn.statusICE.Get() != worker.StatusDisconnected changed := conn.statusICE.Get() != WorkerStatusDisconnected
if changed { if changed {
conn.guard.SetICEConnDisconnected() conn.guard.SetICEConnDisconnected()
} }
@@ -724,7 +733,7 @@ func (conn *Conn) handleICEDisconnected(sessionChanged bool) {
conn.disableWgWatcherIfNeeded() conn.disableWgWatcherIfNeeded()
if conn.currentConnPriority == None { if conn.currentConnPriority == worker.None {
conn.metricsStages.Disconnected() conn.metricsStages.Disconnected()
} }
@@ -741,9 +750,9 @@ func (conn *Conn) handleICEDisconnected(sessionChanged bool) {
// handleRelayReady sets up the WireGuard proxy for a freshly opened relayed // handleRelayReady sets up the WireGuard proxy for a freshly opened relayed
// connection and activates it unless ICE has priority. // connection and activates it unless ICE has priority.
func (conn *Conn) handleRelayReady(rci RelayConnInfo) { func (conn *Conn) handleRelayReady(rci worker.RelayConnInfo) {
if conn.ctx.Err() != nil { if conn.ctx.Err() != nil {
if err := rci.relayedConn.Close(); err != nil { if err := rci.RelayedConn.Close(); err != nil {
conn.Log.Warnf("failed to close unnecessary relayed connection: %v", err) conn.Log.Warnf("failed to close unnecessary relayed connection: %v", err)
} }
return return
@@ -752,7 +761,7 @@ func (conn *Conn) handleRelayReady(rci RelayConnInfo) {
conn.dumpState.RelayConnected() conn.dumpState.RelayConnected()
conn.Log.Debugf("Relay connection has been established, setup the WireGuard") conn.Log.Debugf("Relay connection has been established, setup the WireGuard")
wgProxy, err := conn.newProxy(rci.relayedConn) wgProxy, err := conn.newProxy(rci.RelayedConn)
if err != nil { if err != nil {
conn.Log.Errorf("failed to add relayed net.Conn to local proxy: %v", err) conn.Log.Errorf("failed to add relayed net.Conn to local proxy: %v", err)
return return
@@ -767,18 +776,18 @@ func (conn *Conn) handleRelayReady(rci RelayConnInfo) {
conn.Log.Debugf("do not switch to relay because current priority is: %s", conn.currentConnPriority.String()) conn.Log.Debugf("do not switch to relay because current priority is: %s", conn.currentConnPriority.String())
conn.setRelayedProxy(wgProxy) conn.setRelayedProxy(wgProxy)
conn.statusRelay.SetConnected() conn.statusRelay.SetConnected()
conn.updateRelayStatus(rci.relayedConn.RemoteAddr().String(), rci.rosenpassPubKey, time.Now()) conn.updateRelayStatus(rci.RelayedConn.RemoteAddr().String(), rci.RosenpassPubKey, time.Now())
return return
} }
controller := isController(conn.config) controller := conn.config.IsController()
if controller { if controller {
wgProxy.Work() wgProxy.Work()
} }
updateTime := time.Now() updateTime := time.Now()
conn.enableWgWatcherIfNeeded(updateTime) conn.enableWgWatcherIfNeeded(updateTime)
if err := conn.endpointUpdater.ConfigureWGEndpoint(wgProxy.EndpointAddr(), conn.presharedKey(rci.rosenpassPubKey)); err != nil { if err := conn.endpointUpdater.ConfigureWGEndpoint(wgProxy.EndpointAddr(), conn.presharedKey(rci.RosenpassPubKey)); err != nil {
if err := wgProxy.CloseConn(); err != nil { if err := wgProxy.CloseConn(); err != nil {
conn.Log.Warnf("Failed to close relay connection: %v", err) conn.Log.Warnf("Failed to close relay connection: %v", err)
} }
@@ -793,13 +802,13 @@ func (conn *Conn) handleRelayReady(rci RelayConnInfo) {
conn.injectPendingFirstPacket(wgProxy, nil) conn.injectPendingFirstPacket(wgProxy, nil)
conn.rosenpassRemoteKey = rci.rosenpassPubKey conn.rosenpassRemoteKey = rci.RosenpassPubKey
conn.currentConnPriority = Relay conn.currentConnPriority = worker.Relay
conn.statusRelay.SetConnected() conn.statusRelay.SetConnected()
conn.setRelayedProxy(wgProxy) conn.setRelayedProxy(wgProxy)
conn.updateRelayStatus(rci.relayedConn.RemoteAddr().String(), rci.rosenpassPubKey, updateTime) conn.updateRelayStatus(rci.RelayedConn.RemoteAddr().String(), rci.RosenpassPubKey, updateTime)
conn.Log.Infof("start to communicate with peer via relay") conn.Log.Infof("start to communicate with peer via relay")
conn.doOnConnected(rci.rosenpassPubKey, rci.rosenpassAddr, updateTime) conn.doOnConnected(rci.RosenpassPubKey, rci.RosenpassAddr, updateTime)
} }
// handleRelayDisconnected cleans up the relayed transport and the WireGuard // handleRelayDisconnected cleans up the relayed transport and the WireGuard
@@ -811,9 +820,9 @@ func (conn *Conn) handleRelayDisconnected() {
conn.Log.Debugf("relay connection is disconnected") conn.Log.Debugf("relay connection is disconnected")
if conn.currentConnPriority == Relay { if conn.currentConnPriority == worker.Relay {
conn.Log.Debugf("clean up WireGuard config") conn.Log.Debugf("clean up WireGuard config")
conn.currentConnPriority = None conn.currentConnPriority = worker.None
if err := conn.config.WgConfig.WgInterface.RemoveEndpointAddress(conn.config.WgConfig.RemoteKey); err != nil { if err := conn.config.WgConfig.WgInterface.RemoveEndpointAddress(conn.config.WgConfig.RemoteKey); err != nil {
conn.Log.Errorf("failed to remove wg endpoint: %v", err) conn.Log.Errorf("failed to remove wg endpoint: %v", err)
} }
@@ -824,7 +833,7 @@ func (conn *Conn) handleRelayDisconnected() {
conn.wgProxyRelay = nil conn.wgProxyRelay = nil
} }
changed := conn.statusRelay.Get() != worker.StatusDisconnected changed := conn.statusRelay.Get() != WorkerStatusDisconnected
if changed { if changed {
conn.guard.SetRelayedConnDisconnected() conn.guard.SetRelayedConnDisconnected()
} }
@@ -832,7 +841,7 @@ func (conn *Conn) handleRelayDisconnected() {
conn.disableWgWatcherIfNeeded() conn.disableWgWatcherIfNeeded()
if conn.currentConnPriority == None { if conn.currentConnPriority == worker.None {
conn.metricsStages.Disconnected() conn.metricsStages.Disconnected()
} }
@@ -858,10 +867,10 @@ func (conn *Conn) handleWGTimeout() {
// Close the active connection based on current priority // Close the active connection based on current priority
switch conn.currentConnPriority { switch conn.currentConnPriority {
case Relay: case worker.Relay:
conn.workerRelay.CloseConn() conn.workerRelay.CloseConn()
conn.handleRelayDisconnected() conn.handleRelayDisconnected()
case ICEP2P, ICETurn: case worker.ICEP2P, worker.ICETurn:
conn.workerICE.Close() conn.workerICE.Close()
default: default:
conn.Log.Debugf("No active connection to close on WG timeout") conn.Log.Debugf("No active connection to close on WG timeout")
@@ -900,7 +909,7 @@ func (conn *Conn) handleWGCheckSuccess() {
conn.wgTimeouts = 0 conn.wgTimeouts = 0
} }
func (conn *Conn) onICEConnectionIsReady(priority ConnPriority, iceConnInfo ICEConnInfo) { func (conn *Conn) onICEConnectionIsReady(priority worker.ConnPriority, iceConnInfo worker.ICEConnInfo) {
conn.post(evICEReady{priority: priority, info: iceConnInfo}) conn.post(evICEReady{priority: priority, info: iceConnInfo})
} }
@@ -910,11 +919,11 @@ func (conn *Conn) onICEStateDisconnected(sessionChanged bool) {
// onRelayConnectionIsReady closes the relayed connection when the event loop // onRelayConnectionIsReady closes the relayed connection when the event loop
// is gone and nobody will take ownership of it. // is gone and nobody will take ownership of it.
func (conn *Conn) onRelayConnectionIsReady(rci RelayConnInfo) { func (conn *Conn) onRelayConnectionIsReady(rci worker.RelayConnInfo) {
if conn.post(evRelayReady{info: rci}) { if conn.post(evRelayReady{info: rci}) {
return return
} }
if err := rci.relayedConn.Close(); err != nil { if err := rci.RelayedConn.Close(); err != nil {
conn.Log.Warnf("failed to close unnecessary relayed connection: %v", err) conn.Log.Warnf("failed to close unnecessary relayed connection: %v", err)
} }
} }
@@ -984,7 +993,7 @@ func (conn *Conn) updateRelayStatus(relayServerAddr string, rosenpassPubKey []by
} }
} }
func (conn *Conn) updateIceState(iceConnInfo ICEConnInfo, updateTime time.Time) { func (conn *Conn) updateIceState(iceConnInfo worker.ICEConnInfo, updateTime time.Time) {
peerState := status.State{ peerState := status.State{
PubKey: conn.config.Key, PubKey: conn.config.Key,
ConnStatusUpdate: updateTime, ConnStatusUpdate: updateTime,
@@ -1006,7 +1015,7 @@ func (conn *Conn) updateIceState(iceConnInfo ICEConnInfo, updateTime time.Time)
func (conn *Conn) setStatusToDisconnected() { func (conn *Conn) setStatusToDisconnected() {
conn.statusRelay.SetDisconnected() conn.statusRelay.SetDisconnected()
conn.statusICE.SetDisconnected() conn.statusICE.SetDisconnected()
conn.currentConnPriority = None conn.currentConnPriority = worker.None
peerState := status.State{ peerState := status.State{
PubKey: conn.config.Key, PubKey: conn.config.Key,
@@ -1039,7 +1048,7 @@ func (conn *Conn) doOnConnected(remoteRosenpassPubKey []byte, remoteRosenpassAdd
func (conn *Conn) isRelayed() bool { func (conn *Conn) isRelayed() bool {
switch conn.currentConnPriority { switch conn.currentConnPriority {
case Relay, ICETurn: case worker.Relay, worker.ICETurn:
return true return true
default: default:
return false return false
@@ -1047,7 +1056,7 @@ func (conn *Conn) isRelayed() bool {
} }
func (conn *Conn) evalStatus() status.ConnStatus { func (conn *Conn) evalStatus() status.ConnStatus {
if conn.statusRelay.Get() == worker.StatusConnected || conn.statusICE.Get() == worker.StatusConnected { if conn.statusRelay.Get() == WorkerStatusConnected || conn.statusICE.Get() == WorkerStatusConnected {
return status.StatusConnected return status.StatusConnected
} }
@@ -1077,10 +1086,10 @@ func (conn *Conn) isConnectedOnAllWay() (status guard.ConnStatus) {
return evalConnStatus(connStatusInputs{ return evalConnStatus(connStatusInputs{
forceRelay: IsForceRelayed(), forceRelay: IsForceRelayed(),
peerUsesRelay: conn.workerRelay.IsRelayConnectionSupportedWithPeer(), peerUsesRelay: conn.workerRelay.IsRelayConnectionSupportedWithPeer(),
relayConnected: conn.statusRelay.Get() == worker.StatusConnected, relayConnected: conn.statusRelay.Get() == WorkerStatusConnected,
remoteSupportsICE: conn.handshaker.RemoteICESupported(), remoteSupportsICE: conn.handshaker.RemoteICESupported(),
iceWorkerCreated: iceWorkerCreated, iceWorkerCreated: iceWorkerCreated,
iceStatusConnecting: conn.statusICE.Get() != worker.StatusDisconnected, iceStatusConnecting: conn.statusICE.Get() != WorkerStatusDisconnected,
iceInProgress: iceInProgress, iceInProgress: iceInProgress,
}) })
} }
@@ -1100,7 +1109,7 @@ func (conn *Conn) enableWgWatcherIfNeeded(enabledTime time.Time) {
} }
func (conn *Conn) disableWgWatcherIfNeeded() { func (conn *Conn) disableWgWatcherIfNeeded() {
if conn.currentConnPriority == None && conn.wgWatcherCancel != nil { if conn.currentConnPriority == worker.None && conn.wgWatcherCancel != nil {
conn.wgWatcherCancel() conn.wgWatcherCancel()
conn.wgWatcherCancel = nil conn.wgWatcherCancel = nil
} }
@@ -1122,7 +1131,7 @@ func (conn *Conn) newProxy(remoteConn net.Conn) (wgproxy.Proxy, error) {
} }
func (conn *Conn) resetEndpoint() { func (conn *Conn) resetEndpoint() {
if !isController(conn.config) { if !conn.config.IsController() {
return return
} }
conn.Log.Infof("reset wg endpoint") conn.Log.Infof("reset wg endpoint")
@@ -1133,11 +1142,11 @@ func (conn *Conn) resetEndpoint() {
} }
func (conn *Conn) isReadyToUpgrade() bool { func (conn *Conn) isReadyToUpgrade() bool {
return conn.wgProxyRelay != nil && conn.currentConnPriority != Relay return conn.wgProxyRelay != nil && conn.currentConnPriority != worker.Relay
} }
func (conn *Conn) isICEActive() bool { func (conn *Conn) isICEActive() bool {
return (conn.currentConnPriority == ICEP2P || conn.currentConnPriority == ICETurn) && conn.statusICE.Get() == worker.StatusConnected return (conn.currentConnPriority == worker.ICEP2P || conn.currentConnPriority == worker.ICETurn) && conn.statusICE.Get() == WorkerStatusConnected
} }
func (conn *Conn) handleConfigurationFailure(err error, wgProxy wgproxy.Proxy) { func (conn *Conn) handleConfigurationFailure(err error, wgProxy wgproxy.Proxy) {
@@ -1177,7 +1186,7 @@ func (conn *Conn) recordConnectionMetrics() {
var connType metrics.ConnectionType var connType metrics.ConnectionType
switch conn.currentConnPriority { switch conn.currentConnPriority {
case Relay: case worker.Relay:
connType = metrics.ConnectionTypeRelay connType = metrics.ConnectionTypeRelay
default: default:
connType = metrics.ConnectionTypeICE connType = metrics.ConnectionTypeICE
@@ -1225,10 +1234,6 @@ func (conn *Conn) presharedKey(remoteRosenpassKey []byte) *wgtypes.Key {
return determKey return determKey
} }
func isController(config ConnConfig) bool {
return config.LocalKey > config.Key
}
func isRosenpassEnabled(remoteRosenpassPubKey []byte) bool { func isRosenpassEnabled(remoteRosenpassPubKey []byte) bool {
return remoteRosenpassPubKey != nil return remoteRosenpassPubKey != nil
} }
+1 -1
View File
@@ -8,7 +8,7 @@ type connStatusInputs struct {
peerUsesRelay bool // remote peer advertises relay support AND local has relay peerUsesRelay bool // remote peer advertises relay support AND local has relay
relayConnected bool // statusRelay reports Connected (independent of whether peer uses relay) relayConnected bool // statusRelay reports Connected (independent of whether peer uses relay)
remoteSupportsICE bool // remote peer sent ICE credentials remoteSupportsICE bool // remote peer sent ICE credentials
iceWorkerCreated bool // local WorkerICE exists (false in force-relay mode) iceWorkerCreated bool // local ICE worker exists (false in force-relay mode)
iceStatusConnecting bool // statusICE is anything other than Disconnected iceStatusConnecting bool // statusICE is anything other than Disconnected
iceInProgress bool // a negotiation is currently in flight iceInProgress bool // a negotiation is currently in flight
} }
+4 -3
View File
@@ -6,6 +6,7 @@ import (
"github.com/pion/ice/v4" "github.com/pion/ice/v4"
"github.com/netbirdio/netbird/client/internal/peer/signaling" "github.com/netbirdio/netbird/client/internal/peer/signaling"
"github.com/netbirdio/netbird/client/internal/peer/worker"
"github.com/netbirdio/netbird/route" "github.com/netbirdio/netbird/route"
) )
@@ -35,8 +36,8 @@ type evRemoteCandidate struct {
} }
type evICEReady struct { type evICEReady struct {
priority ConnPriority priority worker.ConnPriority
info ICEConnInfo info worker.ICEConnInfo
} }
type evICEDown struct { type evICEDown struct {
@@ -44,7 +45,7 @@ type evICEDown struct {
} }
type evRelayReady struct { type evRelayReady struct {
info RelayConnInfo info worker.RelayConnInfo
} }
type evRelayDown struct{} type evRelayDown struct{}
@@ -1,4 +1,4 @@
package peer package worker
import ( import (
"fmt" "fmt"
@@ -1,4 +1,4 @@
package peer package worker
import ( import (
"context" "context"
@@ -21,11 +21,6 @@ import (
"github.com/netbirdio/netbird/route" "github.com/netbirdio/netbird/route"
) )
type iceCallbacks interface {
onICEConnectionIsReady(priority ConnPriority, iceConnInfo ICEConnInfo)
onICEStateDisconnected(sessionChanged bool)
}
type ICEConnInfo struct { type ICEConnInfo struct {
RemoteConn net.Conn RemoteConn net.Conn
RosenpassPubKey []byte RosenpassPubKey []byte
@@ -38,11 +33,20 @@ type ICEConnInfo struct {
RelayedOnLocal bool RelayedOnLocal bool
} }
type WorkerICE struct { type ICEDependencies struct {
ctx context.Context Signaler *signaling.Signaler
IFaceDiscover stdnet.ExternalIFaceDiscover
StatusRecorder *status.Recorder
PortForwardManager *portforward.Manager
}
type ICE struct {
log *log.Entry log *log.Entry
config ConnConfig key string
conn iceCallbacks iceConfig icemaker.Config
isController bool
onConnReady func(priority ConnPriority, iceConnInfo ICEConnInfo)
onStatusDisconnect func(sessionChanged bool)
signaler *signaling.Signaler signaler *signaling.Signaler
iFaceDiscover stdnet.ExternalIFaceDiscover iFaceDiscover stdnet.ExternalIFaceDiscover
statusRecorder *status.Recorder statusRecorder *status.Recorder
@@ -72,21 +76,23 @@ type WorkerICE struct {
portForwardAttempted bool portForwardAttempted bool
} }
func NewWorkerICE(ctx context.Context, log *log.Entry, config ConnConfig, conn iceCallbacks, signaler *signaling.Signaler, ifaceDiscover stdnet.ExternalIFaceDiscover, statusRecorder *status.Recorder, portForwardManager *portforward.Manager, hasRelayOnLocally bool) (*WorkerICE, error) { func NewICE(log *log.Entry, key string, iceConfig icemaker.Config, isController bool, onConnReady func(ConnPriority, ICEConnInfo), onStatusDisconnect func(bool), services ICEDependencies, hasRelayOnLocally bool) (*ICE, error) {
sessionID, err := icemaker.NewSessionID() sessionID, err := icemaker.NewSessionID()
if err != nil { if err != nil {
return nil, err return nil, err
} }
w := &WorkerICE{ w := &ICE{
ctx: ctx,
log: log, log: log,
config: config, key: key,
conn: conn, iceConfig: iceConfig,
signaler: signaler, isController: isController,
iFaceDiscover: ifaceDiscover, onConnReady: onConnReady,
statusRecorder: statusRecorder, onStatusDisconnect: onStatusDisconnect,
portForwardManager: portForwardManager, signaler: services.Signaler,
iFaceDiscover: services.IFaceDiscover,
statusRecorder: services.StatusRecorder,
portForwardManager: services.PortForwardManager,
hasRelayOnLocally: hasRelayOnLocally, hasRelayOnLocally: hasRelayOnLocally,
sessionID: sessionID, sessionID: sessionID,
} }
@@ -100,7 +106,7 @@ func NewWorkerICE(ctx context.Context, log *log.Entry, config ConnConfig, conn i
return w, nil return w, nil
} }
func (w *WorkerICE) OnNewOffer(remoteOfferAnswer *signaling.OfferAnswer) { func (w *ICE) OnNewOffer(ctx context.Context, remoteOfferAnswer *signaling.OfferAnswer) {
w.log.Debugf("OnNewOffer for ICE, serial: %s", remoteOfferAnswer.SessionIDString()) w.log.Debugf("OnNewOffer for ICE, serial: %s", remoteOfferAnswer.SessionIDString())
w.muxAgent.Lock() w.muxAgent.Lock()
defer w.muxAgent.Unlock() defer w.muxAgent.Unlock()
@@ -142,8 +148,8 @@ func (w *WorkerICE) OnNewOffer(remoteOfferAnswer *signaling.OfferAnswer) {
if remoteOfferAnswer.SessionID != nil { if remoteOfferAnswer.SessionID != nil {
w.log.Debugf("recreate ICE agent: %s / %s", w.sessionID, *remoteOfferAnswer.SessionID) w.log.Debugf("recreate ICE agent: %s / %s", w.sessionID, *remoteOfferAnswer.SessionID)
} }
dialerCtx, dialerCancel := context.WithCancel(w.ctx) dialerCtx, dialerCancel := context.WithCancel(ctx)
agent, err := w.reCreateAgent(dialerCancel, preferredCandidateTypes) agent, err := w.reCreateAgent(ctx, dialerCancel, preferredCandidateTypes)
if err != nil { if err != nil {
w.log.Errorf("failed to recreate ICE Agent: %s", err) w.log.Errorf("failed to recreate ICE Agent: %s", err)
return return
@@ -161,10 +167,10 @@ func (w *WorkerICE) OnNewOffer(remoteOfferAnswer *signaling.OfferAnswer) {
} }
// OnRemoteCandidate Handles ICE connection Candidate provided by the remote peer. // OnRemoteCandidate Handles ICE connection Candidate provided by the remote peer.
func (w *WorkerICE) OnRemoteCandidate(candidate ice.Candidate, haRoutes route.HAMap) { func (w *ICE) OnRemoteCandidate(candidate ice.Candidate, haRoutes route.HAMap) {
w.muxAgent.Lock() w.muxAgent.Lock()
defer w.muxAgent.Unlock() defer w.muxAgent.Unlock()
w.log.Debugf("OnRemoteCandidate from peer %s -> %s", w.config.Key, candidate.String()) w.log.Debugf("OnRemoteCandidate from peer %s -> %s", w.key, candidate.String())
if w.agent == nil { if w.agent == nil {
w.log.Warnf("ICE Agent is not initialized yet") w.log.Warnf("ICE Agent is not initialized yet")
return return
@@ -191,7 +197,7 @@ func (w *WorkerICE) OnRemoteCandidate(candidate ice.Candidate, haRoutes route.HA
} }
} }
func (w *WorkerICE) Credentials() signaling.Credentials { func (w *ICE) Credentials() signaling.Credentials {
w.muxAgent.Lock() w.muxAgent.Lock()
defer w.muxAgent.Unlock() defer w.muxAgent.Unlock()
return signaling.Credentials{ return signaling.Credentials{
@@ -201,14 +207,14 @@ func (w *WorkerICE) Credentials() signaling.Credentials {
} }
} }
func (w *WorkerICE) InProgress() bool { func (w *ICE) InProgress() bool {
w.muxAgent.Lock() w.muxAgent.Lock()
defer w.muxAgent.Unlock() defer w.muxAgent.Unlock()
return w.agentConnecting return w.agentConnecting
} }
func (w *WorkerICE) Close() { func (w *ICE) Close() {
w.muxAgent.Lock() w.muxAgent.Lock()
defer w.muxAgent.Unlock() defer w.muxAgent.Unlock()
@@ -224,10 +230,10 @@ func (w *WorkerICE) Close() {
w.agent = nil w.agent = nil
} }
func (w *WorkerICE) reCreateAgent(dialerCancel context.CancelFunc, candidates []ice.CandidateType) (*icemaker.ThreadSafeAgent, error) { func (w *ICE) reCreateAgent(ctx context.Context, dialerCancel context.CancelFunc, candidates []ice.CandidateType) (*icemaker.ThreadSafeAgent, error) {
w.portForwardAttempted = false w.portForwardAttempted = false
agent, err := icemaker.NewAgent(w.ctx, w.iFaceDiscover, w.config.ICEConfig, candidates, w.localUfrag, w.localPwd) agent, err := icemaker.NewAgent(ctx, w.iFaceDiscover, w.iceConfig, candidates, w.localUfrag, w.localPwd)
if err != nil { if err != nil {
return nil, fmt.Errorf("create agent: %w", err) return nil, fmt.Errorf("create agent: %w", err)
} }
@@ -249,7 +255,7 @@ func (w *WorkerICE) reCreateAgent(dialerCancel context.CancelFunc, candidates []
return agent, nil return agent, nil
} }
func (w *WorkerICE) getSessionID() icemaker.SessionID { func (w *ICE) getSessionID() icemaker.SessionID {
w.muxAgent.Lock() w.muxAgent.Lock()
defer w.muxAgent.Unlock() defer w.muxAgent.Unlock()
@@ -259,7 +265,7 @@ func (w *WorkerICE) getSessionID() icemaker.SessionID {
// will block until connection succeeded // will block until connection succeeded
// but it won't release if ICE Agent went into Disconnected or Failed state, // but it won't release if ICE Agent went into Disconnected or Failed state,
// so we have to cancel it with the provided context once agent detected a broken connection // so we have to cancel it with the provided context once agent detected a broken connection
func (w *WorkerICE) connect(ctx context.Context, dialerCancel context.CancelFunc, agent *icemaker.ThreadSafeAgent, remoteOfferAnswer *signaling.OfferAnswer) { func (w *ICE) connect(ctx context.Context, dialerCancel context.CancelFunc, agent *icemaker.ThreadSafeAgent, remoteOfferAnswer *signaling.OfferAnswer) {
w.log.Debugf("gather candidates") w.log.Debugf("gather candidates")
if err := agent.GatherCandidates(); err != nil { if err := agent.GatherCandidates(); err != nil {
w.log.Warnf("failed to gather candidates: %s", err) w.log.Warnf("failed to gather candidates: %s", err)
@@ -323,10 +329,10 @@ func (w *WorkerICE) connect(ctx context.Context, dialerCancel context.CancelFunc
w.muxAgent.Unlock() w.muxAgent.Unlock()
w.log.Infof("connection succeeded with offer session: %s", remoteOfferAnswer.SessionIDString()) w.log.Infof("connection succeeded with offer session: %s", remoteOfferAnswer.SessionIDString())
w.conn.onICEConnectionIsReady(selectedPriority(pair), ci) w.onConnReady(selectedPriority(pair), ci)
} }
func (w *WorkerICE) closeAgent(agent *icemaker.ThreadSafeAgent, cancel context.CancelFunc) bool { func (w *ICE) closeAgent(agent *icemaker.ThreadSafeAgent, cancel context.CancelFunc) bool {
cancel() cancel()
if err := agent.Close(); err != nil { if err := agent.Close(); err != nil {
w.log.Warnf("failed to close ICE agent: %s", err) w.log.Warnf("failed to close ICE agent: %s", err)
@@ -352,7 +358,7 @@ func (w *WorkerICE) closeAgent(agent *icemaker.ThreadSafeAgent, cancel context.C
return sessionChanged return sessionChanged
} }
func (w *WorkerICE) punchRemoteWGPort(pair *ice.CandidatePair, remoteWgPort int) { func (w *ICE) punchRemoteWGPort(pair *ice.CandidatePair, remoteWgPort int) {
// wait local endpoint configuration // wait local endpoint configuration
time.Sleep(time.Second) time.Sleep(time.Second)
addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(pair.Remote.Address(), strconv.Itoa(remoteWgPort))) addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(pair.Remote.Address(), strconv.Itoa(remoteWgPort)))
@@ -361,7 +367,7 @@ func (w *WorkerICE) punchRemoteWGPort(pair *ice.CandidatePair, remoteWgPort int)
return return
} }
mux, ok := w.config.ICEConfig.UDPMuxSrflx.(*udpmux.UniversalUDPMuxDefault) mux, ok := w.iceConfig.UDPMuxSrflx.(*udpmux.UniversalUDPMuxDefault)
if !ok { if !ok {
w.log.Warn("invalid udp mux conversion") w.log.Warn("invalid udp mux conversion")
return return
@@ -374,7 +380,7 @@ func (w *WorkerICE) punchRemoteWGPort(pair *ice.CandidatePair, remoteWgPort int)
// onICECandidate is a callback attached to an ICE Agent to receive new local connection candidates // onICECandidate is a callback attached to an ICE Agent to receive new local connection candidates
// and then signals them to the remote peer // and then signals them to the remote peer
func (w *WorkerICE) onICECandidate(candidate ice.Candidate) { func (w *ICE) onICECandidate(candidate ice.Candidate) {
// nil means candidate gathering has been ended // nil means candidate gathering has been ended
if candidate == nil { if candidate == nil {
return return
@@ -383,9 +389,9 @@ func (w *WorkerICE) onICECandidate(candidate ice.Candidate) {
// TODO: reported port is incorrect for CandidateTypeHost, makes understanding ICE use via logs confusing as port is ignored // TODO: reported port is incorrect for CandidateTypeHost, makes understanding ICE use via logs confusing as port is ignored
w.log.Debugf("discovered local candidate %s", candidate.String()) w.log.Debugf("discovered local candidate %s", candidate.String())
go func() { go func() {
err := w.signaler.SignalICECandidate(candidate, w.config.Key) err := w.signaler.SignalICECandidate(candidate, w.key)
if err != nil { if err != nil {
w.log.Errorf("failed signaling candidate to the remote peer %s %s", w.config.Key, err) w.log.Errorf("failed signaling candidate to the remote peer %s %s", w.key, err)
} }
}() }()
@@ -395,7 +401,7 @@ func (w *WorkerICE) onICECandidate(candidate ice.Candidate) {
} }
// injectPortForwardedCandidate signals an additional candidate using the pre-created port mapping. // injectPortForwardedCandidate signals an additional candidate using the pre-created port mapping.
func (w *WorkerICE) injectPortForwardedCandidate(srflxCandidate ice.Candidate) { func (w *ICE) injectPortForwardedCandidate(srflxCandidate ice.Candidate) {
pfManager := w.portForwardManager pfManager := w.portForwardManager
if pfManager == nil { if pfManager == nil {
return return
@@ -424,7 +430,7 @@ func (w *WorkerICE) injectPortForwardedCandidate(srflxCandidate ice.Candidate) {
forwardedCandidate.String(), mapping.InternalPort, mapping.ExternalPort, mapping.NATType, forwardedCandidate.Priority()) forwardedCandidate.String(), mapping.InternalPort, mapping.ExternalPort, mapping.NATType, forwardedCandidate.Priority())
go func() { go func() {
if err := w.signaler.SignalICECandidate(forwardedCandidate, w.config.Key); err != nil { if err := w.signaler.SignalICECandidate(forwardedCandidate, w.key); err != nil {
w.log.Errorf("signal port-forwarded candidate: %v", err) w.log.Errorf("signal port-forwarded candidate: %v", err)
} }
}() }()
@@ -432,7 +438,7 @@ func (w *WorkerICE) injectPortForwardedCandidate(srflxCandidate ice.Candidate) {
// createForwardedCandidate creates a new server reflexive candidate with the forwarded port. // createForwardedCandidate creates a new server reflexive candidate with the forwarded port.
// It uses the NAT gateway's external IP with the forwarded port. // It uses the NAT gateway's external IP with the forwarded port.
func (w *WorkerICE) createForwardedCandidate(srflxCandidate ice.Candidate, mapping *portforward.Mapping) (ice.Candidate, error) { func (w *ICE) createForwardedCandidate(srflxCandidate ice.Candidate, mapping *portforward.Mapping) (ice.Candidate, error) {
var externalIP string var externalIP string
if mapping.ExternalIP != nil && !mapping.ExternalIP.IsUnspecified() { if mapping.ExternalIP != nil && !mapping.ExternalIP.IsUnspecified() {
externalIP = mapping.ExternalIP.String() externalIP = mapping.ExternalIP.String()
@@ -477,9 +483,9 @@ func (w *WorkerICE) createForwardedCandidate(srflxCandidate ice.Candidate, mappi
return candidate, nil return candidate, nil
} }
func (w *WorkerICE) onICESelectedCandidatePair(agent *icemaker.ThreadSafeAgent, c1, c2 ice.Candidate) { func (w *ICE) onICESelectedCandidatePair(agent *icemaker.ThreadSafeAgent, c1, c2 ice.Candidate) {
w.log.Debugf("selected candidate pair [local <-> remote] -> [%s <-> %s], peer %s", c1.String(), c2.String(), w.log.Debugf("selected candidate pair [local <-> remote] -> [%s <-> %s], peer %s", c1.String(), c2.String(),
w.config.Key) w.key)
pairStat, ok := agent.GetSelectedCandidatePairStats() pairStat, ok := agent.GetSelectedCandidatePairStats()
if !ok { if !ok {
@@ -488,13 +494,13 @@ func (w *WorkerICE) onICESelectedCandidatePair(agent *icemaker.ThreadSafeAgent,
} }
duration := time.Duration(pairStat.CurrentRoundTripTime * float64(time.Second)) duration := time.Duration(pairStat.CurrentRoundTripTime * float64(time.Second))
if err := w.statusRecorder.UpdateLatency(w.config.Key, duration); err != nil { if err := w.statusRecorder.UpdateLatency(w.key, duration); err != nil {
w.log.Debugf("failed to update latency for peer: %s", err) w.log.Debugf("failed to update latency for peer: %s", err)
return return
} }
} }
func (w *WorkerICE) logSuccessfulPaths(agent *icemaker.ThreadSafeAgent) { func (w *ICE) logSuccessfulPaths(agent *icemaker.ThreadSafeAgent) {
sessionID := w.getSessionID() sessionID := w.getSessionID()
stats := agent.GetCandidatePairsStats() stats := agent.GetCandidatePairsStats()
localCandidates, _ := agent.GetLocalCandidates() localCandidates, _ := agent.GetLocalCandidates()
@@ -525,7 +531,7 @@ func (w *WorkerICE) logSuccessfulPaths(agent *icemaker.ThreadSafeAgent) {
} }
} }
func (w *WorkerICE) onConnectionStateChange(agent *icemaker.ThreadSafeAgent, dialerCancel context.CancelFunc) func(ice.ConnectionState) { func (w *ICE) onConnectionStateChange(agent *icemaker.ThreadSafeAgent, dialerCancel context.CancelFunc) func(ice.ConnectionState) {
// per-agent state; pion delivers callbacks of one agent sequentially // per-agent state; pion delivers callbacks of one agent sequentially
var connected bool var connected bool
return func(state ice.ConnectionState) { return func(state ice.ConnectionState) {
@@ -556,13 +562,13 @@ func (w *WorkerICE) onConnectionStateChange(agent *icemaker.ThreadSafeAgent, dia
w.log.Debugf("suppress disconnected event of replaced ICE agent") w.log.Debugf("suppress disconnected event of replaced ICE agent")
return return
} }
w.conn.onICEStateDisconnected(sessionChanged) w.onStatusDisconnect(sessionChanged)
} }
} }
} }
func (w *WorkerICE) turnAgentDial(ctx context.Context, agent *icemaker.ThreadSafeAgent, remoteOfferAnswer *signaling.OfferAnswer) (*ice.Conn, error) { func (w *ICE) turnAgentDial(ctx context.Context, agent *icemaker.ThreadSafeAgent, remoteOfferAnswer *signaling.OfferAnswer) (*ice.Conn, error) {
if isController(w.config) { if w.isController {
return agent.Dial(ctx, remoteOfferAnswer.IceCredentials.UFrag, remoteOfferAnswer.IceCredentials.Pwd) return agent.Dial(ctx, remoteOfferAnswer.IceCredentials.UFrag, remoteOfferAnswer.IceCredentials.Pwd)
} else { } else {
return agent.Accept(ctx, remoteOfferAnswer.IceCredentials.UFrag, remoteOfferAnswer.IceCredentials.Pwd) return agent.Accept(ctx, remoteOfferAnswer.IceCredentials.UFrag, remoteOfferAnswer.IceCredentials.Pwd)
@@ -1,4 +1,4 @@
package peer package worker
import ( import (
"context" "context"
@@ -15,23 +15,18 @@ import (
) )
type RelayConnInfo struct { type RelayConnInfo struct {
relayedConn net.Conn RelayedConn net.Conn
rosenpassPubKey []byte RosenpassPubKey []byte
rosenpassAddr string RosenpassAddr string
}
type relayCallbacks interface {
onRelayConnectionIsReady(rci RelayConnInfo)
onRelayDisconnected()
} }
type WorkerRelay struct { type WorkerRelay struct {
peerCtx context.Context log *log.Entry
log *log.Entry key string
isController bool isController bool
config ConnConfig onConnReady func(RelayConnInfo)
conn relayCallbacks onDisconnected func()
relayManager *relayClient.Manager relayManager *relayClient.Manager
relayedConn net.Conn relayedConn net.Conn
relayLock sync.Mutex relayLock sync.Mutex
@@ -39,19 +34,19 @@ type WorkerRelay struct {
relaySupportedOnRemotePeer atomic.Bool relaySupportedOnRemotePeer atomic.Bool
} }
func NewWorkerRelay(ctx context.Context, log *log.Entry, ctrl bool, config ConnConfig, conn relayCallbacks, relayManager *relayClient.Manager) *WorkerRelay { func NewWorkerRelay(log *log.Entry, key string, isController bool, onConnReady func(RelayConnInfo), onDisconnected func(), relayManager *relayClient.Manager) *WorkerRelay {
r := &WorkerRelay{ r := &WorkerRelay{
peerCtx: ctx, log: log,
log: log, key: key,
isController: ctrl, isController: isController,
config: config, onConnReady: onConnReady,
conn: conn, onDisconnected: onDisconnected,
relayManager: relayManager, relayManager: relayManager,
} }
return r return r
} }
func (w *WorkerRelay) OnNewOffer(remoteOfferAnswer *signaling.OfferAnswer) { func (w *WorkerRelay) OnNewOffer(ctx context.Context, remoteOfferAnswer *signaling.OfferAnswer) {
if !w.isRelaySupported(remoteOfferAnswer) { if !w.isRelaySupported(remoteOfferAnswer) {
w.log.Infof("Relay is not supported by remote peer") w.log.Infof("Relay is not supported by remote peer")
w.relaySupportedOnRemotePeer.Store(false) w.relaySupportedOnRemotePeer.Store(false)
@@ -72,7 +67,7 @@ func (w *WorkerRelay) OnNewOffer(remoteOfferAnswer *signaling.OfferAnswer) {
serverIP = remoteOfferAnswer.RelaySrvIP serverIP = remoteOfferAnswer.RelaySrvIP
} }
relayedConn, err := w.relayManager.OpenConn(w.peerCtx, srv, w.config.Key, serverIP) relayedConn, err := w.relayManager.OpenConn(ctx, srv, w.key, serverIP)
if err != nil { if err != nil {
if errors.Is(err, relayClient.ErrConnAlreadyExists) { if errors.Is(err, relayClient.ErrConnAlreadyExists) {
w.log.Debugf("handled offer by reusing existing relay connection") w.log.Debugf("handled offer by reusing existing relay connection")
@@ -94,10 +89,10 @@ func (w *WorkerRelay) OnNewOffer(remoteOfferAnswer *signaling.OfferAnswer) {
} }
w.log.Debugf("peer conn opened via Relay: %s", srv) w.log.Debugf("peer conn opened via Relay: %s", srv)
w.conn.onRelayConnectionIsReady(RelayConnInfo{ w.onConnReady(RelayConnInfo{
relayedConn: relayedConn, RelayedConn: relayedConn,
rosenpassPubKey: remoteOfferAnswer.RosenpassPubKey, RosenpassPubKey: remoteOfferAnswer.RosenpassPubKey,
rosenpassAddr: remoteOfferAnswer.RosenpassAddr, RosenpassAddr: remoteOfferAnswer.RosenpassAddr,
}) })
} }
@@ -140,5 +135,5 @@ func (w *WorkerRelay) preferredRelayServer(myRelayAddress, remoteRelayAddress st
} }
func (w *WorkerRelay) onRelayClientDisconnected() { func (w *WorkerRelay) onRelayClientDisconnected() {
w.conn.onRelayDisconnected() w.onDisconnected()
} }
@@ -1,4 +1,4 @@
package worker package peer
import ( import (
"sync/atomic" "sync/atomic"
@@ -7,17 +7,17 @@ import (
) )
const ( const (
StatusDisconnected Status = iota WorkerStatusDisconnected WorkerStatus = iota
StatusConnected WorkerStatusConnected
) )
type Status int32 type WorkerStatus int32
func (s Status) String() string { func (s WorkerStatus) String() string {
switch s { switch s {
case StatusDisconnected: case WorkerStatusDisconnected:
return "Disconnected" return "Disconnected"
case StatusConnected: case WorkerStatusConnected:
return "Connected" return "Connected"
default: default:
log.Errorf("unknown status: %d", s) log.Errorf("unknown status: %d", s)
@@ -37,16 +37,16 @@ func NewAtomicStatus() *AtomicWorkerStatus {
} }
// Get returns the current connection status // Get returns the current connection status
func (acs *AtomicWorkerStatus) Get() Status { func (acs *AtomicWorkerStatus) Get() WorkerStatus {
return Status(acs.status.Load()) return WorkerStatus(acs.status.Load())
} }
func (acs *AtomicWorkerStatus) SetConnected() { func (acs *AtomicWorkerStatus) SetConnected() {
acs.status.Store(int32(StatusConnected)) acs.status.Store(int32(WorkerStatusConnected))
} }
func (acs *AtomicWorkerStatus) SetDisconnected() { func (acs *AtomicWorkerStatus) SetDisconnected() {
acs.status.Store(int32(StatusDisconnected)) acs.status.Store(int32(WorkerStatusDisconnected))
} }
// String returns the string representation of the current status // String returns the string representation of the current status