diff options
Diffstat (limited to 'tempfork')
| -rw-r--r-- | tempfork/gliderlabs/ssh/session.go | 9 | ||||
| -rw-r--r-- | tempfork/gliderlabs/ssh/tcpip.go | 29 |
2 files changed, 33 insertions, 5 deletions
diff --git a/tempfork/gliderlabs/ssh/session.go b/tempfork/gliderlabs/ssh/session.go index a7a9a3eeb..ef068355e 100644 --- a/tempfork/gliderlabs/ssh/session.go +++ b/tempfork/gliderlabs/ssh/session.go @@ -188,7 +188,12 @@ func (sess *session) Exit(code int) error { if err != nil { return err } - return sess.Close() + // Don't close the channel here. Per RFC 4254 section 6.10, the exit-status + // message should be sent before the channel is closed. By not closing immediately, + // we allow the session handler to complete any remaining I/O operations (like + // flushing output and sending EOF via CloseWrite) before the channel is closed + // by the request handler's cleanup code. + return nil } func (sess *session) User() string { @@ -273,6 +278,7 @@ func (sess *session) handleRequests(reqs <-chan *gossh.Request) { go func() { sess.handler(sess) sess.Exit(0) + sess.Close() }() case "subsystem": if sess.handled { @@ -307,6 +313,7 @@ func (sess *session) handleRequests(reqs <-chan *gossh.Request) { go func() { handler(sess) sess.Exit(0) + sess.Close() }() case "env": if sess.handled { diff --git a/tempfork/gliderlabs/ssh/tcpip.go b/tempfork/gliderlabs/ssh/tcpip.go index 335fda657..307cc53cb 100644 --- a/tempfork/gliderlabs/ssh/tcpip.go +++ b/tempfork/gliderlabs/ssh/tcpip.go @@ -53,16 +53,37 @@ func DirectTCPIPHandler(srv *Server, conn *gossh.ServerConn, newChan gossh.NewCh } go gossh.DiscardRequests(reqs) + defer ch.Close() + defer dconn.Close() + + done := make(chan struct{}, 2) go func() { - defer ch.Close() - defer dconn.Close() + defer ch.CloseWrite() + defer closeRead(dconn) io.Copy(ch, dconn) + done <- struct{}{} }() go func() { - defer ch.Close() - defer dconn.Close() + defer closeWrite(dconn) io.Copy(dconn, ch) + done <- struct{}{} }() + <-done + <-done +} + +func closeWrite(c net.Conn) error { + if cw, ok := c.(interface{ CloseWrite() error }); ok { + return cw.CloseWrite() + } + return c.Close() +} + +func closeRead(c net.Conn) error { + if cr, ok := c.(interface{ CloseRead() error }); ok { + return cr.CloseRead() + } + return c.Close() } type remoteForwardRequest struct { |
