Remove SessionInfo class, refactor message receive so it will respect timeout

This commit is contained in:
olegkap_cp
2010-08-10 21:01:15 +00:00
parent b86e465fd0
commit c7aa60afbe
19 changed files with 206 additions and 187 deletions
@@ -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)
+107 -24
View File
@@ -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;
+2 -2
View File
@@ -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"
+13 -2
View File
@@ -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);
+3 -2
View File
@@ -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);