mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 09:15:47 +00:00
Remove SessionInfo class, refactor message receive so it will respect timeout
This commit is contained in:
@@ -17,7 +17,7 @@ namespace Renci.SshClient.Algorithms
|
||||
/// </summary>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <returns></returns>
|
||||
internal static KeyExchange Create(KeyExchangeInitMessage message, SessionInfo sessionInfo)
|
||||
internal static KeyExchange Create(KeyExchangeInitMessage message, Session session)
|
||||
{
|
||||
|
||||
// TODO: Determine key exchange algorithm
|
||||
@@ -32,7 +32,7 @@ namespace Renci.SshClient.Algorithms
|
||||
throw new InvalidDataException("Failed to negotiate key exchange algorithm.");
|
||||
}
|
||||
|
||||
return Settings.KeyExchangeAlgorithms[keyExchangeAlgorithm](sessionInfo);
|
||||
return Settings.KeyExchangeAlgorithms[keyExchangeAlgorithm](session);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,7 +87,7 @@ namespace Renci.SshClient.Algorithms
|
||||
|
||||
public bool IsSuccessed { get; protected set; }
|
||||
|
||||
protected SessionInfo SessionInfo { get; private set; }
|
||||
protected Session Session { get; private set; }
|
||||
|
||||
protected string ClientPayload { get; set; }
|
||||
|
||||
@@ -107,9 +107,9 @@ namespace Renci.SshClient.Algorithms
|
||||
|
||||
public event EventHandler<KeyExchangeFailedEventArgs> Failed;
|
||||
|
||||
public KeyExchange(SessionInfo sessionInfo)
|
||||
public KeyExchange(Session session)
|
||||
{
|
||||
this.SessionInfo = sessionInfo;
|
||||
this.Session = session;
|
||||
this.ServerDecompression = Compression.None;
|
||||
this.ClientCompression = Compression.None;
|
||||
}
|
||||
@@ -191,9 +191,9 @@ namespace Renci.SshClient.Algorithms
|
||||
public virtual void Finish()
|
||||
{
|
||||
// TODO: Validate that all required properties are set
|
||||
if (this.SessionInfo.SessionId == null)
|
||||
if (this.Session.SessionId == null)
|
||||
{
|
||||
this.SessionInfo.SessionId = this.ExchangeHash;
|
||||
this.Session.SessionId = this.ExchangeHash;
|
||||
}
|
||||
|
||||
// Set encryption
|
||||
@@ -201,10 +201,10 @@ namespace Renci.SshClient.Algorithms
|
||||
using (var clientAlgorithm = this._clientEncryptionAlgorithm())
|
||||
{
|
||||
// Calculate client to server initial IV
|
||||
var clientValue = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'A', this.SessionInfo.SessionId));
|
||||
var clientValue = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'A', this.Session.SessionId));
|
||||
|
||||
// Calculate client to server encryption
|
||||
var clientKey = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'C', this.SessionInfo.SessionId));
|
||||
var clientKey = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'C', this.Session.SessionId));
|
||||
|
||||
clientKey = this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, clientKey, clientAlgorithm.KeySize / 8);
|
||||
|
||||
@@ -219,10 +219,10 @@ namespace Renci.SshClient.Algorithms
|
||||
using (var serverAlgorithm = this._serverDecryptionAlgorithm())
|
||||
{
|
||||
// Calculate server to client initial IV
|
||||
var serverValue = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'B', this.SessionInfo.SessionId));
|
||||
var serverValue = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'B', this.Session.SessionId));
|
||||
|
||||
// Calculate server to client encryption
|
||||
var serverKey = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'D', this.SessionInfo.SessionId));
|
||||
var serverKey = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'D', this.Session.SessionId));
|
||||
|
||||
serverKey = this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, serverKey, serverAlgorithm.KeySize / 8);
|
||||
|
||||
@@ -233,11 +233,11 @@ namespace Renci.SshClient.Algorithms
|
||||
}
|
||||
|
||||
// Calculate client to server integrity
|
||||
var MACc2s = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'E', this.SessionInfo.SessionId));
|
||||
var MACc2s = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'E', this.Session.SessionId));
|
||||
var clientMac = this._clientHmacAlgorithm(MACc2s);
|
||||
|
||||
// Calculate server to client integrity
|
||||
var MACs2c = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'F', this.SessionInfo.SessionId));
|
||||
var MACs2c = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'F', this.Session.SessionId));
|
||||
var serverMac = this._serverHmacAlgorithm(MACs2c);
|
||||
|
||||
// TODO: Create compression and decompression objects if any
|
||||
@@ -314,15 +314,15 @@ namespace Renci.SshClient.Algorithms
|
||||
|
||||
protected void SendMessage(Message message)
|
||||
{
|
||||
this.SessionInfo.SendMessage(message);
|
||||
this.Session.SendMessage(message);
|
||||
}
|
||||
|
||||
private IEnumerable<byte> CalculateHash()
|
||||
{
|
||||
var hashData = new _ExchangeHashData
|
||||
{
|
||||
ClientVersion = this.SessionInfo.ClientVersion,
|
||||
ServerVersion = this.SessionInfo.ServerVersion,
|
||||
ClientVersion = this.Session.ClientVersion,
|
||||
ServerVersion = this.Session.ServerVersion,
|
||||
ClientPayload = this.ClientPayload,
|
||||
ServerPayload = this.ServerPayload,
|
||||
HostKey = this.HostKey,
|
||||
|
||||
@@ -43,8 +43,8 @@ namespace Renci.SshClient.Algorithms
|
||||
/// Initializes a new instance of the <see cref="KeyExchangeDiffieHellman"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sessionInfo">The session information.</param>
|
||||
internal KeyExchangeDiffieHellman(SessionInfo sessionInfo)
|
||||
: base(sessionInfo)
|
||||
internal KeyExchangeDiffieHellman(Session session)
|
||||
: base(session)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Renci.SshClient.Algorithms
|
||||
E = this.ClientExchangeValue,
|
||||
});
|
||||
|
||||
this.SessionInfo.MessageReceived += SessionInfo_MessageReceived;
|
||||
this.Session.MessageReceived += SessionInfo_MessageReceived;
|
||||
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace Renci.SshClient.Algorithms
|
||||
{
|
||||
base.Finish();
|
||||
|
||||
this.SessionInfo.MessageReceived -= SessionInfo_MessageReceived;
|
||||
this.Session.MessageReceived -= SessionInfo_MessageReceived;
|
||||
}
|
||||
|
||||
private void SessionInfo_MessageReceived(object sender, MessageReceivedEventArgs e)
|
||||
|
||||
@@ -38,9 +38,9 @@ namespace Renci.SshClient.Channels
|
||||
|
||||
public bool IsOpen { get; protected set; }
|
||||
|
||||
protected SessionInfo SessionInfo { get; private set; }
|
||||
protected Session Session { get; private set; }
|
||||
|
||||
public Channel(SessionInfo sessionInfo, uint windowSize, uint packetSize)
|
||||
public Channel(Session session, uint windowSize, uint packetSize)
|
||||
{
|
||||
this._initialWindowSize = windowSize;
|
||||
this._maximumPacketSize = Math.Max(packetSize, 0x8000); // Ensure minimum maximum packet size of 0x8000 bytes
|
||||
@@ -61,21 +61,21 @@ namespace Renci.SshClient.Channels
|
||||
this.ClientChannelNumber = _channelCounter++;
|
||||
}
|
||||
|
||||
this.SessionInfo = sessionInfo;
|
||||
this.Session = session;
|
||||
this.ChannelData = new StringBuilder((int)this._initialWindowSize);
|
||||
this.ChannelExtendedData = new StringBuilder((int)this._initialWindowSize);
|
||||
this.WindowSize = this._initialWindowSize; // Initial window size
|
||||
this.PacketSize = this._maximumPacketSize; // Maximum packet size
|
||||
}
|
||||
|
||||
public Channel(SessionInfo sessionInfo)
|
||||
: this(sessionInfo, 0x100000, 0x8000)
|
||||
public Channel(Session session)
|
||||
: this(session, 0x100000, 0x8000)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Open()
|
||||
{
|
||||
this.SessionInfo.MessageReceived += SessionInfo_MessageReceived;
|
||||
this.Session.MessageReceived += SessionInfo_MessageReceived;
|
||||
|
||||
// Open session channel
|
||||
if (!this.IsOpen)
|
||||
@@ -88,7 +88,7 @@ namespace Renci.SshClient.Channels
|
||||
MaximumPacketSize = this.PacketSize,
|
||||
});
|
||||
|
||||
this.SessionInfo.WaitHandle(this._channelOpenWaitHandle);
|
||||
this.Session.WaitHandle(this._channelOpenWaitHandle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Renci.SshClient.Channels
|
||||
});
|
||||
|
||||
// Wait for channel to be closed
|
||||
this.SessionInfo.WaitHandle(this._channelClosedWaitHandle);
|
||||
this.Session.WaitHandle(this._channelClosedWaitHandle);
|
||||
}
|
||||
|
||||
this.CloseCleanup();
|
||||
@@ -130,7 +130,7 @@ namespace Renci.SshClient.Channels
|
||||
|
||||
protected void SendMessage(Message message)
|
||||
{
|
||||
this.SessionInfo.SendMessage(message);
|
||||
this.Session.SendMessage(message);
|
||||
}
|
||||
|
||||
private void SessionInfo_MessageReceived(object sender, MessageReceivedEventArgs e)
|
||||
@@ -251,7 +251,7 @@ namespace Renci.SshClient.Channels
|
||||
|
||||
this.IsOpen = false;
|
||||
|
||||
this.SessionInfo.MessageReceived -= SessionInfo_MessageReceived;
|
||||
this.Session.MessageReceived -= SessionInfo_MessageReceived;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace Renci.SshClient.Channels
|
||||
get { return ChannelTypes.Session; }
|
||||
}
|
||||
|
||||
public ChannelSession(SessionInfo sessionInfo)
|
||||
: base(sessionInfo, 0x100000, 0x1000)
|
||||
public ChannelSession(Session session)
|
||||
: base(session, 0x100000, 0x1000)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Renci.SshClient.Channels
|
||||
});
|
||||
|
||||
|
||||
this.SessionInfo.WaitHandle(this._channelEofWaitHandle);
|
||||
this.Session.WaitHandle(this._channelEofWaitHandle);
|
||||
|
||||
this.Close();
|
||||
|
||||
@@ -49,6 +49,13 @@ namespace Renci.SshClient.Channels
|
||||
this._channelEofWaitHandle.Set();
|
||||
}
|
||||
|
||||
protected override void OnChannelClose()
|
||||
{
|
||||
base.OnChannelClose();
|
||||
|
||||
this._channelEofWaitHandle.Set();
|
||||
}
|
||||
|
||||
protected override void OnChannelData(string data)
|
||||
{
|
||||
base.OnChannelData(data);
|
||||
|
||||
@@ -33,13 +33,13 @@ namespace Renci.SshClient.Channels
|
||||
get { return ChannelTypes.Session; }
|
||||
}
|
||||
|
||||
public ChannelSftp(SessionInfo sessionInfo, uint windowSize, uint packetSize)
|
||||
: base(sessionInfo, windowSize, packetSize)
|
||||
public ChannelSftp(Session session, uint windowSize, uint packetSize)
|
||||
: base(session, windowSize, packetSize)
|
||||
{
|
||||
}
|
||||
|
||||
public ChannelSftp(SessionInfo sessionInfo)
|
||||
: base(sessionInfo, 0x100000, 0x4000)
|
||||
public ChannelSftp(Session session)
|
||||
: base(session, 0x100000, 0x4000)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Renci.SshClient.Channels
|
||||
SubsystemName = "sftp",
|
||||
});
|
||||
|
||||
this.SessionInfo.WaitHandle(this._channelRequestSuccessWaitHandle);
|
||||
this.Session.WaitHandle(this._channelRequestSuccessWaitHandle);
|
||||
|
||||
this.SendMessage(new InitMessage
|
||||
{
|
||||
@@ -263,7 +263,7 @@ namespace Renci.SshClient.Channels
|
||||
|
||||
private SftpMessage ReceiveMessage()
|
||||
{
|
||||
this.SessionInfo.WaitHandle(this._responseMessageReceivedWaitHandle);
|
||||
this.Session.WaitHandle(this._responseMessageReceivedWaitHandle);
|
||||
|
||||
var statusMessage = this._responseMessage as StatusMessage;
|
||||
|
||||
|
||||
@@ -172,7 +172,6 @@
|
||||
<Compile Include="Services\Service.cs" />
|
||||
<Compile Include="Services\UserAuthenticationService.cs" />
|
||||
<Compile Include="Session.cs" />
|
||||
<Compile Include="SessionInfo.cs" />
|
||||
<Compile Include="SessionSSHv2.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="Common\SshData.cs" />
|
||||
|
||||
@@ -10,20 +10,10 @@ namespace Renci.SshClient.Services
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public ConnectionService(SessionInfo sessionInfo)
|
||||
: base(sessionInfo)
|
||||
public ConnectionService(Session session)
|
||||
: base(session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//public override void Request()
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
|
||||
//public override void Accept()
|
||||
//{
|
||||
// throw new NotImplementedException();
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,16 @@ namespace Renci.SshClient.Services
|
||||
{
|
||||
public abstract ServiceNames ServiceName { get; }
|
||||
|
||||
protected SessionInfo SessionInfo { get; private set; }
|
||||
protected Session Session { get; private set; }
|
||||
|
||||
public Service(SessionInfo sessionInfo)
|
||||
public Service(Session session)
|
||||
{
|
||||
this.SessionInfo = sessionInfo;
|
||||
this.Session = session;
|
||||
}
|
||||
|
||||
protected void SendMessage(Message message)
|
||||
{
|
||||
this.SessionInfo.SendMessage(message);
|
||||
this.Session.SendMessage(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@ namespace Renci.SshClient.Services
|
||||
{
|
||||
public abstract string Name { get; }
|
||||
|
||||
protected SessionInfo SessionInfo { get; private set; }
|
||||
protected Session Session { get; private set; }
|
||||
|
||||
public UserAuthentication(SessionInfo sessionInfo)
|
||||
public UserAuthentication(Session session)
|
||||
{
|
||||
this.SessionInfo = sessionInfo;
|
||||
this.Session = session;
|
||||
}
|
||||
|
||||
public abstract bool Start();
|
||||
|
||||
protected void SendMessage(Message message)
|
||||
{
|
||||
this.SessionInfo.SendMessage(message);
|
||||
this.Session.SendMessage(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace Renci.SshClient.Services
|
||||
return "hostbased";
|
||||
}
|
||||
}
|
||||
public UserAuthenticationHost(SessionInfo sessionInfo)
|
||||
: base(sessionInfo)
|
||||
public UserAuthenticationHost(Session session)
|
||||
: base(session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace Renci.SshClient.Services
|
||||
}
|
||||
}
|
||||
|
||||
public UserAuthenticationPassword(SessionInfo sessionInfo)
|
||||
: base(sessionInfo)
|
||||
public UserAuthenticationPassword(Session session)
|
||||
: base(session)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -24,13 +24,13 @@ namespace Renci.SshClient.Services
|
||||
// TODO: Handle all user authentication messages
|
||||
//Message.RegisterMessageType<PasswordChangeRequiredMessage>(MessageTypes.UserAuthenticationPasswordChangeRequired);
|
||||
|
||||
if (!string.IsNullOrEmpty(this.SessionInfo.ConnectionInfo.Password))
|
||||
if (!string.IsNullOrEmpty(this.Session.ConnectionInfo.Password))
|
||||
{
|
||||
this.SendMessage(new PasswordRequestMessage
|
||||
{
|
||||
ServiceName = ServiceNames.Connection,
|
||||
Username = this.SessionInfo.ConnectionInfo.Username,
|
||||
Password = this.SessionInfo.ConnectionInfo.Password,
|
||||
Username = this.Session.ConnectionInfo.Username,
|
||||
Password = this.Session.ConnectionInfo.Password,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace Renci.SshClient.Services
|
||||
}
|
||||
}
|
||||
|
||||
public UserAuthenticationPublicKey(SessionInfo sessionInfo)
|
||||
: base(sessionInfo)
|
||||
public UserAuthenticationPublicKey(Session session)
|
||||
: base(session)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -22,16 +22,16 @@ namespace Renci.SshClient.Services
|
||||
|
||||
public override bool Start()
|
||||
{
|
||||
if (this.SessionInfo.ConnectionInfo.KeyFile != null)
|
||||
if (this.Session.ConnectionInfo.KeyFile != null)
|
||||
{
|
||||
// TODO: Complete full public key implemention which includes other messages
|
||||
this.SendMessage(new PublicKeyRequestMessage
|
||||
{
|
||||
ServiceName = ServiceNames.Connection,
|
||||
Username = this.SessionInfo.ConnectionInfo.Username,
|
||||
PublicKeyAlgorithmName = this.SessionInfo.ConnectionInfo.KeyFile.AlgorithmName,
|
||||
PublicKeyData = this.SessionInfo.ConnectionInfo.KeyFile.PublicKey,
|
||||
Signature = this.SessionInfo.ConnectionInfo.KeyFile.GetSignature(this.SessionInfo.SessionId),
|
||||
Username = this.Session.ConnectionInfo.Username,
|
||||
PublicKeyAlgorithmName = this.Session.ConnectionInfo.KeyFile.AlgorithmName,
|
||||
PublicKeyData = this.Session.ConnectionInfo.KeyFile.PublicKey,
|
||||
Signature = this.Session.ConnectionInfo.KeyFile.GetSignature(this.Session.SessionId),
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace Renci.SshClient.Services
|
||||
|
||||
public bool IsAuthenticated { get; private set; }
|
||||
|
||||
public UserAuthenticationService(SessionInfo sessionInfo)
|
||||
: base(sessionInfo)
|
||||
public UserAuthenticationService(Session session)
|
||||
: base(session)
|
||||
{
|
||||
this.AuthenticationCompletedHandle = new AutoResetEvent(false);
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace Renci.SshClient.Services
|
||||
Message.RegisterMessageType<BannerMessage>(MessageTypes.UserAuthenticationBanner);
|
||||
|
||||
// Attach event handlers to handle messages
|
||||
this.SessionInfo.MessageReceived += SessionInfo_MessageReceived;
|
||||
this.Session.MessageReceived += SessionInfo_MessageReceived;
|
||||
|
||||
// Request user authorization service
|
||||
this.SendMessage(new ServiceRequestMessage
|
||||
@@ -50,19 +50,19 @@ namespace Renci.SshClient.Services
|
||||
});
|
||||
|
||||
// Wait for service to be accepted
|
||||
this.SessionInfo.WaitHandle(this._serviceAccepted);
|
||||
this.Session.WaitHandle(this._serviceAccepted);
|
||||
|
||||
// Start by quering supported authentication methods
|
||||
this.SendMessage(new RequestMessage
|
||||
{
|
||||
Username = this.SessionInfo.ConnectionInfo.Username,
|
||||
Username = this.Session.ConnectionInfo.Username,
|
||||
ServiceName = ServiceNames.Connection,
|
||||
});
|
||||
|
||||
// Wait for authentication to be completed
|
||||
this.SessionInfo.WaitHandle(this._authenticationCompleted);
|
||||
this.Session.WaitHandle(this._authenticationCompleted);
|
||||
|
||||
this.SessionInfo.MessageReceived -= SessionInfo_MessageReceived;
|
||||
this.Session.MessageReceived -= SessionInfo_MessageReceived;
|
||||
|
||||
Message.UnRegisterMessageType(MessageTypes.UserAuthenticationFailure);
|
||||
Message.UnRegisterMessageType(MessageTypes.UserAuthenticationSuccess);
|
||||
@@ -105,7 +105,7 @@ namespace Renci.SshClient.Services
|
||||
|
||||
if (methodsToTry.Count() == 0)
|
||||
{
|
||||
this.AuthenticationFailed(string.Format("User '{0}' cannot be authorized.", this.SessionInfo.ConnectionInfo.Username));
|
||||
this.AuthenticationFailed(string.Format("User '{0}' cannot be authorized.", this.Session.ConnectionInfo.Username));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -116,11 +116,11 @@ namespace Renci.SshClient.Services
|
||||
|
||||
if (methodName == "publickey")
|
||||
{
|
||||
userAuthentication = new UserAuthenticationPublicKey(this.SessionInfo);
|
||||
userAuthentication = new UserAuthenticationPublicKey(this.Session);
|
||||
}
|
||||
else if (methodName == "password")
|
||||
{
|
||||
userAuthentication = new UserAuthenticationPassword(this.SessionInfo);
|
||||
userAuthentication = new UserAuthenticationPassword(this.Session);
|
||||
}
|
||||
this._executedMethods.Add(methodName);
|
||||
if (userAuthentication != null)
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Renci.SshClient.Algorithms;
|
||||
using Renci.SshClient.Channels;
|
||||
using Renci.SshClient.Common;
|
||||
using Renci.SshClient.Messages;
|
||||
using Renci.SshClient.Messages.Connection;
|
||||
@@ -26,7 +27,8 @@ namespace Renci.SshClient
|
||||
var ep = new IPEndPoint(Dns.GetHostAddresses(connectionInfo.Host)[0], connectionInfo.Port);
|
||||
var socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
socket.Connect(ep);
|
||||
socket.ReceiveTimeout = 5 * 1000; // Set default receive timeout to 5 seconds
|
||||
//socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1000 * 15);
|
||||
//socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000 * 5);
|
||||
|
||||
// Get server version from the server,
|
||||
// ignore text lines which are sent before if any
|
||||
@@ -50,10 +52,10 @@ namespace Renci.SshClient
|
||||
return session;
|
||||
}
|
||||
|
||||
private ConnectionInfo _connectionInfo;
|
||||
|
||||
private Socket _socket;
|
||||
|
||||
private int _waitTimeout = 5 * 1000; // Set default receive timeout to 5 seconds
|
||||
|
||||
private KeyExchange _keyExhcange;
|
||||
|
||||
private BackgroundWorker _messageListener;
|
||||
@@ -64,6 +66,14 @@ namespace Renci.SshClient
|
||||
|
||||
private IDictionary<uint, uint> _openChannels = new Dictionary<uint, uint>();
|
||||
|
||||
private EventWaitHandle _disconnectWaitHandle = new AutoResetEvent(false);
|
||||
|
||||
private EventWaitHandle _exceptionWaitHandle = new AutoResetEvent(false);
|
||||
|
||||
private Exception _exceptionToThrow;
|
||||
|
||||
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
|
||||
|
||||
protected HMAC ServerMac { get; private set; }
|
||||
|
||||
protected HMAC ClientMac { get; private set; }
|
||||
@@ -76,7 +86,14 @@ namespace Renci.SshClient
|
||||
|
||||
protected Compression ClientCompression { get; private set; }
|
||||
|
||||
internal SessionInfo SessionInfo { get; private set; }
|
||||
// TODO: Consider refactor to make setter private
|
||||
public IEnumerable<byte> SessionId { get; set; }
|
||||
|
||||
public string ServerVersion { get; private set; }
|
||||
|
||||
public string ClientVersion { get; private set; }
|
||||
|
||||
public ConnectionInfo ConnectionInfo { get; private set; }
|
||||
|
||||
public bool IsConnected
|
||||
{
|
||||
@@ -90,18 +107,32 @@ namespace Renci.SshClient
|
||||
|
||||
protected Session(ConnectionInfo connectionInfo, Socket socket, string serverVersion)
|
||||
{
|
||||
this._connectionInfo = connectionInfo;
|
||||
this.ConnectionInfo = connectionInfo;
|
||||
this._socket = socket;
|
||||
//this._socket.ReceiveTimeout = this._waitTimeout;
|
||||
|
||||
this.SessionInfo = new SessionInfo(this.SendMessage, this._connectionInfo, socket.ReceiveTimeout);
|
||||
this.SessionInfo.ServerVersion = serverVersion;
|
||||
this.SessionInfo.ClientVersion = string.Format("SSH-2.0-Renci.SshClient.{0}", this.GetType().Assembly.GetName().Version);
|
||||
this.ServerVersion = serverVersion;
|
||||
this.ClientVersion = string.Format("SSH-2.0-Renci.SshClient.{0}", this.GetType().Assembly.GetName().Version);
|
||||
}
|
||||
|
||||
private static IDictionary<Type, Func<Session, Channel>> _channels = new Dictionary<Type, Func<Session, Channel>>()
|
||||
{
|
||||
{typeof(ChannelSession), (session) => { return new ChannelSession(session);}},
|
||||
{typeof(ChannelSftp), (session) => { return new ChannelSftp(session);}}
|
||||
};
|
||||
|
||||
public T CreateChannel<T>() where T : Channel
|
||||
{
|
||||
if (!this._socket.Connected)
|
||||
{
|
||||
throw new InvalidOperationException("Not connected");
|
||||
}
|
||||
return _channels[typeof(T)](this) as T;
|
||||
}
|
||||
|
||||
public void Connect()
|
||||
{
|
||||
this.Write(Encoding.ASCII.GetBytes(string.Format("{0}\n", this.SessionInfo.ClientVersion)));
|
||||
this.Write(Encoding.ASCII.GetBytes(string.Format("{0}\n", this.ClientVersion)));
|
||||
|
||||
// Register Transport response messages
|
||||
Message.RegisterMessageType<DisconnectMessage>(MessageTypes.Disconnect);
|
||||
@@ -118,16 +149,16 @@ namespace Renci.SshClient
|
||||
this._messageListener.RunWorkerAsync();
|
||||
|
||||
// Wait for key exchange to be completed
|
||||
this.SessionInfo.WaitHandle(this._keyExhangedFinishedWaitHandle);
|
||||
this.WaitHandle(this._keyExhangedFinishedWaitHandle);
|
||||
|
||||
// If sessionId is not set then its not connected
|
||||
if (this.SessionInfo.SessionId == null)
|
||||
if (this.SessionId == null)
|
||||
{
|
||||
this.Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
var authenticationService = new UserAuthenticationService(this.SessionInfo);
|
||||
var authenticationService = new UserAuthenticationService(this);
|
||||
|
||||
authenticationService.AuthenticateUser();
|
||||
|
||||
@@ -145,7 +176,33 @@ namespace Renci.SshClient
|
||||
this.DisconnectCleanup();
|
||||
}
|
||||
|
||||
protected abstract void SendMessage(Message message);
|
||||
internal abstract void SendMessage(Message message);
|
||||
|
||||
internal void WaitHandle(EventWaitHandle waitHandle)
|
||||
{
|
||||
var waitHandles = new EventWaitHandle[]
|
||||
{
|
||||
this._disconnectWaitHandle,
|
||||
this._exceptionWaitHandle,
|
||||
waitHandle,
|
||||
};
|
||||
|
||||
//EventWaitHandle.WaitAny(waitHandles);
|
||||
|
||||
var index = EventWaitHandle.WaitAny(waitHandles, this._waitTimeout);
|
||||
|
||||
if (this._exceptionToThrow != null)
|
||||
{
|
||||
var exception = this._exceptionToThrow;
|
||||
this._exceptionToThrow = null;
|
||||
throw exception;
|
||||
}
|
||||
else if (index > waitHandles.Length)
|
||||
{
|
||||
// TODO: Issue timeout disconnect message if approapriate
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Message ReceiveMessage();
|
||||
|
||||
@@ -196,7 +253,7 @@ namespace Renci.SshClient
|
||||
}
|
||||
|
||||
// Create key exchange algorithm
|
||||
this._keyExhcange = KeyExchange.Create(message, this.SessionInfo);
|
||||
this._keyExhcange = KeyExchange.Create(message, this);
|
||||
|
||||
this._keyExhcange.Failed += delegate(object sender, KeyExchangeFailedEventArgs e)
|
||||
{
|
||||
@@ -261,20 +318,35 @@ namespace Renci.SshClient
|
||||
{
|
||||
var buffer = new byte[length];
|
||||
|
||||
SocketError socketErrorCode;
|
||||
SocketError socketErrorCode = SocketError.Success;
|
||||
|
||||
this._socket.Receive(buffer, 0, length, SocketFlags.None, out socketErrorCode);
|
||||
int bytesRead = 0;
|
||||
|
||||
// Check for socket errors
|
||||
if (socketErrorCode != SocketError.Success)
|
||||
while (bytesRead == 0 && this._socket.Connected && socketErrorCode == SocketError.Success)
|
||||
{
|
||||
throw new SocketException((int)socketErrorCode);
|
||||
var asynchResult = this._socket.BeginReceive(buffer, 0, length, SocketFlags.None, null, null);
|
||||
|
||||
while (!asynchResult.IsCompleted && this._socket.Connected)
|
||||
{
|
||||
asynchResult.AsyncWaitHandle.WaitOne(this._waitTimeout);
|
||||
}
|
||||
bytesRead = this._socket.EndReceive(asynchResult, out socketErrorCode);
|
||||
}
|
||||
else if (!this._socket.Connected)
|
||||
|
||||
// Check for errors
|
||||
if (!this._socket.Connected)
|
||||
{
|
||||
// If socket was closed throw an exception
|
||||
throw new SocketException(995); // WSA_OPERATION_ABORTED
|
||||
}
|
||||
if (bytesRead != length && socketErrorCode == SocketError.Success)
|
||||
{
|
||||
throw new InvalidDataException(string.Format("Data read {0}, expected {1}", bytesRead, length));
|
||||
}
|
||||
else if (socketErrorCode != SocketError.Success)
|
||||
{
|
||||
throw new SocketException((int)socketErrorCode);
|
||||
}
|
||||
else
|
||||
return buffer;
|
||||
}
|
||||
@@ -322,9 +394,6 @@ namespace Renci.SshClient
|
||||
{
|
||||
this._socket.Disconnect(false);
|
||||
}
|
||||
|
||||
// Let session know that it was disconected
|
||||
this.SessionInfo.Disconnect();
|
||||
}
|
||||
|
||||
private void MessageListener_DoWork(object sender, DoWorkEventArgs e)
|
||||
@@ -344,13 +413,19 @@ namespace Renci.SshClient
|
||||
this.HandleMessage(message);
|
||||
|
||||
// Raise an event that message received
|
||||
this.SessionInfo.RaiseMessageReceived(this, new MessageReceivedEventArgs(message));
|
||||
this.RaiseMessageReceived(this, new MessageReceivedEventArgs(message));
|
||||
}
|
||||
catch (Exception exp)
|
||||
{
|
||||
// TODO: This exception can be swolloed if it occures while running in the background, look for possible solutions
|
||||
|
||||
// In case of error issue disconntect command
|
||||
this.Disconnect(DisconnectReasonCodes.ByApplication, exp.ToString());
|
||||
|
||||
// Set exception that need to be thrown by the main thread
|
||||
this._exceptionToThrow = exp;
|
||||
|
||||
this._exceptionWaitHandle.Set();
|
||||
// TODO: Set exp to some excpetion that can be thrown later by the main thread.
|
||||
|
||||
break;
|
||||
@@ -358,6 +433,14 @@ namespace Renci.SshClient
|
||||
}
|
||||
}
|
||||
|
||||
private void RaiseMessageReceived(object sender, MessageReceivedEventArgs args)
|
||||
{
|
||||
if (this.MessageReceived != null)
|
||||
{
|
||||
this.MessageReceived(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleMessage(ChannelOpenConfirmationMessage message)
|
||||
{
|
||||
// Keep track of open channels
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Renci.SshClient.Common;
|
||||
using Renci.SshClient.Messages;
|
||||
|
||||
namespace Renci.SshClient
|
||||
{
|
||||
public delegate void SendMessage(Message message);
|
||||
|
||||
internal class SessionInfo
|
||||
{
|
||||
private SendMessage _sendMessage;
|
||||
|
||||
private EventWaitHandle _disconnectWaitHandle = new AutoResetEvent(false);
|
||||
|
||||
private int _waitTimeout;
|
||||
|
||||
public ConnectionInfo ConnectionInfo { get; private set; }
|
||||
|
||||
public IEnumerable<byte> SessionId { get; set; }
|
||||
|
||||
public string ServerVersion { get; set; }
|
||||
|
||||
public string ClientVersion { get; set; }
|
||||
|
||||
public SessionInfo(SendMessage sendMessage, ConnectionInfo connectionInfo, int waitTimeout)
|
||||
{
|
||||
this._sendMessage = sendMessage;
|
||||
this._waitTimeout = waitTimeout;
|
||||
this.ConnectionInfo = connectionInfo;
|
||||
}
|
||||
|
||||
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
|
||||
|
||||
public void RaiseMessageReceived(object sender, MessageReceivedEventArgs args)
|
||||
{
|
||||
if (this.MessageReceived != null)
|
||||
{
|
||||
this.MessageReceived(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendMessage(Message message)
|
||||
{
|
||||
this._sendMessage(message);
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
this._disconnectWaitHandle.Set();
|
||||
}
|
||||
|
||||
public void WaitHandle(EventWaitHandle waitHandle)
|
||||
{
|
||||
var waitHandles = new EventWaitHandle[]
|
||||
{
|
||||
this._disconnectWaitHandle,
|
||||
waitHandle,
|
||||
};
|
||||
var index = EventWaitHandle.WaitAny(waitHandles);
|
||||
|
||||
//var index = EventWaitHandle.WaitAny(waitHandles, this._waitTimeout);
|
||||
|
||||
//if (index > waitHandles.Length)
|
||||
//{
|
||||
// // TODO: Issue timeout disconnect message if approapriate
|
||||
// throw new TimeoutException();
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace Renci.SshClient
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SendMessage(Message message)
|
||||
internal override void SendMessage(Message message)
|
||||
{
|
||||
if (!this.IsConnected)
|
||||
return;
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Renci.SshClient
|
||||
{
|
||||
internal static class Settings
|
||||
{
|
||||
public static IDictionary<string, Func<SessionInfo, KeyExchange>> KeyExchangeAlgorithms { get; private set; }
|
||||
public static IDictionary<string, Func<Session, KeyExchange>> KeyExchangeAlgorithms { get; private set; }
|
||||
|
||||
public static IDictionary<string, Func<SymmetricAlgorithm>> Encryptions { get; private set; }
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Renci.SshClient
|
||||
|
||||
static Settings()
|
||||
{
|
||||
Settings.KeyExchangeAlgorithms = new Dictionary<string, Func<SessionInfo, KeyExchange>>()
|
||||
Settings.KeyExchangeAlgorithms = new Dictionary<string, Func<Session, KeyExchange>>()
|
||||
{
|
||||
{"diffie-hellman-group1-sha1", (a) => { return new KeyExchangeDiffieHellman(a);}}
|
||||
//"diffie-hellman-group-exchange-sha1"
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace Renci.SshClient
|
||||
{
|
||||
this._session = session;
|
||||
|
||||
// TODO: Keep track of all open channels to disconnect them when connection is closed
|
||||
this._channel = new ChannelSftp(this._session.SessionInfo);
|
||||
//this._channel = new ChannelSftp(this._session);
|
||||
this._channel = this._session.CreateChannel<ChannelSftp>();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,22 @@ namespace Renci.SshClient
|
||||
this._channel.UploadFile(source, fileName);
|
||||
}
|
||||
|
||||
public void UploadFile(string source, string fileName)
|
||||
{
|
||||
this._channel.UploadFile(File.OpenRead(source), fileName);
|
||||
}
|
||||
|
||||
public void DownloadFile(string fileName, Stream destination)
|
||||
{
|
||||
this._channel.DownloadFile(fileName, destination);
|
||||
}
|
||||
|
||||
public void DownloadFile(string fileName, string destination)
|
||||
{
|
||||
var file = File.Create(destination);
|
||||
this._channel.DownloadFile(fileName, file);
|
||||
}
|
||||
|
||||
public void RemoveFile(string fileName)
|
||||
{
|
||||
this._channel.RemoveFile(fileName);
|
||||
|
||||
@@ -13,8 +13,9 @@ namespace Renci.SshClient
|
||||
|
||||
public string Execute(string command)
|
||||
{
|
||||
// TODO: Keep track of all open channels to cdisconnect them when connection is closed
|
||||
var channel = new ChannelSession(this._session.SessionInfo);
|
||||
//var channel = new ChannelSession(this._session);
|
||||
|
||||
var channel = this._session.CreateChannel<ChannelSession>();
|
||||
|
||||
var result = channel.Execute(command);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user