initial working version
parent
e8dc386ba0
commit
10cf19535e
@ -1,41 +1,82 @@
|
||||
package iperf
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func Execute(cmd string, outPipe io.ReadCloser, errPipe io.ReadCloser, exit chan <- int) (err error) {
|
||||
func ExecuteAsync(cmd string) (outPipe io.ReadCloser, errPipe io.ReadCloser, exitCode chan int, err error) {
|
||||
exitCode = make(chan int)
|
||||
cmdParts := strings.Fields(cmd)
|
||||
binary, err := exec.LookPath(cmdParts[0])
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
exe := exec.Command(binary, cmdParts[1:]...)
|
||||
outPipe, err = exe.StdoutPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
errPipe, err = exe.StderrPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
err = exe.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
go func() {
|
||||
if err := exe.Wait(); err != nil {
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||
exit <- status.ExitStatus()
|
||||
exitCode <- status.ExitStatus()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exit <- 0
|
||||
exitCode <- 0
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
return outPipe, errPipe, exitCode, nil
|
||||
}
|
||||
|
||||
func ExecuteAsyncWithCancel(cmd string) (stdOut io.ReadCloser, stdErr io.ReadCloser, exitCode chan int, cancelToken context.CancelFunc, err error) {
|
||||
exitCode = make(chan int)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cmdParts := strings.Fields(cmd)
|
||||
binary, err := exec.LookPath(cmdParts[0])
|
||||
if err != nil {
|
||||
defer cancel()
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
exe := exec.CommandContext(ctx, binary, cmdParts[1:]...)
|
||||
stdOut, err = exe.StdoutPipe()
|
||||
if err != nil {
|
||||
defer cancel()
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
stdErr, err = exe.StderrPipe()
|
||||
if err != nil {
|
||||
defer cancel()
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
err = exe.Start()
|
||||
if err != nil {
|
||||
defer cancel()
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
go func() {
|
||||
if err := exe.Wait(); err != nil {
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||
exitCode <- status.ExitStatus()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exitCode <- 0
|
||||
}
|
||||
}()
|
||||
return stdOut, stdErr, exitCode, cancel, nil
|
||||
}
|
||||
|
@ -1,2 +1,25 @@
|
||||
github.com/BGrewell/go-conversions v0.0.0-20201203155646-5e189e4ca087 h1:/ZR3IHtTSPqwzYQSfZYwGjrmDI5c1u2jEDDtT75Fmqw=
|
||||
github.com/BGrewell/go-conversions v0.0.0-20201203155646-5e189e4ca087/go.mod h1:XtXcz/MP04vhr6c6R/5gZPJZVQpbXlFsKTHr5yy/5sU=
|
||||
github.com/BGrewell/go-execute v0.0.0-20201203155726-b7c037ebde49 h1:HV+WdlqXjmzP59lhgb100vTSIcDuKuLmK11KdnPY0cg=
|
||||
github.com/BGrewell/go-execute v0.0.0-20201203155726-b7c037ebde49/go.mod h1:vQZr3vuuuKuknvi74K22ne7NzOlwKTPKXOFMVr9Qa6A=
|
||||
github.com/BGrewell/tail v1.0.0 h1:sG+Uvv+UApHtj5z+AWWB9i5m2SCH0RLfxYqXujYQo+Q=
|
||||
github.com/BGrewell/tail v1.0.0/go.mod h1:0PFYWAobUZKZLEYIxxmjFgnfvCLA600LkFbGO9KFIRA=
|
||||
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
|
||||
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
|
||||
github.com/fatih/gomodifytags v1.13.0 h1:fmhwoecjZ5c34Q2chjRB9cL8Rgag+1TOSMy+grissMc=
|
||||
github.com/fatih/gomodifytags v1.13.0/go.mod h1:TbUyEjH1Zo0GkJd2Q52oVYqYcJ0eGNqG8bsiOb75P9c=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/tools v0.0.0-20180824175216-6c1c5e93cdc1/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
|
@ -1 +1,393 @@
|
||||
package iperf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type StreamInterval struct {
|
||||
Streams []*StreamIntervalReport `json:"streams"`
|
||||
Sum *StreamIntervalSumReport `json:"sum"`
|
||||
}
|
||||
|
||||
func (si *StreamInterval) String() string {
|
||||
b, err := json.Marshal(si)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type StreamIntervalReport struct {
|
||||
Socket int `json:"socket"`
|
||||
StartInterval float32 `json:"start"`
|
||||
EndInterval float32 `json:"end"`
|
||||
Seconds float32 `json:"seconds"`
|
||||
Bytes int `json:"bytes"`
|
||||
BitsPerSecond float64 `json:"bits_per_second"`
|
||||
Omitted bool `json:"omitted"`
|
||||
}
|
||||
|
||||
func (sir *StreamIntervalReport) String() string {
|
||||
b, err := json.Marshal(sir)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type StreamIntervalSumReport struct {
|
||||
StartInterval float32 `json:"start"`
|
||||
EndInterval float32 `json:"end"`
|
||||
Seconds float32 `json:"seconds"`
|
||||
Bytes int `json:"bytes"`
|
||||
BitsPerSecond float64 `json:"bits_per_second"`
|
||||
Omitted bool `json:"omitted"`
|
||||
}
|
||||
|
||||
func (sisr *StreamIntervalSumReport) String() string {
|
||||
b, err := json.Marshal(sisr)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type StreamEndReport struct {
|
||||
Sender TcpStreamEndReport `json:"sender"`
|
||||
Receiver TcpStreamEndReport `json:"receiver"`
|
||||
Udp UdpStreamEndReport `json:"udp"`
|
||||
}
|
||||
|
||||
func (ser *StreamEndReport) String() string {
|
||||
b, err := json.Marshal(ser)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type UdpStreamEndReport struct {
|
||||
Socket int `json:"socket"`
|
||||
Start float32 `json:"start"`
|
||||
End float32 `json:"end"`
|
||||
Seconds float32 `json:"seconds"`
|
||||
Bytes int `json:"bytes"`
|
||||
BitsPerSecond float64 `json:"bits_per_second"`
|
||||
JitterMs float32 `json:"jitter_ms"`
|
||||
LostPackets int `json:"lost_packets"`
|
||||
Packets int `json:"packets"`
|
||||
LostPercent float32 `json:"lost_percent"`
|
||||
OutOfOrder int `json:"out_of_order"`
|
||||
}
|
||||
|
||||
func (user *UdpStreamEndReport) String() string {
|
||||
b, err := json.Marshal(user)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type TcpStreamEndReport struct {
|
||||
Socket int `json:"socket"`
|
||||
Start float32 `json:"start"`
|
||||
End float32 `json:"end"`
|
||||
Seconds float32 `json:"seconds"`
|
||||
Bytes int `json:"bytes"`
|
||||
BitsPerSecond float64 `json:"bits_per_second"`
|
||||
}
|
||||
|
||||
func (tser *TcpStreamEndReport) String() string {
|
||||
b, err := json.Marshal(tser)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type StreamEndSumReport struct {
|
||||
Start float32 `json:"start"`
|
||||
End float32 `json:"end"`
|
||||
Seconds float32 `json:"seconds"`
|
||||
Bytes int `json:"bytes"`
|
||||
BitsPerSecond float64 `json:"bits_per_second"`
|
||||
}
|
||||
|
||||
func (sesr *StreamEndSumReport) String() string {
|
||||
b, err := json.Marshal(sesr)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type CpuUtilizationReport struct {
|
||||
HostTotal float32 `json:"host_total"`
|
||||
HostUser float32 `json:"host_user"`
|
||||
HostSystem float32 `json:"host_system"`
|
||||
RemoteTotal float32 `json:"remote_total"`
|
||||
RemoteUser float32 `json:"remote_user"`
|
||||
RemoteSystem float32 `json:"remote_system"`
|
||||
}
|
||||
|
||||
func (cur *CpuUtilizationReport) String() string {
|
||||
b, err := json.Marshal(cur)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type ConnectionInfo struct {
|
||||
Socket int `json:"socket"`
|
||||
LocalHost string `json:"local_host"`
|
||||
LocalPort int `json:"local_port"`
|
||||
RemoteHost string `json:"remote_host"`
|
||||
RemotePort int `json:"remote_port"`
|
||||
}
|
||||
|
||||
func (ci *ConnectionInfo) String() string {
|
||||
b, err := json.Marshal(ci)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type TimestampInfo struct {
|
||||
Time string `json:"time"`
|
||||
TimeSecs int `json:"timesecs"`
|
||||
}
|
||||
|
||||
func (tsi *TimestampInfo) String() string {
|
||||
b, err := json.Marshal(tsi)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type ConnectingToInfo struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
}
|
||||
|
||||
func (cti *ConnectingToInfo) String() string {
|
||||
b, err := json.Marshal(cti)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type TestStartInfo struct {
|
||||
Protocol string `json:"protocol"`
|
||||
NumStreams int `json:"num_streams"`
|
||||
BlkSize int `json:"blksize"`
|
||||
Omit int `json:"omit"`
|
||||
Duration int `json:"duration"`
|
||||
Bytes int `json:"bytes"`
|
||||
Blocks int `json:"blocks"`
|
||||
Reverse int `json:"reverse"`
|
||||
}
|
||||
|
||||
func (tsi *TestStartInfo) String() string {
|
||||
b, err := json.Marshal(tsi)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type StartInfo struct {
|
||||
Connected []*ConnectionInfo `json:"connected"`
|
||||
Version string `json:"version"`
|
||||
SystemInfo string `json:"system_info"`
|
||||
Timestamp TimestampInfo `json:"timestamp"`
|
||||
ConnectingTo ConnectingToInfo `json:"connecting_to"`
|
||||
Cookie string `json:"cookie"`
|
||||
TcpMssDefault int `json:"tcp_mss_default"`
|
||||
TestStart TestStartInfo `json:"test_start"`
|
||||
}
|
||||
|
||||
func (si *StartInfo) String() string {
|
||||
b, err := json.Marshal(si)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type EndInfo struct {
|
||||
Streams []*StreamEndReport `json:"streams"`
|
||||
SumSent StreamEndSumReport `json:"sum_sent"`
|
||||
SumReceived StreamEndSumReport `json:"sum_received"`
|
||||
CpuReport CpuUtilizationReport `json:"cpu_utilization_percent"`
|
||||
}
|
||||
|
||||
func (ei *EndInfo) String() string {
|
||||
b, err := json.Marshal(ei)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type ServerReport struct {
|
||||
Start StartInfo `json:"start"`
|
||||
Intervals []*StreamInterval `json:"intervals"`
|
||||
End EndInfo `json:"end"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
func (sr *ServerReport) String() string {
|
||||
b, err := json.Marshal(sr)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
type TestReport struct {
|
||||
Start StartInfo `json:"start"`
|
||||
Intervals []*StreamInterval `json:"intervals"`
|
||||
End EndInfo `json:"end"`
|
||||
Error string `json:"error"`
|
||||
ServerOutputJson ServerReport `json:"server_output_json"`
|
||||
}
|
||||
|
||||
func (tr *TestReport) String() string {
|
||||
b, err := json.Marshal(tr)
|
||||
if err != nil {
|
||||
return "error converting to json"
|
||||
}
|
||||
|
||||
var pretty bytes.Buffer
|
||||
err = json.Indent(&pretty, b, "", " ")
|
||||
if err != nil {
|
||||
return "error converting json to indented format"
|
||||
}
|
||||
|
||||
return string(pretty.Bytes())
|
||||
}
|
||||
|
||||
func Loads(jsonStr string) (report *TestReport, err error) {
|
||||
r := &TestReport{}
|
||||
err = json.Unmarshal([]byte(jsonStr), r)
|
||||
return r, err
|
||||
}
|
||||
|
||||
func Load(filename string) (report *TestReport, err error) {
|
||||
contents, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Loads(string(contents))
|
||||
}
|
||||
|
@ -1 +1,92 @@
|
||||
package iperf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/BGrewell/tail"
|
||||
"github.com/BGrewell/go-conversions"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Reporter struct {
|
||||
ReportingChannel chan *StreamIntervalReport
|
||||
LogFile string
|
||||
running bool
|
||||
}
|
||||
|
||||
func (r *Reporter) Start() {
|
||||
r.running = true
|
||||
go r.runLogProcessor()
|
||||
}
|
||||
|
||||
func (r *Reporter) Stop() {
|
||||
r.running = false
|
||||
close(r.ReportingChannel)
|
||||
}
|
||||
|
||||
func (r *Reporter) runLogProcessor() {
|
||||
tailer, err := tail.TailFile(r.LogFile, tail.Config{
|
||||
Follow: true,
|
||||
ReOpen: true,
|
||||
Poll: true,
|
||||
MustExist: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to tail log file: %v", err)
|
||||
}
|
||||
for line := range tailer.Lines {
|
||||
// TODO: For now this only cares about individual streams it ignores the sum lines
|
||||
if len(line.Text) > 5 {
|
||||
id := line.Text[1:4]
|
||||
stream, err := strconv.Atoi(strings.TrimSpace(id))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line.Text[5:])
|
||||
if len(fields) >= 6 {
|
||||
if fields[0] == "local" {
|
||||
continue
|
||||
}
|
||||
timeFields := strings.Split(fields[0], "-")
|
||||
start, err := strconv.ParseFloat(timeFields[0], 32)
|
||||
if err != nil {
|
||||
log.Printf("failed to convert start time: %s\n", err)
|
||||
}
|
||||
end, err := strconv.ParseFloat(timeFields[1], 32)
|
||||
transferedStr := fmt.Sprintf("%s%s", fields[2], fields[3])
|
||||
transferedBytes, err := conversions.StringBitRateToInt(transferedStr)
|
||||
if err != nil {
|
||||
log.Printf("failed to convert units: %s\n", err)
|
||||
}
|
||||
transferedBytes = transferedBytes / 8
|
||||
rateStr := fmt.Sprintf("%s%s", fields[4], fields[5])
|
||||
rate, err := conversions.StringBitRateToInt(rateStr)
|
||||
if err != nil {
|
||||
log.Printf("failed to convert units: %s\n", err)
|
||||
}
|
||||
omitted := false
|
||||
if len(fields) >= 7 && fields[6] == "(omitted)" {
|
||||
omitted = true
|
||||
}
|
||||
report := &StreamIntervalReport{
|
||||
Socket: stream,
|
||||
StartInterval: float32(start),
|
||||
EndInterval: float32(end),
|
||||
Seconds: float32(end - start),
|
||||
Bytes: int(transferedBytes),
|
||||
BitsPerSecond: float64(rate),
|
||||
Omitted: omitted,
|
||||
}
|
||||
r.ReportingChannel <- report
|
||||
}
|
||||
}
|
||||
|
||||
if !r.running {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,291 @@
|
||||
{
|
||||
"start":{
|
||||
"connected":[
|
||||
{
|
||||
"socket":4,
|
||||
"local_host":"127.0.0.1",
|
||||
"local_port":64200,
|
||||
"remote_host":"127.0.0.1",
|
||||
"remote_port":5201
|
||||
}
|
||||
],
|
||||
"version":"iperf 3.1.3",
|
||||
"system_info":"CYGWIN_NT-10.0 BGrewell-MOBL3 2.5.1(0.297/5/3) 2016-04-21 22:14 x86_64",
|
||||
"timestamp":{
|
||||
"time":"Tue, 02 Mar 2021 18:28:14 GMT",
|
||||
"timesecs":1614709694
|
||||
},
|
||||
"connecting_to":{
|
||||
"host":"127.0.0.1",
|
||||
"port":5201
|
||||
},
|
||||
"cookie":"BGrewell-MOBL3.1614709694.715824.0bf",
|
||||
"tcp_mss_default":0,
|
||||
"test_start":{
|
||||
"protocol":"TCP",
|
||||
"num_streams":1,
|
||||
"blksize":131072,
|
||||
"omit":0,
|
||||
"duration":10,
|
||||
"bytes":0,
|
||||
"blocks":0,
|
||||
"reverse":0
|
||||
}
|
||||
},
|
||||
"intervals":[
|
||||
{
|
||||
"streams":[
|
||||
{
|
||||
"socket":4,
|
||||
"start":0,
|
||||
"end":1.000554,
|
||||
"seconds":1.000554,
|
||||
"bytes":1635647488,
|
||||
"bits_per_second":1.307794e+10,
|
||||
"omitted":false
|
||||
}
|
||||
],
|
||||
"sum":{
|
||||
"start":0,
|
||||
"end":1.000554,
|
||||
"seconds":1.000554,
|
||||
"bytes":1635647488,
|
||||
"bits_per_second":1.307794e+10,
|
||||
"omitted":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"streams":[
|
||||
{
|
||||
"socket":4,
|
||||
"start":1.000554,
|
||||
"end":2.000056,
|
||||
"seconds":0.999502,
|
||||
"bytes":1527250944,
|
||||
"bits_per_second":1.222409e+10,
|
||||
"omitted":false
|
||||
}
|
||||
],
|
||||
"sum":{
|
||||
"start":1.000554,
|
||||
"end":2.000056,
|
||||
"seconds":0.999502,
|
||||
"bytes":1527250944,
|
||||
"bits_per_second":1.222409e+10,
|
||||
"omitted":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"streams":[
|
||||
{
|
||||
"socket":4,
|
||||
"start":2.000056,
|
||||
"end":3.000353,
|
||||
"seconds":1.000297,
|
||||
"bytes":1712062464,
|
||||
"bits_per_second":1.369244e+10,
|
||||
"omitted":false
|
||||
}
|
||||
],
|
||||
"sum":{
|
||||
"start":2.000056,
|
||||
"end":3.000353,
|
||||
"seconds":1.000297,
|
||||
"bytes":1712062464,
|
||||
"bits_per_second":1.369244e+10,
|
||||
"omitted":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"streams":[
|
||||
{
|
||||
"socket":4,
|
||||
"start":3.000353,
|
||||
"end":4.000669,
|
||||
"seconds":1.000316,
|
||||
"bytes":1730412544,
|
||||
"bits_per_second":1.383893e+10,
|
||||
"omitted":false
|
||||
}
|
||||
],
|
||||
"sum":{
|
||||
"start":3.000353,
|
||||
"end":4.000669,
|
||||
"seconds":1.000316,
|
||||
"bytes":1730412544,
|
||||
"bits_per_second":1.383893e+10,
|
||||
"omitted":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"streams":[
|
||||
{
|
||||
"socket":4,
|
||||
"start":4.000669,
|
||||
"end":5.000021,
|
||||
"seconds":0.999352,
|
||||
"bytes":1777467392,
|
||||
"bits_per_second":1.422896e+10,
|
||||
"omitted":false
|
||||
}
|
||||
],
|
||||
"sum":{
|
||||
"start":4.000669,
|
||||
"end":5.000021,
|
||||
"seconds":0.999352,
|
||||
"bytes":1777467392,
|
||||
"bits_per_second":1.422896e+10,
|
||||
"omitted":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"streams":[
|
||||
{
|
||||
"socket":4,
|
||||
"start":5.000021,
|
||||
"end":6.000122,
|
||||
"seconds":1.000101,
|
||||
"bytes":1673920512,
|
||||
"bits_per_second":1.339001e+10,
|
||||
"omitted":false
|
||||
}
|
||||
],
|
||||
"sum":{
|
||||
"start":5.000021,
|
||||
"end":6.000122,
|
||||
"seconds":1.000101,
|
||||
"bytes":1673920512,
|
||||
"bits_per_second":1.339001e+10,
|
||||
"omitted":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"streams":[
|
||||
{
|
||||
"socket":4,
|
||||
"start":6.000122,
|
||||
"end":7.000517,
|
||||
"seconds":1.000395,
|
||||
"bytes":1585446912,
|
||||
"bits_per_second":1.267857e+10,
|
||||
"omitted":false
|
||||
}
|
||||
],
|
||||
"sum":{
|
||||
"start":6.000122,
|
||||
"end":7.000517,
|
||||
"seconds":1.000395,
|
||||
"bytes":1585446912,
|
||||
"bits_per_second":1.267857e+10,
|
||||
"omitted":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"streams":[
|
||||
{
|
||||
"socket":4,
|
||||
"start":7.000517,
|
||||
"end":8.000053,
|
||||
"seconds":0.999536,
|
||||
"bytes":1642987520,
|
||||
"bits_per_second":1.315000e+10,
|
||||
"omitted":false
|
||||
}
|
||||
],
|
||||
"sum":{
|
||||
"start":7.000517,
|
||||
"end":8.000053,
|
||||
"seconds":0.999536,
|
||||
"bytes":1642987520,
|
||||
"bits_per_second":1.315000e+10,
|
||||
"omitted":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"streams":[
|
||||
{
|
||||
"socket":4,
|
||||
"start":8.000053,
|
||||
"end":9.000105,
|
||||
"seconds":1.000052,
|
||||
"bytes":1547173888,
|
||||
"bits_per_second":1.237675e+10,
|
||||
"omitted":false
|
||||
}
|
||||
],
|
||||
"sum":{
|
||||
"start":8.000053,
|
||||
"end":9.000105,
|
||||
"seconds":1.000052,
|
||||
"bytes":1547173888,
|
||||
"bits_per_second":1.237675e+10,
|
||||
"omitted":false
|
||||
}
|
||||
},
|
||||
{
|
||||
"streams":[
|
||||
{
|
||||
"socket":4,
|
||||
"start":9.000105,
|
||||
"end":10.000386,
|
||||
"seconds":1.000281,
|
||||
"bytes":1773142016,
|
||||
"bits_per_second":1.418115e+10,
|
||||
"omitted":false
|
||||
}
|
||||
],
|
||||
"sum":{
|
||||
"start":9.000105,
|
||||
"end":10.000386,
|
||||
"seconds":1.000281,
|
||||
"bytes":1773142016,
|
||||
"bits_per_second":1.418115e+10,
|
||||
"omitted":false
|
||||
}
|
||||
}
|
||||
],
|
||||
"end":{
|
||||
"streams":[
|
||||
{
|
||||
"sender":{
|
||||
"socket":4,
|
||||
"start":0,
|
||||
"end":10.000386,
|
||||
"seconds":10.000386,
|
||||
"bytes":16605511680,
|
||||
"bits_per_second":1.328390e+10
|
||||
},
|
||||
"receiver":{
|
||||
"socket":4,
|
||||
"start":0,
|
||||
"end":10.000386,
|
||||
"seconds":10.000386,
|
||||
"bytes":16605511680,
|
||||
"bits_per_second":1.328390e+10
|
||||
}
|
||||
}
|
||||
],
|
||||
"sum_sent":{
|
||||
"start":0,
|
||||
"end":10.000386,
|
||||
"seconds":10.000386,
|
||||
"bytes":16605511680,
|
||||
"bits_per_second":1.328390e+10
|
||||
},
|
||||
"sum_received":{
|
||||
"start":0,
|
||||
"end":10.000386,
|
||||
"seconds":10.000386,
|
||||
"bytes":16605511680,
|
||||
"bits_per_second":1.328390e+10
|
||||
},
|
||||
"cpu_utilization_percent":{
|
||||
"host_total":83.983525,
|
||||
"host_user":5.155306,
|
||||
"host_system":78.828219,
|
||||
"remote_total":34.722681,
|
||||
"remote_user":7.224950,
|
||||
"remote_system":27.497731
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/BGrewell/go-iperf"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
$END$
|
||||
s := iperf.NewServer()
|
||||
err := s.Start()
|
||||
if err != nil {
|
||||
fmt.Println("failed to start server")
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
for s.Running {
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
fmt.Println("server has exited")
|
||||
}
|
||||
|
Loading…
Reference in New Issue