From cca2895526872e83eb2e66cc1f2b76fb33646ba8 Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Wed, 17 Jan 2018 20:36:53 -0800 Subject: [PATCH] Took a step back on cmd exec, just getting EOF/hangup on client/server ends working --- demo/client/client.go | 51 +++++++++++++++++++++++++++++++++++++++---- demo/server/server.go | 40 ++++++++++++++++----------------- 2 files changed, 67 insertions(+), 24 deletions(-) diff --git a/demo/client/client.go b/demo/client/client.go index 64b3284..b09c17d 100644 --- a/demo/client/client.go +++ b/demo/client/client.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "os" + "sync" hkex "blitter.com/herradurakex" ) @@ -22,6 +23,8 @@ import ( // connection (app-specific, passed through to the server to use or // ignore at its discretion). func main() { + var wg sync.WaitGroup + var cAlg string var hAlg string var server string @@ -36,8 +39,48 @@ func main() { fmt.Println("Err!") panic(err) } - _, err = io.Copy(conn, os.Stdin) - if err != nil && err.Error() != "EOF" { - fmt.Println(err) - } + defer conn.Close() + + 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() } diff --git a/demo/server/server.go b/demo/server/server.go index 23f8cae..67d63c5 100644 --- a/demo/server/server.go +++ b/demo/server/server.go @@ -29,18 +29,11 @@ const ( type Op uint8 type cmdRunner struct { - op Op - who string - arg string - authCookie string - CloseHandler func(*cmdRunner) - status int -} - -func testCloseHandler(r *cmdRunner) { - fmt.Println("[testCloseHandler()]") - r.arg = "/usr/bin/touch " + r.arg - cmd(r) + op Op + who string + arg string + authCookie string + status int } func cmd(r *cmdRunner) { @@ -134,7 +127,7 @@ func main() { }(ch, eCh) ticker := time.Tick(time.Second / 100) - var r cmdRunner + //var r cmdRunner var connOp *byte = nil Term: // continuously read from the connection @@ -157,12 +150,20 @@ func main() { fmt.Printf("[* connOp '%c']\n", *connOp) // The CloseHandler typically handles the // accumulated command data - r = cmdRunner{op: Op(*connOp), - who: "larissa", arg: string(data), - authCookie: "c00ki3", - CloseHandler: testCloseHandler, - status: 0} - conn.Write([]byte("SERVER OUTPUT")) + //r = cmdRunner{op: Op(*connOp), + // who: "larissa", arg: string(data), + // authCookie: "c00ki3", + // status: 0} + } + + // 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)) @@ -171,7 +172,6 @@ func main() { // handle our error then exit for loop if err.Error() == "EOF" { fmt.Printf("[Client disconnected]\n") - r.CloseHandler(&r) } else { fmt.Printf("Error reading client data! (%+v)\n", err) }