using System; using System.IO; using System.Threading; using Renci.SshNet; namespace cdrtool { public class sftp { private static SftpClient CreateClient( string host, int port, string username, string password) { var client = new SftpClient(host, port, username, password); client.ConnectionInfo.Timeout = System.TimeSpan.FromSeconds(15); client.OperationTimeout = System.TimeSpan.FromSeconds(30); client.KeepAliveInterval = System.TimeSpan.FromSeconds(10); return client; } public static Renci.SshNet.ConnectionInfo BuildConnectionInfo( string host, int port, string username, string password, Renci.SshNet.PrivateKeyFile privateKeyFile = null) { var auth = new System.Collections.Generic.List(); if (privateKeyFile != null) auth.Add(new Renci.SshNet.PrivateKeyAuthenticationMethod(username, privateKeyFile)); if (!string.IsNullOrEmpty(password)) { var kb = new Renci.SshNet.KeyboardInteractiveAuthenticationMethod(username); kb.AuthenticationPrompt += (s, e) => { foreach (var p in e.Prompts) p.Response = password; }; auth.Add(kb); auth.Add(new Renci.SshNet.PasswordAuthenticationMethod(username, password)); } return new Renci.SshNet.ConnectionInfo(host, port, username, auth.ToArray()) { Timeout = System.TimeSpan.FromSeconds(30), RetryAttempts = 1 }; } /* public static bool ConnectWithRetries( Renci.SshNet.ConnectionInfo info, int maxAttempts, int timeoutSeconds) { for (int i = 0; i < maxAttempts; i++) { if (TrySftpConnectWithHardTimeout(info, timeoutSeconds)) return true; System.Threading.Thread.Sleep(5000); } return false; } */ public static Renci.SshNet.SftpClient TrySftpConnectWithHardTimeout( Renci.SshNet.ConnectionInfo connectionInfo, int maxAttempts, int timeoutSeconds) { for (int i = 0; i < maxAttempts; i++) { Renci.SshNet.SftpClient client = null; try { var task = System.Threading.Tasks.Task.Run(() => { client = new Renci.SshNet.SftpClient(connectionInfo); // These are still useful, but not sufficient alone client.ConnectionInfo.Timeout = System.TimeSpan.FromSeconds(30); client.KeepAliveInterval = System.TimeSpan.FromSeconds(15); client.Connect(); }); bool completed = task.Wait(System.TimeSpan.FromSeconds(timeoutSeconds)); if (!completed) { // HARD TIMEOUT try { client?.Dispose(); } catch { } //return null; } else { return client; } } catch { try { client?.Dispose(); } catch { } //return null; } System.Threading.Thread.Sleep(5000); } return null; } public static void Upload_stream(MemoryStream ms, string filename, string host, int port, string username, string password) { int maxAttempts = 5; int timeout = 120; //seconds try { //using (var sftpClient = CreateClient(host, port, username, password)) var sftpInfo = BuildConnectionInfo(host, port, username, password); Renci.SshNet.SftpClient sftpClient = null; try { sftpClient = TrySftpConnectWithHardTimeout(sftpInfo, maxAttempts, timeout); } catch (Renci.SshNet.Common.SshConnectionException e) { Logger.Log(1, " connection exception ({0}) : {1}", "", e.Message); } if ( sftpClient == null) { Logger.Log(1, " null connection exception. Transfer failed."); return; } try { sftpClient.UploadFile( ms, filename, uploaded => { Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file."); }); } catch (Renci.SshNet.Common.SshException e) { Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message); } Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, host, port, (ms.Length / 1024)); sftpClient.Disconnect(); Logger.Log(" SSH Disconnected"); try { sftpClient?.Dispose(); } catch { } return; // success } catch (Exception e) { Logger.Log(0, "SFTP exception {0}:{1}", e.Message, e.InnerException.Message); } } public static void Upload_stream_linear(MemoryStream ms, string filename, string host, int port, string username, string password) { int attempts = 0; int maxAttempts = 5; while (true) { try { using (var sftpClient = CreateClient(host, port, username, password)) { attempts++; try { sftpClient.Connect(); } catch (Renci.SshNet.Common.SshConnectionException e) { Logger.Log(1, " connection exception ({0}) : {1}", attempts, e.Message); } //------------ if (!sftpClient.IsConnected) { Logger.Log(1, " connection failure {0}", attempts); if (attempts < 10) { Thread.Sleep(TimeSpan.FromSeconds(5)); continue; } else { break; }; } try { sftpClient.UploadFile( ms, filename, uploaded => { Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file."); }); } catch (Renci.SshNet.Common.SshException e) { Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message); } Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, host, port, (ms.Length / 1024)); sftpClient.Disconnect(); Logger.Log(" SSH Disconnected"); return; // success } } catch (Exception e) { Logger.Log(0, "SFTP exception {0}:{1}", e.Message, e.InnerException.Message); } attempts++; if (attempts >= maxAttempts) { Logger.Log(0, ("Failed to Connect after 10 attempts.")); return; } Logger.Log(1, " ...retrying ({0})", attempts); Thread.Sleep(TimeSpan.FromSeconds(5)); } // end of while true/do forever } public static void Upload_stream_old( MemoryStream ms, string filename, string host, int port, string username, string password) { try { using (var sftpClient = new SftpClient(host, port, username, password)) //using (var fs = new FileStream(fileToUpload, FileMode.Open)) { sftpClient.OperationTimeout = TimeSpan.FromSeconds(30); sftpClient.ConnectionInfo.Timeout = TimeSpan.FromSeconds(30); int attempts = 0; do { attempts++; try { sftpClient.Connect(); } catch (Renci.SshNet.Common.SshConnectionException e) { Logger.Log(1," retrying ({0}) : {1}",attempts, e.Message); Thread.Sleep(TimeSpan.FromSeconds(5)); } } while (attempts < 10 && !sftpClient.IsConnected); if (attempts >= 10) { throw new Exception("Failed to Connect after 10 attempts."); } else { Logger.Log(" SSH Connected"); try { sftpClient.UploadFile( ms, filename, uploaded => { Logger.Log(5, $"Uploaded {(double)uploaded / ms.Length * 100}% of the file."); }); } catch (Renci.SshNet.Common.SshException e) { Logger.Log(0, " SSH upload Exception {0}:{1}", e.Message, e.InnerException.Message); } Logger.Log(" SSH Disconnected"); sftpClient.Disconnect(); } } Logger.Log(1, " -- uploaded: {0} ({3}KB) to {1}:{2}", filename, host, port, ( ms.Length/1024) ); } catch (Exception e) { Logger.Log(e.Message); } } public static void Upload_file(string fileToUpload, string host, int port, string username, string password) { try { using (var sftpClient = new SftpClient(host, port, username, password)) using (var fs = new FileStream(fileToUpload, FileMode.Open)) { sftpClient.OperationTimeout = TimeSpan.FromSeconds(30); int attempts = 0; do { try { attempts += 1; sftpClient.Connect(); } catch (Renci.SshNet.Common.SshConnectionException e) { Logger.Log(1, " retrying in 5s ({0}) : {1}", attempts, e.Message); Thread.Sleep(TimeSpan.FromSeconds(5)); } } while (attempts < 10 && !sftpClient.IsConnected); Logger.Log(" SSH Connected"); try { sftpClient.UploadFile( fs, "/Doug/" + Path.GetFileName(fileToUpload), uploaded => { Logger.Log(5,$"Uploaded {(double)uploaded / fs.Length * 100}% of the file."); }); } catch (Renci.SshNet.Common.SshException e) { Logger.Log(0, " SSH Exception {0}:{1}", e.Message, e.InnerException.Message); } sftpClient.Disconnect(); } Logger.Log(1," uploaded: {0}", fileToUpload); } catch (Exception e) { Console.WriteLine(e.Message); } } } }