hnakamur / go-scp

[Unmaintained] A scp client library written in Go
MIT License
41 stars 23 forks source link

Connection is not closed #12

Closed fallais closed 5 years ago

fallais commented 5 years ago

Is there a way to ensure that the connection is closed after the SCP is done ? I use this lib and I reached 3k connections left opened...

Thanks a lot !

hnakamur commented 5 years ago

Sorry for being late.

Could you give me an example code that make connections left opened?

Actually https://godoc.org/golang.org/x/crypto/ssh#Session.Close is called at https://github.com/hnakamur/go-scp/blob/b745e1ba4be9eb078b9eee1039be7a87d2a5b197/source.go#L230 (which is called from https://github.com/hnakamur/go-scp/blob/b745e1ba4be9eb078b9eee1039be7a87d2a5b197/source.go#L249) and https://github.com/hnakamur/go-scp/blob/b745e1ba4be9eb078b9eee1039be7a87d2a5b197/sink.go#L324 (which is called from https://github.com/hnakamur/go-scp/blob/b745e1ba4be9eb078b9eee1039be7a87d2a5b197/sink.go#L336)

fallais commented 5 years ago

Hello,

No problem. Here it is.

// pullFileBySCP
func pullFileBySCP(fileID, server string, port int64, username, password, path, file string) error {
    // Create the SSH configuration
    sshConfig := &ssh.ClientConfig{
        User: username,
        Auth: []ssh.AuthMethod{
            ssh.Password(password),
        },
        HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
            return nil
        },
    }

    // Create a new SSH connection
    sshClient, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", server, port), sshConfig)
    if err != nil {
        return fmt.Errorf("Error while creating the SSH client : %s", err)
    }

    // Create the SCP client
    scpClient := scp.NewSCP(sshClient)

    // Create the destination file
    dstFile, err := os.Create(fmt.Sprintf("%s/%s", shared.TmpDir, fileID))
    if err != nil {
        return fmt.Errorf("Error while creating the destination file : %s", err)
    }
    defer dstFile.Close()

    // Copy the file
    _, err = scpClient.Receive(fmt.Sprintf("%s%s", path, file), dstFile)
    if err != nil {
        return fmt.Errorf("Error while copying the file : %s", err)
    }

    return nil
}

If I do not add defer sshClient.Conn.Close(), all the connections remain opened.

hnakamur commented 5 years ago

Thanks for your example.

It is caller's responsibility to call Close for your sshClient.

In test codes, the Close of https://godoc.org/golang.org/x/crypto/ssh#Conn which is embedded in https://godoc.org/golang.org/x/crypto/ssh#Client is called at: https://github.com/hnakamur/go-scp/blob/b745e1ba4be9eb078b9eee1039be7a87d2a5b197/sink_test.go#L26 https://github.com/hnakamur/go-scp/blob/b745e1ba4be9eb078b9eee1039be7a87d2a5b197/source_test.go#L39

I'll add update the documentation of NewSCP

fallais commented 5 years ago

Wow ! You mean that in my case, calling sshClient.Close() is the same as sshClient.Conn.Close() because it is wrapped ? What is the name of this mechanism please ? I never heard of it, powerful !

I search the Close() in the documentation of ssh but I did not find it, that is why I was surprised..

Thanks ! And yes, updating your README could be awesome !

hnakamur commented 5 years ago

It is called embedding. Please refer https://golang.org/doc/effective_go.html#embedding

hnakamur commented 5 years ago

I updated the document of NewSCP and added an example at https://godoc.org/github.com/hnakamur/go-scp

fallais commented 5 years ago

Awesome, thanks a lot !

I suggest that adding an example in your README could be great for everybody, just saying. Why ? Because your library deserves to be more known as I did not find many libraries that allow to copy a file FROM a remote server TO a local destination, but I may be wrong..

hnakamur commented 5 years ago

Thanks for your suggestion. I added a link to the example at godoc in README.