2023-01-27 21:37:20 +00:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2021-07-15 18:43:13 +00:00
|
|
|
|
|
|
|
// Package speedtest contains both server and client code for
|
|
|
|
// running speedtests between tailscale nodes.
|
|
|
|
package speedtest
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2022-09-15 00:52:47 +00:00
|
|
|
blockSize = 2 * 1024 * 1024 // size of the block of data to send
|
2021-07-15 18:43:13 +00:00
|
|
|
MinDuration = 5 * time.Second // minimum duration for a test
|
|
|
|
DefaultDuration = MinDuration // default duration for a test
|
|
|
|
MaxDuration = 30 * time.Second // maximum duration for a test
|
2022-09-15 00:52:47 +00:00
|
|
|
version = 2 // value used when comparing client and server versions
|
2021-07-15 18:43:13 +00:00
|
|
|
increment = time.Second // increment to display results for, in seconds
|
|
|
|
minInterval = 10 * time.Millisecond // minimum interval length for a result to be included
|
|
|
|
DefaultPort = 20333
|
|
|
|
)
|
|
|
|
|
|
|
|
// config is the initial message sent to the server, that contains information on how to
|
|
|
|
// conduct the test.
|
|
|
|
type config struct {
|
|
|
|
Version int `json:"version"`
|
|
|
|
TestDuration time.Duration `json:"time"`
|
|
|
|
Direction Direction `json:"direction"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// configResponse is the response to the testConfig message. If the server has an
|
|
|
|
// error with the config, the Error variable will hold that error value.
|
|
|
|
type configResponse struct {
|
|
|
|
Error string `json:"error,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// This represents the Result of a speedtest within a specific interval
|
|
|
|
type Result struct {
|
2022-09-15 00:52:47 +00:00
|
|
|
Bytes int // number of bytes sent/received during the interval
|
|
|
|
IntervalStart time.Time // start of the interval
|
|
|
|
IntervalEnd time.Time // end of the interval
|
|
|
|
Total bool // if true, this result struct represents the entire test, rather than a segment of the test
|
2021-07-15 18:43:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r Result) MBitsPerSecond() float64 {
|
2022-09-15 00:52:47 +00:00
|
|
|
return r.MegaBits() / r.IntervalEnd.Sub(r.IntervalStart).Seconds()
|
2021-07-15 18:43:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r Result) MegaBytes() float64 {
|
|
|
|
return float64(r.Bytes) / 1000000.0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r Result) MegaBits() float64 {
|
|
|
|
return r.MegaBytes() * 8.0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r Result) Interval() time.Duration {
|
2022-09-15 00:52:47 +00:00
|
|
|
return r.IntervalEnd.Sub(r.IntervalStart)
|
2021-07-15 18:43:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Direction int
|
|
|
|
|
|
|
|
const (
|
|
|
|
Download Direction = iota
|
|
|
|
Upload
|
|
|
|
)
|
|
|
|
|
|
|
|
func (d Direction) String() string {
|
|
|
|
switch d {
|
|
|
|
case Upload:
|
|
|
|
return "upload"
|
|
|
|
case Download:
|
|
|
|
return "download"
|
|
|
|
default:
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *Direction) Reverse() {
|
|
|
|
switch *d {
|
|
|
|
case Upload:
|
|
|
|
*d = Download
|
|
|
|
case Download:
|
|
|
|
*d = Upload
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|