summaryrefslogtreecommitdiffhomepage
path: root/tempfork
diff options
context:
space:
mode:
Diffstat (limited to 'tempfork')
-rw-r--r--tempfork/gliderlabs/ssh/session.go9
-rw-r--r--tempfork/gliderlabs/ssh/tcpip.go29
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 {