From 46cbc23d499ba1aebb16e36cd354689b0f15a667 Mon Sep 17 00:00:00 2001 From: Anisse Astier Date: Mon, 13 May 2019 10:08:41 +0200 Subject: Minimal client for QEMU websocket serial --- README.md | 1 + go.mod | 6 +++++ go.sum | 10 +++++++ main.go | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c13b75 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Minimal websocket serial client for QEMU websocket chardev. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..94a3a9d --- /dev/null +++ b/go.mod @@ -0,0 +1,6 @@ +module websocktty + +require ( + github.com/gorilla/websocket v1.4.0 + golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..eef9bca --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000..b2f80f8 --- /dev/null +++ b/main.go @@ -0,0 +1,89 @@ +package main + +import ( + "flag" + "fmt" + "log" + "net/http" + "net/url" + "os" + "os/signal" + "syscall" + "time" + + "github.com/gorilla/websocket" + "golang.org/x/crypto/ssh/terminal" +) + +var addr = flag.String("addr", "localhost:8080", "http service address") + +func main() { + flag.Parse() + log.SetFlags(0) + + interrupt := make(chan os.Signal, 1) + signal.Notify(interrupt, os.Interrupt) + signal.Notify(interrupt, syscall.SIGTERM) + + u := url.URL{Scheme: "ws", Host: *addr, Path: "/"} + log.Printf("connecting to %s. `kill -15 %d` to stop", u.String(), os.Getpid()) + + proto := make(http.Header) + proto.Add("Sec-WebSocket-Protocol", "binary") + c, _, err := websocket.DefaultDialer.Dial(u.String(), proto) + if err != nil { + log.Fatal("dial:", err) + } + defer c.Close() + + oldState, err := terminal.MakeRaw(0) + if err != nil { + fmt.Println("Cannot set input terminal in raw mode") + } + defer terminal.Restore(0, oldState) + + done := make(chan struct{}) + + go func() { + defer close(done) + for { + _, message, err := c.ReadMessage() + if err != nil { + log.Println("read:", err) + return + } + fmt.Fprintf(os.Stdout, "%s", message) + } + }() + + for { + select { + case <-done: + return + case <-interrupt: + log.Println("interrupt") + + // Cleanly close the connection by sending a close message and then + // waiting (with timeout) for the server to close the connection. + err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) + if err != nil { + log.Println("write close:", err) + return + } + select { + case <-done: + case <-time.After(time.Second): + } + return + default: + buf := make([]byte, 128) + n, err := os.Stdin.Read(buf) + err = c.WriteMessage(websocket.BinaryMessage, buf[:n]) + if err != nil { + log.Println("write:", err) + return + } + } + + } +} -- cgit v1.2.3