mirror of
https://gogs.blitter.com/RLabs/xs
synced 2024-08-14 10:26:42 +00:00
Added pty lib to give true terminal capability. raw mode/restore for client working
This commit is contained in:
parent
e8fe31f6d7
commit
49c589ee8d
3 changed files with 142 additions and 7 deletions
|
@ -10,6 +10,7 @@ import (
|
|||
"sync"
|
||||
|
||||
hkex "blitter.com/herradurakex"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Demo of a simple client that dials up to a simple test server to
|
||||
|
@ -45,6 +46,13 @@ func main() {
|
|||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Set stdin in raw mode.
|
||||
oldState, err := MakeRaw(int(os.Stdin.Fd()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() { _ = Restore(int(os.Stdin.Fd()), oldState) }() // Best effort.
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
// This will guarantee the side that closes first
|
||||
|
@ -64,7 +72,7 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
fmt.Println("[Got Write EOF]")
|
||||
log.Println("[Got Write EOF]")
|
||||
wg.Done() // client hanging up, close server read goroutine
|
||||
}()
|
||||
|
||||
|
@ -81,10 +89,68 @@ func main() {
|
|||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
fmt.Println("[Got Read EOF]")
|
||||
log.Println("[Got Read EOF]")
|
||||
wg.Done() // server hung up, close client write goroutine
|
||||
}()
|
||||
|
||||
// Wait until both stdin and stdout goroutines finish
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
/* ------------- minimal terminal APIs brought in from ssh/terminal
|
||||
* (they have no real business being there as they aren't specific to
|
||||
* ssh.)
|
||||
* -------------
|
||||
*/
|
||||
|
||||
const ioctlReadTermios = unix.TCGETS
|
||||
const ioctlWriteTermios = unix.TCSETS
|
||||
|
||||
// State contains the state of a terminal.
|
||||
type State struct {
|
||||
termios unix.Termios
|
||||
}
|
||||
|
||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||
// mode and returns the previous state of the terminal so that it can be
|
||||
// restored.
|
||||
func MakeRaw(fd int) (*State, error) {
|
||||
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldState := State{termios: *termios}
|
||||
|
||||
// This attempts to replicate the behaviour documented for cfmakeraw in
|
||||
// the termios(3) manpage.
|
||||
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
|
||||
termios.Oflag &^= unix.OPOST
|
||||
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
|
||||
termios.Cflag &^= unix.CSIZE | unix.PARENB
|
||||
termios.Cflag |= unix.CS8
|
||||
termios.Cc[unix.VMIN] = 1
|
||||
termios.Cc[unix.VTIME] = 0
|
||||
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oldState, nil
|
||||
}
|
||||
|
||||
// GetState returns the current state of a terminal which may be useful to
|
||||
// restore the terminal after a signal.
|
||||
func GetState(fd int) (*State, error) {
|
||||
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &State{termios: *termios}, nil
|
||||
}
|
||||
|
||||
// Restore restores the terminal connected to the given file descriptor to a
|
||||
// previous state.
|
||||
func Restore(fd int, state *State) error {
|
||||
return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os/exec"
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
"time"
|
||||
|
||||
hkex "blitter.com/herradurakex"
|
||||
"github.com/kr/pty"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -37,6 +39,60 @@ type cmdRunner struct {
|
|||
status int
|
||||
}
|
||||
|
||||
/* ------------- minimal terminal APIs brought in from ssh/terminal
|
||||
* (they have no real business being there as they aren't specific to
|
||||
* ssh.)
|
||||
* -------------
|
||||
*/
|
||||
|
||||
/*
|
||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
||||
// mode and returns the previous state of the terminal so that it can be
|
||||
// restored.
|
||||
func MakeRaw(fd int) (*State, error) {
|
||||
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldState := State{termios: *termios}
|
||||
|
||||
// This attempts to replicate the behaviour documented for cfmakeraw in
|
||||
// the termios(3) manpage.
|
||||
termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
|
||||
termios.Oflag &^= unix.OPOST
|
||||
termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
|
||||
termios.Cflag &^= unix.CSIZE | unix.PARENB
|
||||
termios.Cflag |= unix.CS8
|
||||
termios.Cc[unix.VMIN] = 1
|
||||
termios.Cc[unix.VTIME] = 0
|
||||
if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oldState, nil
|
||||
}
|
||||
|
||||
// GetState returns the current state of a terminal which may be useful to
|
||||
// restore the terminal after a signal.
|
||||
func GetState(fd int) (*State, error) {
|
||||
termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &State{termios: *termios}, nil
|
||||
}
|
||||
|
||||
// Restore restores the terminal connected to the given file descriptor to a
|
||||
// previous state.
|
||||
func Restore(fd int, state *State) error {
|
||||
return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios)
|
||||
}
|
||||
*/
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
func cmd(r *cmdRunner) {
|
||||
switch r.op {
|
||||
|
@ -72,7 +128,19 @@ func runCmdAs(who string, cmd string, conn hkex.Conn) (err error) {
|
|||
c.Stdout = conn
|
||||
c.Stderr = conn
|
||||
|
||||
err = c.Run()
|
||||
// Start the command with a pty.
|
||||
ptmx, err := pty.Start(c) // returns immediately with ptmx file
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Make sure to close the pty at the end.
|
||||
defer func() { _ = ptmx.Close() }() // Best effort.
|
||||
// Copy stdin to the pty and the pty to stdout.
|
||||
go func() { _, _ = io.Copy(ptmx, conn) }()
|
||||
_, _ = io.Copy(conn, ptmx)
|
||||
|
||||
//err = c.Run() // returns when c finishes.
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Command finished with error: %v", err)
|
||||
log.Printf("[%s]\n", cmd)
|
||||
|
@ -175,6 +243,7 @@ func main() {
|
|||
// Clear current op so user can enter next, or EOF
|
||||
connOp = nil
|
||||
fmt.Println("[Exiting shell]")
|
||||
conn.Close()
|
||||
}
|
||||
if strings.Trim(string(data), "\r\n") == "exit" {
|
||||
conn.Close()
|
||||
|
|
|
@ -175,7 +175,7 @@ func Dial(protocol string, ipport string, extensions ...string) (hc *Conn, err e
|
|||
// Close a hkex.Conn
|
||||
func (c Conn) Close() (err error) {
|
||||
err = c.c.Close()
|
||||
fmt.Println("[Conn Closing]")
|
||||
log.Println("[Conn Closing]")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,7 @@ func Listen(protocol string, ipport string) (hl HKExListener, e error) {
|
|||
if err != nil {
|
||||
return HKExListener{nil}, err
|
||||
}
|
||||
fmt.Println("[Listening]")
|
||||
log.Println("[Listening]")
|
||||
hl.l = l
|
||||
return
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ func Listen(protocol string, ipport string) (hl HKExListener, e error) {
|
|||
//
|
||||
// See go doc io.Close
|
||||
func (hl HKExListener) Close() error {
|
||||
fmt.Println("[Listener Closed]")
|
||||
log.Println("[Listener Closed]")
|
||||
return hl.l.Close()
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ func (hl HKExListener) Accept() (hc Conn, err error) {
|
|||
return Conn{c: nil, h: nil, cipheropts: 0, opts: 0,
|
||||
r: nil, w: nil}, err
|
||||
}
|
||||
fmt.Println("[Accepted]")
|
||||
log.Println("[Accepted]")
|
||||
|
||||
hc = Conn{c: c, h: New(0, 0), cipheropts: 0, opts: 0, op: 0, r: nil, w: nil}
|
||||
|
||||
|
|
Loading…
Reference in a new issue