-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
io.Copy Error for closing tunnel #8
Comments
Can you provide the complete example? |
@elliotchance But maybe you could help out in creating a complete example setup w. docker and stuff as I am unable to create a tunnel and sftp locally. here is the example I can give you. That should be working https://github.com/eleijonmarck/go-ssh-tunnel go code specifically: package main
import (
"io/ioutil"
"log"
"os"
"time"
"github.com/elliotchance/sshtunnel"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
)
func main() {
client, err := startTunnel()
if err != nil {
log.Printf("errrrrorrr %s", err)
}
sftpclient, err := sftp.NewClient(client)
if err != nil {
log.Printf("unable to create sftp client with error: %s", err)
}
defer sftpclient.Close()
// check it's there
fi, err := sftpclient.Lstat("toSEB")
if err != nil {
log.Printf("seb upload test failed to upload a file w. error: %s", err)
}
log.Printf("fi %v", fi)
}
func startTunnel() (*ssh.Client, error) {
portForwarded := "2000"
sftpHostUser := "root"
// Connection settings
sftpHostServer := "localhost:2222"
sftpRemoteServer := "localhost:3333"
tunnel := sshtunnel.NewSSHTunnel(
// User and host of tunnel server, it will default to port 22
// if not specified.
sftpHostUser+"@"+sftpHostServer,
// authentication
// auth, // 1. private key
ssh.Password("root"), // 1. private key
// The destination host and port of the actual server.
sftpRemoteServer,
// The local port you want to bind the remote port to.
// Specifying "0" will lead to a random port.
portForwarded,
)
// You can provide a logger for debugging, or remove this line to
// make it silent.
tunnel.Log = log.New(os.Stdout, "", log.Ldate|log.Lmicroseconds)
// Start the server in the background. You will need to wait a
// small amount of time for it to bind to the localhost port
// before you can start sending connections.
go tunnel.Start()
// known io.Copy error:
// even if we wait 5 seconds we still get logs of io.Copy error use of closed connection
defer func() {
time.Sleep(5 * time.Second)
tunnel.Close()
}()
time.Sleep(100 * time.Millisecond)
log.Printf("started tunnel")
log.Printf("tunnel %+v", tunnel)
sftpHostUser = "docker"
keyPath := "./ssh_host_payout_staging_rsa_key"
buff, err := ioutil.ReadFile(keyPath)
if err != nil {
log.Printf("unable to read the privatye key %s, w. error: %s", keyPath, err)
}
signer, err := ssh.ParsePrivateKey(buff)
if err != nil {
log.Printf("unable to parse key")
}
auth := ssh.PublicKeys(signer)
config := &ssh.ClientConfig{
User: sftpHostUser,
Auth: []ssh.AuthMethod{
auth,
},
Timeout: 3 * time.Second,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
hostNetwork := "localhost"
log.Printf("dialing %s:%s", hostNetwork, portForwarded)
return ssh.Dial("tcp", hostNetwork+":"+portForwarded, config)
} |
I suspect it's because ou're closing the sshtunnel in a defer from startTunnel. You will need to close the client in a defer in the parent scope: func main() {
client, tunnel, err := startTunnel()
if err != nil {
log.Printf("errrrrorrr %s", err)
}
defer tunnel.Close()
// ...
}
func startTunnel() (*ssh.Client, *sshtunnel.SSHTunnel, error) {
go tunnel.Start()
client, err := ssh.Dial("tcp", hostNetwork+":"+portForwarded, config)
if err != nil {
return nil, nil, err
}
return client, tunnel, nil
} |
okay that was maybe not representative of the functino I am calling: func downloadFiles(s *service) error {
portForwarded := "3333"
tunnel, err := getTunnel(portForwarded)
if err != nil {
return fmt.Errorf("unable to setup tunnel for files: %w", err)
}
// Start the server in the background. You will need to wait a
// small amount of time for it to bind to the localhost port
// before you can start sending connections.
go tunnel.Start()
defer tunnel.Close()
time.Sleep(100 * time.Millisecond)
log.Print("tunnel connected")
// connect to sftp
sshClient, err := connectSFTP(portForwarded)
if err != nil {
return fmt.Errorf("error happened while connecting to SFTP: %w", err)
}
err = lookForFile(s, sshClient)
if err != nil {
return fmt.Errorf("error happened while downloading files: %w", err)
}
return nil
}
// ideally we would download these files first and then parse for the statuses of the files
func lookForFile(s *service, sshClient *ssh.Client) error {
client, err := sftp.NewClient(sshClient)
if err != nil {
return fmt.Errorf("unable to create sftp client with error: %w", err)
}
defer client.Close()
} I am only using the tunnel inside this scope |
Sorry, I'm not sure what going on. Perhaps there is something that is closing the connection on the other end? |
@elliotchance I have updated the example with the lookForFile function that I am using. But it is only closing the sftp client that is using the sshClient that is connected to the tunnel. Maybe I have to reverse the order in which I am closing the connections. now the defers are in this order when executing client.Close()
sshClient.Close()
tunnel.Close() |
I am experiencing a bit of error logs from the tunnel implementation.
Even if I wait 5 seconds for the tunnel to get any io.Copys out of the way (and I am not creating anything or so) I still get an error of io.Copy
This is probably the interval workings of the tunnel implementation and closing before closing io.Copy implementations.
The text was updated successfully, but these errors were encountered: