Took a step back on cmd exec, just getting EOF/hangup on client/server ends working

This commit is contained in:
Russ Magee 2018-01-17 20:36:53 -08:00
parent ad5366bdfb
commit cca2895526
2 changed files with 67 additions and 24 deletions

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"sync"
hkex "blitter.com/herradurakex" hkex "blitter.com/herradurakex"
) )
@ -22,6 +23,8 @@ import (
// connection (app-specific, passed through to the server to use or // connection (app-specific, passed through to the server to use or
// ignore at its discretion). // ignore at its discretion).
func main() { func main() {
var wg sync.WaitGroup
var cAlg string var cAlg string
var hAlg string var hAlg string
var server string var server string
@ -36,8 +39,48 @@ func main() {
fmt.Println("Err!") fmt.Println("Err!")
panic(err) panic(err)
} }
_, err = io.Copy(conn, os.Stdin) defer conn.Close()
if err != nil && err.Error() != "EOF" {
fmt.Println(err) wg.Add(1)
} go func() {
// This will guarantee the side that closes first
// marks its direction's goroutine as finished.
// Whichever direction's goroutine finishes first
// will call wg.Done() once more explicitly to
// hang up on the other side so the client
// exits immediately on an EOF from either side.
defer wg.Done()
// io.Copy() expects EOF so this will
// exit with inerr == nil
_, inerr := io.Copy(os.Stdout, conn)
if inerr != nil {
if inerr.Error() != "EOF" {
fmt.Println(inerr)
os.Exit(1)
}
}
fmt.Println("[Got Write EOF]")
wg.Done() // client hanging up, close server read goroutine
}()
wg.Add(1)
go func() {
defer wg.Done()
// io.Copy() expects EOF so this will
// exit with outerr == nil
_, outerr := io.Copy(conn, os.Stdin)
if outerr != nil {
if outerr.Error() != "EOF" {
fmt.Println(outerr)
os.Exit(2)
}
}
fmt.Println("[Got Read EOF]")
wg.Done() // server hung up, close client write goroutine
}()
// Wait until both stdin and stdout goroutines finish
wg.Wait()
} }

View File

@ -29,18 +29,11 @@ const (
type Op uint8 type Op uint8
type cmdRunner struct { type cmdRunner struct {
op Op op Op
who string who string
arg string arg string
authCookie string authCookie string
CloseHandler func(*cmdRunner) status int
status int
}
func testCloseHandler(r *cmdRunner) {
fmt.Println("[testCloseHandler()]")
r.arg = "/usr/bin/touch " + r.arg
cmd(r)
} }
func cmd(r *cmdRunner) { func cmd(r *cmdRunner) {
@ -134,7 +127,7 @@ func main() {
}(ch, eCh) }(ch, eCh)
ticker := time.Tick(time.Second / 100) ticker := time.Tick(time.Second / 100)
var r cmdRunner //var r cmdRunner
var connOp *byte = nil var connOp *byte = nil
Term: Term:
// continuously read from the connection // continuously read from the connection
@ -157,12 +150,20 @@ func main() {
fmt.Printf("[* connOp '%c']\n", *connOp) fmt.Printf("[* connOp '%c']\n", *connOp)
// The CloseHandler typically handles the // The CloseHandler typically handles the
// accumulated command data // accumulated command data
r = cmdRunner{op: Op(*connOp), //r = cmdRunner{op: Op(*connOp),
who: "larissa", arg: string(data), // who: "larissa", arg: string(data),
authCookie: "c00ki3", // authCookie: "c00ki3",
CloseHandler: testCloseHandler, // status: 0}
status: 0} }
conn.Write([]byte("SERVER OUTPUT"))
// From here, one could pass all subsequent data
// between client/server attached to an exec.Cmd,
// as data to/from a file, etc.
conn.Write([]byte("SERVER RESPONSE to '"))
conn.Write(data)
conn.Write([]byte("'\n"))
if strings.Trim(string(data), "\r\n") == "exit" {
conn.Close()
} }
//fmt.Printf("Client sent %s\n", string(data)) //fmt.Printf("Client sent %s\n", string(data))
@ -171,7 +172,6 @@ func main() {
// handle our error then exit for loop // handle our error then exit for loop
if err.Error() == "EOF" { if err.Error() == "EOF" {
fmt.Printf("[Client disconnected]\n") fmt.Printf("[Client disconnected]\n")
r.CloseHandler(&r)
} else { } else {
fmt.Printf("Error reading client data! (%+v)\n", err) fmt.Printf("Error reading client data! (%+v)\n", err)
} }