netbird/client/internal/peer/worker_relay.go

133 lines
3.4 KiB
Go
Raw Normal View History

package peer
import (
"context"
"errors"
"math/rand"
"net"
"time"
log "github.com/sirupsen/logrus"
relayClient "github.com/netbirdio/netbird/relay/client"
)
type RelayConnInfo struct {
relayedConn net.Conn
rosenpassPubKey []byte
rosenpassAddr string
}
2024-06-19 11:52:40 +02:00
type WorkerRelayCallbacks struct {
OnConnReady func(RelayConnInfo)
OnStatusChanged func(ConnStatus)
DoHandshake func() (*OfferAnswer, error)
}
2024-06-18 11:22:40 +02:00
type WorkerRelay struct {
2024-06-19 11:52:40 +02:00
ctx context.Context
log *log.Entry
relayManager *relayClient.Manager
config ConnConfig
conn WorkerRelayCallbacks
}
2024-06-19 11:52:40 +02:00
func NewWorkerRelay(ctx context.Context, log *log.Entry, relayManager *relayClient.Manager, config ConnConfig, callbacks WorkerRelayCallbacks) *WorkerRelay {
2024-06-18 11:22:40 +02:00
return &WorkerRelay{
2024-06-19 11:52:40 +02:00
ctx: ctx,
log: log,
relayManager: relayManager,
config: config,
conn: callbacks,
}
}
// SetupRelayConnection todo: this function is not completed. Make no sense to put it in a for loop because we are not waiting for any event
2024-06-18 11:22:40 +02:00
func (w *WorkerRelay) SetupRelayConnection() {
for {
2024-06-18 11:22:40 +02:00
if !w.waitForReconnectTry() {
return
}
2024-06-19 18:16:43 +02:00
w.log.Debugf("trying to establish Relay connection with peer %s", w.config.Key)
2024-06-19 11:52:40 +02:00
remoteOfferAnswer, err := w.conn.DoHandshake()
if err != nil {
if errors.Is(err, ErrSignalIsNotReady) {
2024-06-18 11:22:40 +02:00
w.log.Infof("signal client isn't ready, skipping connection attempt")
}
w.log.Errorf("%s", err)
continue
}
2024-06-18 11:22:40 +02:00
if !w.isRelaySupported(remoteOfferAnswer) {
2024-06-19 18:16:43 +02:00
w.log.Infof("Relay is not supported by remote peer")
// todo should we retry?
// if the remote peer doesn't support relay make no sense to retry infinity
// but if the remote peer supports relay just the connection is lost we should retry
continue
}
// the relayManager will return with error in case if the connection has lost with relay server
2024-06-18 11:22:40 +02:00
currentRelayAddress, err := w.relayManager.RelayAddress()
if err != nil {
2024-06-19 18:16:43 +02:00
w.log.Infof("local Relay connection is lost, skipping connection attempt")
continue
}
2024-06-18 11:22:40 +02:00
srv := w.preferredRelayServer(currentRelayAddress.String(), remoteOfferAnswer.RelaySrvAddress)
relayedConn, err := w.relayManager.OpenConn(srv, w.config.Key)
if err != nil {
2024-06-19 18:16:43 +02:00
w.log.Infof("failed to open relay connection: %s", err)
continue
}
2024-06-19 11:52:40 +02:00
go w.conn.OnConnReady(RelayConnInfo{
relayedConn: relayedConn,
rosenpassPubKey: remoteOfferAnswer.RosenpassPubKey,
rosenpassAddr: remoteOfferAnswer.RosenpassAddr,
})
2024-06-18 11:10:17 +02:00
<-w.ctx.Done()
}
}
2024-06-18 11:22:40 +02:00
func (w *WorkerRelay) RelayAddress() (net.Addr, error) {
return w.relayManager.RelayAddress()
}
2024-06-18 11:22:40 +02:00
func (w *WorkerRelay) isRelaySupported(answer *OfferAnswer) bool {
2024-06-19 11:52:40 +02:00
if !w.relayManager.HasRelayAddress() {
return false
}
return answer.RelaySrvAddress != ""
}
2024-06-18 11:22:40 +02:00
func (w *WorkerRelay) preferredRelayServer(myRelayAddress, remoteRelayAddress string) string {
if w.config.LocalKey > w.config.Key {
return myRelayAddress
}
return remoteRelayAddress
}
2024-06-18 11:22:40 +02:00
func (w *WorkerRelay) RelayIsSupportedLocally() bool {
return w.relayManager.HasRelayAddress()
}
// waitForReconnectTry waits for a random duration before trying to reconnect
2024-06-18 11:22:40 +02:00
func (w *WorkerRelay) waitForReconnectTry() bool {
minWait := 500
maxWait := 2000
duration := time.Duration(rand.Intn(maxWait-minWait)+minWait) * time.Millisecond
2024-06-18 11:20:01 +02:00
timeout := time.NewTimer(duration)
defer timeout.Stop()
select {
2024-06-18 11:22:40 +02:00
case <-w.ctx.Done():
return false
2024-06-18 11:20:01 +02:00
case <-timeout.C:
return true
}
}