TL;DR - What is the proper way to close a golang.org/x/crypto/ssh
session freeing all resources?
My investigation thus far:
The golang.org/x/crypto/ssh
*Session
has a Close()
function which calls the *Channel
Close()
function which sends a message (I'm guessing to the remote server) to close, but I don't see anything about closing other resources like the pipe returned from the *Session
StdoutPipe()
function.
Looking at the *Session
Wait()
code, I see that the *Session stdinPipeWriter
is closed but nothing about the stdoutPipe
.
This package feels a lot like the os/exec
package which guarantees that using the os/exec Wait()
function will clean up all the resources. Doing some light digging there shows some similarities in the Wait()
functions. Both use the following construct to report errors on io.Copy
calls to their stdout, stderr, stdin readers/writers (well if I'm reading this correctly actually only one error) - crypto package shown:
var copyError error
for _ = range s.copyFuncs {
if err := <-s.errors; err != nil && copyError == nil {
copyError = err
}
}
But the os/exec
Wait()
also calls this close descriptor method
c.closeDescriptors(c.closeAfterWait)
which is just calling the close method on a slice of io.Closer
interfaces:
func (c *Cmd) closeDescriptors(closers []io.Closer) {
for _, fd := range closers {
fd.Close()
}
}
when os/exec
creates the pipe, it tracks what needs closing:
func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
if c.Stdout != nil {
return nil, errors.New("exec: Stdout already set")
}
if c.Process != nil {
return nil, errors.New("exec: StdoutPipe after process started")
}
pr, pw, err := os.Pipe()
if err != nil {
return nil, err
}
c.Stdout = pw
c.closeAfterStart = append(c.closeAfterStart, pw)
c.closeAfterWait = append(c.closeAfterWait, pr)
return pr, nil
}
During this I noticed that x/cyrpto/ssh
*Session StdoutPipe()
returns an io.Reader
and ox/exec
returns an io.ReadCloser
. And x/crypto/ssh
does not track what to close. I can't find a call to os.Pipe()
in the library so maybe the implementation is different and I'm missing something and confused by the Pipe name.