mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-20 21:59:07 +02:00
Resolve conflicts in shared/relay/client/manager.go: - NewManager: keep both sides. main's serverPicker.NetEvents wiring and this branch's ForeignRelaysStore construction are independent. - openConnVia/openConnOnTrack: take this branch's deletion. main refined the RelayTrack rt.ready locking, but this branch replaces that machinery with the singleflight-based ForeignRelaysStore, so the refinement applies to a code path that no longer exists. Carry main's netEvents plumbing into the new store so foreign relay dials are still registered for the network change sweep.
159 lines
3.8 KiB
Go
159 lines
3.8 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.org/x/sync/singleflight"
|
|
|
|
relayAuth "github.com/netbirdio/netbird/shared/relay/auth/hmac"
|
|
)
|
|
|
|
type foreignRelay struct {
|
|
client *Client
|
|
created time.Time
|
|
inUse int
|
|
}
|
|
|
|
type ForeignRelaysStore struct {
|
|
mu sync.RWMutex
|
|
clients map[string]*foreignRelay
|
|
|
|
group singleflight.Group
|
|
|
|
ctx context.Context
|
|
tokenStore *relayAuth.TokenStore
|
|
peerID string
|
|
mtu uint16
|
|
transportFallback *transportFallback
|
|
netEvents NetEvents
|
|
onDisconnect func(string)
|
|
keepUnusedServerTime time.Duration
|
|
}
|
|
|
|
func NewForeignRelaysStore(ctx context.Context, tokenStore *relayAuth.TokenStore, peerID string, mtu uint16, transportFallback *transportFallback, netEvents NetEvents, onDisconnect func(string), keepUnusedServerTime time.Duration) *ForeignRelaysStore {
|
|
return &ForeignRelaysStore{
|
|
clients: make(map[string]*foreignRelay),
|
|
ctx: ctx,
|
|
tokenStore: tokenStore,
|
|
peerID: peerID,
|
|
mtu: mtu,
|
|
transportFallback: transportFallback,
|
|
netEvents: netEvents,
|
|
onDisconnect: onDisconnect,
|
|
keepUnusedServerTime: keepUnusedServerTime,
|
|
}
|
|
}
|
|
|
|
func (f *ForeignRelaysStore) OpenConn(ctx context.Context, peerKey string, remoteRelayServer RelayServer) (net.Conn, error) {
|
|
fr, err := f.acquire(remoteRelayServer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.release(fr)
|
|
|
|
return fr.client.OpenConn(ctx, peerKey)
|
|
}
|
|
|
|
func (f *ForeignRelaysStore) acquire(remoteRelayServer RelayServer) (*foreignRelay, error) {
|
|
f.mu.Lock()
|
|
if fr, ok := f.clients[remoteRelayServer.Addr]; ok {
|
|
fr.inUse++
|
|
f.mu.Unlock()
|
|
return fr, nil
|
|
}
|
|
f.mu.Unlock()
|
|
|
|
v, err, _ := f.group.Do(remoteRelayServer.Addr, func() (any, error) {
|
|
f.mu.RLock()
|
|
fr, ok := f.clients[remoteRelayServer.Addr]
|
|
f.mu.RUnlock()
|
|
if ok {
|
|
return fr, nil
|
|
}
|
|
|
|
relayClient := NewClientWithServerIP(remoteRelayServer.Addr, remoteRelayServer.IP, f.tokenStore, f.peerID, f.mtu)
|
|
relayClient.SetTransportFallback(f.transportFallback)
|
|
relayClient.netEvents = f.netEvents
|
|
if err := relayClient.Connect(f.ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
relayClient.SetOnDisconnectListener(f.onDisconnect)
|
|
|
|
f.mu.Lock()
|
|
fr = &foreignRelay{client: relayClient, created: time.Now()}
|
|
f.clients[remoteRelayServer.Addr] = fr
|
|
f.mu.Unlock()
|
|
return fr, nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fr := v.(*foreignRelay)
|
|
f.mu.Lock()
|
|
if cur, ok := f.clients[remoteRelayServer.Addr]; !ok || cur != fr {
|
|
f.mu.Unlock()
|
|
return f.acquire(remoteRelayServer)
|
|
}
|
|
fr.inUse++
|
|
f.mu.Unlock()
|
|
return fr, nil
|
|
}
|
|
|
|
func (f *ForeignRelaysStore) release(fr *foreignRelay) {
|
|
f.mu.Lock()
|
|
fr.inUse--
|
|
f.mu.Unlock()
|
|
}
|
|
|
|
func (f *ForeignRelaysStore) evict(serverAddress string) {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
if _, ok := f.clients[serverAddress]; ok {
|
|
delete(f.clients, serverAddress)
|
|
log.Debugf("evicted disconnected foreign relay client: %s", serverAddress)
|
|
}
|
|
}
|
|
|
|
func (f *ForeignRelaysStore) cleanupUnused() {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
|
|
for addr, fr := range f.clients {
|
|
if time.Since(fr.created) <= f.keepUnusedServerTime {
|
|
continue
|
|
}
|
|
if fr.inUse > 0 {
|
|
continue
|
|
}
|
|
if fr.client.HasConns() {
|
|
continue
|
|
}
|
|
fr.client.SetOnDisconnectListener(nil)
|
|
go func() {
|
|
_ = fr.client.Close()
|
|
}()
|
|
log.Debugf("clean up unused relay server connection: %s", addr)
|
|
delete(f.clients, addr)
|
|
}
|
|
}
|
|
|
|
func (f *ForeignRelaysStore) states() []RelayConnState {
|
|
f.mu.RLock()
|
|
clients := make([]*Client, 0, len(f.clients))
|
|
for _, fr := range f.clients {
|
|
clients = append(clients, fr.client)
|
|
}
|
|
f.mu.RUnlock()
|
|
|
|
states := make([]RelayConnState, 0, len(clients))
|
|
for _, c := range clients {
|
|
states = append(states, relayConnState(c))
|
|
}
|
|
return states
|
|
}
|