initial implementation
This commit is contained in:
70
.idea/workspace.xml
generated
70
.idea/workspace.xml
generated
@@ -2,15 +2,16 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="fc2840de-29dc-4fca-8e0e-a283562f60ca" name="Default Changelist" comment="">
|
<list default="true" id="fc2840de-29dc-4fca-8e0e-a283562f60ca" name="Default Changelist" comment="">
|
||||||
<change afterPath="$PROJECT_DIR$/bindata.go" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/client.go" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/cmd/main.go" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/execute.go" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/protocol.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/server.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/go-iperf.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/go-iperf.iml" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/shared.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/embedded/cygwin1.dll" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/embedded/iperf3" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/bindata.go" beforeDir="false" afterPath="$PROJECT_DIR$/bindata.go" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/embedded/iperf3.exe" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/cmd/main.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/main.go" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/go.mod" beforeDir="false" afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/iperf.go" beforeDir="false" afterPath="$PROJECT_DIR$/iperf.go" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/iperf.go" beforeDir="false" afterPath="$PROJECT_DIR$/iperf.go" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
@@ -21,8 +22,8 @@
|
|||||||
<component name="FileTemplateManagerImpl">
|
<component name="FileTemplateManagerImpl">
|
||||||
<option name="RECENT_TEMPLATES">
|
<option name="RECENT_TEMPLATES">
|
||||||
<list>
|
<list>
|
||||||
<option value="Go File" />
|
|
||||||
<option value="Go Application" />
|
<option value="Go Application" />
|
||||||
|
<option value="Go File" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
@@ -30,17 +31,21 @@
|
|||||||
<component name="Git.Settings">
|
<component name="Git.Settings">
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="GoLibraries">
|
||||||
|
<option name="indexEntireGoPath" value="false" />
|
||||||
|
</component>
|
||||||
<component name="ProjectId" id="1lhjlU9mkZIWjchkp4HkX1szrI1" />
|
<component name="ProjectId" id="1lhjlU9mkZIWjchkp4HkX1szrI1" />
|
||||||
<component name="ProjectViewState">
|
<component name="ProjectViewState">
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent">
|
<component name="PropertiesComponent">
|
||||||
<property name="DefaultGoTemplateProperty" value="Go Application" />
|
<property name="DefaultGoTemplateProperty" value="Go File" />
|
||||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||||
<property name="go.import.settings.migrated" value="true" />
|
<property name="go.import.settings.migrated" value="true" />
|
||||||
<property name="go.sdk.automatically.set" value="true" />
|
<property name="go.sdk.automatically.set" value="true" />
|
||||||
|
<property name="go.tried.to.enable.integration.vgo.integrator" value="true" />
|
||||||
<property name="last_opened_file_path" value="$PROJECT_DIR$/embedded" />
|
<property name="last_opened_file_path" value="$PROJECT_DIR$/embedded" />
|
||||||
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||||
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
||||||
@@ -50,8 +55,53 @@
|
|||||||
<recent name="C:\Users\BGrewell\repos\go-iperf\embedded" />
|
<recent name="C:\Users\BGrewell\repos\go-iperf\embedded" />
|
||||||
</key>
|
</key>
|
||||||
</component>
|
</component>
|
||||||
|
<component name="RunManager">
|
||||||
|
<configuration name="go build github.com/BGrewell/go-iperf/cmd" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||||
|
<module name="go-iperf" />
|
||||||
|
<working_directory value="$PROJECT_DIR$" />
|
||||||
|
<kind value="PACKAGE" />
|
||||||
|
<filePath value="$PROJECT_DIR$/cmd/main.go" />
|
||||||
|
<package value="github.com/BGrewell/go-iperf/cmd" />
|
||||||
|
<directory value="$PROJECT_DIR$" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
<recent_temporary>
|
||||||
|
<list>
|
||||||
|
<item itemvalue="Go Build.go build github.com/BGrewell/go-iperf/cmd" />
|
||||||
|
</list>
|
||||||
|
</recent_temporary>
|
||||||
|
</component>
|
||||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
<option name="version" value="3" />
|
<option name="version" value="3" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="VgoProject">
|
||||||
|
<integration-enabled>true</integration-enabled>
|
||||||
|
</component>
|
||||||
|
<component name="WindowStateProjectService">
|
||||||
|
<state x="652" y="533" key="#Go_Modules" timestamp="1608060904277">
|
||||||
|
<screen x="0" y="0" width="3440" height="1400" />
|
||||||
|
</state>
|
||||||
|
<state x="652" y="533" key="#Go_Modules/0.0.3440.1400@0.0.3440.1400" timestamp="1608060904277" />
|
||||||
|
<state width="1676" height="403" key="GridCell.Tab.0.bottom" timestamp="1608066744405">
|
||||||
|
<screen x="0" y="0" width="3440" height="1400" />
|
||||||
|
</state>
|
||||||
|
<state width="1676" height="403" key="GridCell.Tab.0.bottom/0.0.3440.1400@0.0.3440.1400" timestamp="1608066744405" />
|
||||||
|
<state width="1676" height="403" key="GridCell.Tab.0.center" timestamp="1608066744404">
|
||||||
|
<screen x="0" y="0" width="3440" height="1400" />
|
||||||
|
</state>
|
||||||
|
<state width="1676" height="403" key="GridCell.Tab.0.center/0.0.3440.1400@0.0.3440.1400" timestamp="1608066744404" />
|
||||||
|
<state width="1676" height="403" key="GridCell.Tab.0.left" timestamp="1608066744404">
|
||||||
|
<screen x="0" y="0" width="3440" height="1400" />
|
||||||
|
</state>
|
||||||
|
<state width="1676" height="403" key="GridCell.Tab.0.left/0.0.3440.1400@0.0.3440.1400" timestamp="1608066744404" />
|
||||||
|
<state width="1676" height="403" key="GridCell.Tab.0.right" timestamp="1608066744404">
|
||||||
|
<screen x="0" y="0" width="3440" height="1400" />
|
||||||
|
</state>
|
||||||
|
<state width="1676" height="403" key="GridCell.Tab.0.right/0.0.3440.1400@0.0.3440.1400" timestamp="1608066744404" />
|
||||||
|
<state x="431" y="297" key="com.intellij.openapi.editor.actions.MultiplePasteAction$ClipboardContentChooser" timestamp="1608062415393">
|
||||||
|
<screen x="0" y="0" width="3440" height="1400" />
|
||||||
|
</state>
|
||||||
|
<state x="431" y="297" key="com.intellij.openapi.editor.actions.MultiplePasteAction$ClipboardContentChooser/0.0.3440.1400@0.0.3440.1400" timestamp="1608062415393" />
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,2 +1,6 @@
|
|||||||
# go-iperf
|
# go-iperf
|
||||||
A Go based wrapper around iperf3
|
A Go based wrapper around iperf3
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
go-bindata -pkg iperf -prefix "embedded/" embedded/```
|
||||||
|
|||||||
58
bindata.go
58
bindata.go
File diff suppressed because one or more lines are too long
43
client.go
Normal file
43
client.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package iperf
|
||||||
|
|
||||||
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
|
func NewClient() *Client {
|
||||||
|
json := true
|
||||||
|
proto := Protocol(PROTO_TCP)
|
||||||
|
time := 10
|
||||||
|
length := "128KB"
|
||||||
|
streams := 1
|
||||||
|
c := &Client{
|
||||||
|
JSON: &json,
|
||||||
|
Proto: &proto,
|
||||||
|
TimeSec: &time,
|
||||||
|
Length: &length,
|
||||||
|
Streams: &streams,
|
||||||
|
}
|
||||||
|
c.Id = uuid.New().String()
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
SharedOptions
|
||||||
|
Host string
|
||||||
|
Proto *Protocol
|
||||||
|
Bandwidth *string
|
||||||
|
TimeSec *int
|
||||||
|
Bytes *string
|
||||||
|
BlockCount *string
|
||||||
|
Length *string
|
||||||
|
Streams *int
|
||||||
|
Reverse *bool
|
||||||
|
Window *string
|
||||||
|
MSS *int
|
||||||
|
NoDelay *bool
|
||||||
|
Version4 *bool
|
||||||
|
Version6 *bool
|
||||||
|
TOS *int
|
||||||
|
ZeroCopy *bool
|
||||||
|
OmitSec *int
|
||||||
|
Prefix *string
|
||||||
|
JSON *bool
|
||||||
|
}
|
||||||
22
cmd/main.go
22
cmd/main.go
@@ -1,5 +1,25 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/BGrewell/go-iperf"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
s := iperf.NewServer()
|
||||||
|
c := iperf.NewClient()
|
||||||
|
fmt.Println(s.Id)
|
||||||
|
fmt.Println(c.Id)
|
||||||
|
|
||||||
|
err := s.Start()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
for s.Running {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Server exit code: %d\n", *s.ExitCode)
|
||||||
|
iperf.Cleanup()
|
||||||
}
|
}
|
||||||
|
|||||||
41
execute.go
Normal file
41
execute.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package iperf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Execute(cmd string, outPipe io.ReadCloser, errPipe io.ReadCloser, exit chan <- int) (err error) {
|
||||||
|
cmdParts := strings.Fields(cmd)
|
||||||
|
binary, err := exec.LookPath(cmdParts[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
exe := exec.Command(binary, cmdParts[1:]...)
|
||||||
|
outPipe, err = exe.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
errPipe, err = exe.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = exe.Start()
|
||||||
|
if err != nil {
|
||||||
|
return 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exit <- 0
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
2
go.mod
2
go.mod
@@ -1,3 +1,5 @@
|
|||||||
module github.com/BGrewell/go-iperf
|
module github.com/BGrewell/go-iperf
|
||||||
|
|
||||||
go 1.15
|
go 1.15
|
||||||
|
|
||||||
|
require github.com/google/uuid v1.1.2
|
||||||
|
|||||||
2
go.sum
Normal file
2
go.sum
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
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=
|
||||||
68
iperf.go
68
iperf.go
@@ -1,2 +1,70 @@
|
|||||||
package iperf
|
package iperf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Debug = true
|
||||||
|
binaryDir = ""
|
||||||
|
binaryLocation = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Extract the binaries
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
err := extractWindowsEmbeddedBinaries()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error initializing iperf: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := extractLinuxEmbeddedBinaries()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error initializing iperf: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Cleanup() {
|
||||||
|
os.RemoveAll(binaryDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractWindowsEmbeddedBinaries() (err error) {
|
||||||
|
files := []string{"cygwin1.dll", "iperf3.exe"}
|
||||||
|
err = extractEmbeddedBinaries(files)
|
||||||
|
binaryLocation = path.Join(binaryDir, "iperf3.exe")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractLinuxEmbeddedBinaries() (err error) {
|
||||||
|
files := []string{"iperf3"}
|
||||||
|
err = extractEmbeddedBinaries(files)
|
||||||
|
binaryLocation = path.Join(binaryDir, "iperf3")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractEmbeddedBinaries(files []string) (err error) {
|
||||||
|
binaryDir, err = ioutil.TempDir("", "goiperf")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create temporary iperf directory: %v", err)
|
||||||
|
}
|
||||||
|
for _, file := range files {
|
||||||
|
data, err := Asset(file)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to extract embedded iperf: %v", err)
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(path.Join(binaryDir, file), data, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to save embedded iperf: %v", err)
|
||||||
|
}
|
||||||
|
if Debug {
|
||||||
|
log.Printf("extracted file: %s\n", path.Join(binaryDir, file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
8
protocol.go
Normal file
8
protocol.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package iperf
|
||||||
|
|
||||||
|
type Protocol string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PROTO_TCP = "tcp"
|
||||||
|
PROTO_UDP = "udp"
|
||||||
|
)
|
||||||
50
server.go
Normal file
50
server.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package iperf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewServer() *Server {
|
||||||
|
s := &Server{
|
||||||
|
}
|
||||||
|
s.Id = uuid.New().String()
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
SharedOptions
|
||||||
|
OneOff *bool
|
||||||
|
ExitCode *int
|
||||||
|
Running bool
|
||||||
|
outputStream io.ReadCloser
|
||||||
|
errorStream io.ReadCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start() (err error) {
|
||||||
|
exit := make(chan int, 0)
|
||||||
|
err = Execute(fmt.Sprintf("%s -s", binaryLocation), s.outputStream, s.errorStream, exit)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.Running = true
|
||||||
|
go func() {
|
||||||
|
ds := DebugScanner{}
|
||||||
|
ds.Scan(s.outputStream)
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
ds := DebugScanner{}
|
||||||
|
ds.Scan(s.errorStream)
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
exitCode := <- exit
|
||||||
|
s.ExitCode = &exitCode
|
||||||
|
s.Running = false
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Stop() {
|
||||||
|
|
||||||
|
}
|
||||||
31
shared.go
Normal file
31
shared.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package iperf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SharedOptions struct {
|
||||||
|
Id string
|
||||||
|
Port *int
|
||||||
|
Format *rune
|
||||||
|
Interval *int
|
||||||
|
}
|
||||||
|
|
||||||
|
type DebugScanner struct {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ds *DebugScanner) Scan(buff io.ReadCloser) {
|
||||||
|
if buff == nil {
|
||||||
|
fmt.Println("unable to read, ReadCloser is nil")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
scanner := bufio.NewScanner(buff)
|
||||||
|
scanner.Split(bufio.ScanWords)
|
||||||
|
for scanner.Scan() {
|
||||||
|
text := scanner.Text()
|
||||||
|
fmt.Println(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user