mirror of
https://github.com/netbirdio/netbird.git
synced 2024-12-13 18:31:18 +01:00
0c039274a4
This update adds new relay integration for NetBird clients. The new relay is based on web sockets and listens on a single port. - Adds new relay implementation with websocket with single port relaying mechanism - refactor peer connection logic, allowing upgrade and downgrade from/to P2P connection - peer connections are faster since it connects first to relay and then upgrades to P2P - maintains compatibility with old clients by not using the new relay - updates infrastructure scripts with new relay service
259 lines
6.1 KiB
Go
259 lines
6.1 KiB
Go
//go:build linux || darwin
|
|
|
|
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"flag"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/netbirdio/netbird/util"
|
|
)
|
|
|
|
const (
|
|
errMsgFailedReadTCP = "failed to read from tcp: %s"
|
|
)
|
|
|
|
var (
|
|
dataSize = 1024 * 1024 * 50 // 50MB
|
|
pairs = []int{1, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}
|
|
signalListenAddress = ":8081"
|
|
|
|
relaySrvAddress string
|
|
turnSrvAddress string
|
|
signalURL string
|
|
udpListener string // used for TURN test
|
|
)
|
|
|
|
type testResult struct {
|
|
numOfPairs int
|
|
duration time.Duration
|
|
speed float64
|
|
}
|
|
|
|
func (tr testResult) Speed() string {
|
|
speed := tr.speed
|
|
var unit string
|
|
|
|
switch {
|
|
case speed < 1024:
|
|
unit = "B/s"
|
|
case speed < 1048576:
|
|
speed /= 1024
|
|
unit = "KB/s"
|
|
case speed < 1073741824:
|
|
speed /= 1048576
|
|
unit = "MB/s"
|
|
default:
|
|
speed /= 1073741824
|
|
unit = "GB/s"
|
|
}
|
|
|
|
return fmt.Sprintf("%.2f %s", speed, unit)
|
|
}
|
|
|
|
func seedRandomData(size int) ([]byte, error) {
|
|
token := make([]byte, size)
|
|
_, err := rand.Read(token)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return token, nil
|
|
}
|
|
|
|
func avg(transferDuration []time.Duration) (time.Duration, float64) {
|
|
var totalDuration time.Duration
|
|
for _, d := range transferDuration {
|
|
totalDuration += d
|
|
}
|
|
avgDuration := totalDuration / time.Duration(len(transferDuration))
|
|
bps := float64(dataSize) / avgDuration.Seconds()
|
|
return avgDuration, bps
|
|
}
|
|
|
|
func RelayReceiverMain() []testResult {
|
|
testResults := make([]testResult, 0, len(pairs))
|
|
for _, p := range pairs {
|
|
tr := testResult{numOfPairs: p}
|
|
td := relayReceive(relaySrvAddress, p)
|
|
tr.duration, tr.speed = avg(td)
|
|
|
|
testResults = append(testResults, tr)
|
|
}
|
|
|
|
return testResults
|
|
}
|
|
|
|
func RelaySenderMain() {
|
|
log.Infof("starting sender")
|
|
log.Infof("starting seed phase")
|
|
|
|
testData, err := seedRandomData(dataSize)
|
|
if err != nil {
|
|
log.Fatalf("failed to seed random data: %s", err)
|
|
}
|
|
|
|
log.Infof("data size: %d", len(testData))
|
|
|
|
for n, p := range pairs {
|
|
log.Infof("running test with %d pairs", p)
|
|
relayTransfer(relaySrvAddress, testData, p)
|
|
|
|
// grant time to prepare new receivers
|
|
if n < len(pairs)-1 {
|
|
time.Sleep(3 * time.Second)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// TRUNSenderMain is the sender
|
|
// - allocate turn clients
|
|
// - send relayed addresses to signal server in batch
|
|
// - wait for signal server to send back addresses in a map
|
|
// - send test data to each address in parallel
|
|
func TRUNSenderMain() {
|
|
log.Infof("starting TURN sender test")
|
|
|
|
log.Infof("starting seed random data: %d", dataSize)
|
|
testData, err := seedRandomData(dataSize)
|
|
if err != nil {
|
|
log.Fatalf("failed to seed random data: %s", err)
|
|
}
|
|
|
|
ss := SignalClient{signalURL}
|
|
|
|
for _, p := range pairs {
|
|
log.Infof("running test with %d pairs", p)
|
|
turnSender := &TurnSender{}
|
|
|
|
createTurnConns(p, turnSender)
|
|
|
|
log.Infof("send addresses via signal server: %d", len(turnSender.addresses))
|
|
clientAddresses, err := ss.SendAddress(turnSender.addresses)
|
|
if err != nil {
|
|
log.Fatalf("failed to send address: %s", err)
|
|
}
|
|
log.Infof("received addresses: %v", clientAddresses.Address)
|
|
|
|
createSenderDevices(turnSender, clientAddresses)
|
|
|
|
log.Infof("waiting for tcpListeners to be ready")
|
|
time.Sleep(2 * time.Second)
|
|
|
|
tcpConns := make([]net.Conn, 0, len(turnSender.devices))
|
|
for i := range turnSender.devices {
|
|
addr := fmt.Sprintf("10.0.%d.2:9999", i)
|
|
log.Infof("dialing: %s", addr)
|
|
tcpConn, err := net.Dial("tcp", addr)
|
|
if err != nil {
|
|
log.Fatalf("failed to dial tcp: %s", err)
|
|
}
|
|
tcpConns = append(tcpConns, tcpConn)
|
|
}
|
|
|
|
log.Infof("start test data transfer for %d pairs", p)
|
|
testDataLen := len(testData)
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(len(tcpConns))
|
|
for i, tcpConn := range tcpConns {
|
|
log.Infof("sending test data to device: %d", i)
|
|
go runTurnWriting(tcpConn, testData, testDataLen, &wg)
|
|
}
|
|
wg.Wait()
|
|
|
|
for _, d := range turnSender.devices {
|
|
_ = d.Close()
|
|
}
|
|
|
|
log.Infof("test finished with %d pairs", p)
|
|
}
|
|
}
|
|
|
|
func TURNReaderMain() []testResult {
|
|
log.Infof("starting TURN receiver test")
|
|
si := NewSignalService()
|
|
go func() {
|
|
log.Infof("starting signal server")
|
|
err := si.Listen(signalListenAddress)
|
|
if err != nil {
|
|
log.Errorf("failed to listen: %s", err)
|
|
}
|
|
}()
|
|
|
|
testResults := make([]testResult, 0, len(pairs))
|
|
for range pairs {
|
|
addresses := <-si.AddressesChan
|
|
instanceNumber := len(addresses)
|
|
log.Infof("received addresses: %d", instanceNumber)
|
|
|
|
turnReceiver := &TurnReceiver{}
|
|
err := createDevices(addresses, turnReceiver)
|
|
if err != nil {
|
|
log.Fatalf("%s", err)
|
|
}
|
|
|
|
// send client addresses back via signal server
|
|
si.ClientAddressChan <- turnReceiver.clientAddresses
|
|
|
|
durations := make(chan time.Duration, instanceNumber)
|
|
for _, device := range turnReceiver.devices {
|
|
go runTurnReading(device, durations)
|
|
}
|
|
|
|
durationsList := make([]time.Duration, 0, instanceNumber)
|
|
for d := range durations {
|
|
durationsList = append(durationsList, d)
|
|
if len(durationsList) == instanceNumber {
|
|
close(durations)
|
|
}
|
|
}
|
|
|
|
avgDuration, avgSpeed := avg(durationsList)
|
|
ts := testResult{
|
|
numOfPairs: len(durationsList),
|
|
duration: avgDuration,
|
|
speed: avgSpeed,
|
|
}
|
|
testResults = append(testResults, ts)
|
|
|
|
for _, d := range turnReceiver.devices {
|
|
_ = d.Close()
|
|
}
|
|
}
|
|
return testResults
|
|
}
|
|
|
|
func main() {
|
|
var mode string
|
|
|
|
_ = util.InitLog("debug", "console")
|
|
flag.StringVar(&mode, "mode", "sender", "sender or receiver mode")
|
|
flag.Parse()
|
|
|
|
relaySrvAddress = os.Getenv("TEST_RELAY_SERVER") // rel://ip:port
|
|
turnSrvAddress = os.Getenv("TEST_TURN_SERVER") // ip:3478
|
|
signalURL = os.Getenv("TEST_SIGNAL_URL") // http://receiver_ip:8081
|
|
udpListener = os.Getenv("TEST_UDP_LISTENER") // IP:0
|
|
|
|
if mode == "receiver" {
|
|
relayResult := RelayReceiverMain()
|
|
turnResults := TURNReaderMain()
|
|
for i := 0; i < len(turnResults); i++ {
|
|
log.Infof("pairs: %d,\tRelay speed:\t%s,\trelay duration:\t%s", relayResult[i].numOfPairs, relayResult[i].Speed(), relayResult[i].duration)
|
|
log.Infof("pairs: %d,\tTURN speed:\t%s,\tturn duration:\t%s", turnResults[i].numOfPairs, turnResults[i].Speed(), turnResults[i].duration)
|
|
}
|
|
} else {
|
|
RelaySenderMain()
|
|
// grant time for receiver to start
|
|
time.Sleep(3 * time.Second)
|
|
TRUNSenderMain()
|
|
}
|
|
}
|