initial implementation
This commit is contained in:
70
.idea/workspace.xml
generated
70
.idea/workspace.xml
generated
@@ -2,15 +2,16 @@
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<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$/cmd/main.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.gitignore" beforeDir="false" afterPath="$PROJECT_DIR$/.gitignore" 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$/client.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/execute.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/protocol.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/server.go" 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$/embedded/cygwin1.dll" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/embedded/iperf3" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/embedded/iperf3.exe" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/bindata.go" beforeDir="false" afterPath="$PROJECT_DIR$/bindata.go" afterDir="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" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
@@ -21,8 +22,8 @@
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Go File" />
|
||||
<option value="Go Application" />
|
||||
<option value="Go File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
@@ -30,17 +31,21 @@
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="GoLibraries">
|
||||
<option name="indexEntireGoPath" value="false" />
|
||||
</component>
|
||||
<component name="ProjectId" id="1lhjlU9mkZIWjchkp4HkX1szrI1" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="DefaultGoTemplateProperty" value="Go Application" />
|
||||
<property name="DefaultGoTemplateProperty" value="Go File" />
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="go.import.settings.migrated" 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="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
||||
@@ -50,8 +55,53 @@
|
||||
<recent name="C:\Users\BGrewell\repos\go-iperf\embedded" />
|
||||
</key>
|
||||
</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="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</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>
|
||||
@@ -1,2 +1,6 @@
|
||||
# go-iperf
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/BGrewell/go-iperf"
|
||||
"time"
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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