added a event pipe to break unix.Poll better for local pty
This commit is contained in:
@ -41,6 +41,7 @@ func (pty *client_pty_ws) ServeWebsocket(ws *websocket.Conn) (int, error) {
|
||||
var out *os.File
|
||||
var tty *os.File
|
||||
var cmd *exec.Cmd
|
||||
var pfd [2]int = [2]int{ -1, -1 }
|
||||
var wg sync.WaitGroup
|
||||
var conn_ready_chan chan bool
|
||||
var err error
|
||||
@ -63,9 +64,9 @@ func (pty *client_pty_ws) ServeWebsocket(ws *websocket.Conn) (int, error) {
|
||||
var n int
|
||||
var err error
|
||||
|
||||
|
||||
poll_fds = []unix.PollFd{
|
||||
unix.PollFd{Fd: int32(out.Fd()), Events: unix.POLLIN},
|
||||
unix.PollFd{Fd: int32(pfd[0]), Events: unix.POLLIN},
|
||||
}
|
||||
|
||||
c.stats.pty_sessions.Add(1)
|
||||
@ -84,6 +85,10 @@ func (pty *client_pty_ws) ServeWebsocket(ws *websocket.Conn) (int, error) {
|
||||
c.log.Write(pty.Id, LOG_DEBUG, "[%s] EOF detected on pty stdout", req.RemoteAddr)
|
||||
break
|
||||
}
|
||||
if (poll_fds[1].Revents & (unix.POLLERR | unix.POLLHUP | unix.POLLNVAL)) != 0 {
|
||||
c.log.Write(pty.Id, LOG_DEBUG, "[%s] EOF detected on pty event pipe", req.RemoteAddr)
|
||||
break
|
||||
}
|
||||
|
||||
if (poll_fds[0].Revents & unix.POLLIN) != 0 {
|
||||
n, err = out.Read(buf[:])
|
||||
@ -102,6 +107,10 @@ func (pty *client_pty_ws) ServeWebsocket(ws *websocket.Conn) (int, error) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (poll_fds[1].Revents & unix.POLLIN) != 0 {
|
||||
c.log.Write(pty.Id, LOG_DEBUG, "[%s] Stop request noticed on pty event pipe", req.RemoteAddr)
|
||||
break
|
||||
}
|
||||
}
|
||||
c.stats.pty_sessions.Add(-1)
|
||||
}
|
||||
@ -120,6 +129,7 @@ ws_recv_loop:
|
||||
switch ev.Type {
|
||||
case "open":
|
||||
if tty == nil && len(ev.Data) == 2 {
|
||||
// not using username and password for now...
|
||||
//username = string(ev.Data[0])
|
||||
//password = string(ev.Data[1])
|
||||
|
||||
@ -128,23 +138,38 @@ ws_recv_loop:
|
||||
var err error
|
||||
|
||||
defer wg.Done()
|
||||
|
||||
err = unix.Pipe(pfd[:])
|
||||
if err != nil {
|
||||
c.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to create event pipe for pty - %s", req.RemoteAddr, err.Error())
|
||||
send_ws_data_for_xterm(ws, "error", err.Error())
|
||||
ws.Close() // dirty way to flag out the error
|
||||
return
|
||||
}
|
||||
|
||||
cmd, tty, err = connect_pty(c.pty_shell, c.pty_user)
|
||||
if err != nil {
|
||||
c.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to connect pty - %s", req.RemoteAddr, err.Error())
|
||||
send_ws_data_for_xterm(ws, "error", err.Error())
|
||||
ws.Close() // dirty way to flag out the error
|
||||
} else {
|
||||
err = send_ws_data_for_xterm(ws, "status", "opened")
|
||||
if err != nil {
|
||||
c.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to write opened event to websocket - %s", req.RemoteAddr, err.Error())
|
||||
ws.Close() // dirty way to flag out the error
|
||||
} else {
|
||||
c.log.Write(pty.Id, LOG_DEBUG, "[%s] Opened pty session", req.RemoteAddr)
|
||||
out = tty
|
||||
in = tty
|
||||
conn_ready_chan <- true
|
||||
}
|
||||
unix.Close(pfd[0]); pfd[0] = -1
|
||||
unix.Close(pfd[1]); pfd[1] = -1
|
||||
return
|
||||
}
|
||||
|
||||
err = send_ws_data_for_xterm(ws, "status", "opened")
|
||||
if err != nil {
|
||||
c.log.Write(pty.Id, LOG_ERROR, "[%s] Failed to write opened event to websocket - %s", req.RemoteAddr, err.Error())
|
||||
ws.Close() // dirty way to flag out the error
|
||||
unix.Close(pfd[0]); pfd[0] = -1
|
||||
unix.Close(pfd[1]); pfd[1] = -1
|
||||
return
|
||||
}
|
||||
|
||||
c.log.Write(pty.Id, LOG_DEBUG, "[%s] Opened pty session", req.RemoteAddr)
|
||||
out = tty
|
||||
in = tty
|
||||
conn_ready_chan <- true
|
||||
}()
|
||||
}
|
||||
|
||||
@ -153,6 +178,9 @@ ws_recv_loop:
|
||||
tty.Close()
|
||||
tty = nil
|
||||
}
|
||||
if pfd[1] >= 0 {
|
||||
unix.Write(pfd[1], []byte{0})
|
||||
}
|
||||
break ws_recv_loop
|
||||
|
||||
case "iov":
|
||||
@ -194,6 +222,11 @@ done:
|
||||
if tty != nil { tty.Close() }
|
||||
if cmd != nil { cmd.Wait() }
|
||||
wg.Wait()
|
||||
|
||||
// close the event pipe after all goroutines are over
|
||||
if pfd[0] >= 0 { unix.Close(pfd[0]) }
|
||||
if pfd[1] >= 0 { unix.Close(pfd[1]) }
|
||||
|
||||
c.log.Write(pty.Id, LOG_DEBUG, "[%s] Ended pty session", req.RemoteAddr)
|
||||
|
||||
return http.StatusOK, err
|
||||
|
Reference in New Issue
Block a user