EldoS | Feel safer!

Software components for data protection, secure storage and transfer

OnOpenShell

Also by EldoS: BizCrypto
Components for BizTalk® and SQL Server® Integration Services that let you securely store and transfer information in your business automation solutions.
#7582
Posted: 09/12/2008 05:21:45
by Manfred Domandl (Basic support level)
Joined: 09/11/2008
Posts: 9

Hello :-)

i took the sshserver demo and rewrite ist to run under Windows CE (ARMV4I - CE 5.0). I hade to change code for the timers, threading and to completly create new forms. Now the server app. is running. It's possible to add new User, to generate new Key and to start to listening. It starts also the SSH Session. What I not get is the OpenShell event. I varified ist with the original W32 Version where this event will be fired but not on the CE Version. May be you have an idea why I will not get this event. May be this is an issue of the different threading mechanism of the two window versions....

Thanh you in advance for help.

Kind Regards.
Manfred Domandl
InterCard
#7583
Posted: 09/12/2008 05:34:45
by Ken Ivanov (EldoS Corp.)

Thank you for contacting us.

Please specify, which events of TElSSHServer objects *do fire*. Knowing it we would be able to find out the reason for the issue.
#7584
Posted: 09/12/2008 06:25:08
by Manfred Domandl (Basic support level)
Joined: 09/11/2008
Posts: 9

Hy,

thanks for the fast response.

I will get the following events in SSHServer.cs:

OnSend
OnReceive
OnSocketSessionTimeout

Kind Regards
Manfred Domandl
InterCard
#7585
Posted: 09/12/2008 07:01:10
by Ken Ivanov (EldoS Corp.)

A common sequence of SSH protocol events is the following:
a) socket session is established,
b) peers negotiate the algorithms to use,
c) client authenticates the server,
d) server authenticates the client,
e) client requests shell, command or other tunnels.

The corresponding sequence of TElSSHServer's events looks in the following way:
a) OnSend and OnReceive events are fired repeatedly during the entire session,
b) one or more OnAuthAttempt events, each one followed by either OnAuthPassword, OnAuthPublicKey or OnAuthKeyboard event; OnFurtherAuthNeeded event is fired after each successful authentication attempt,
c) OnOpenShell/OnOpenSubsystem/OnOpenCommand event fires.

The events you are getting show that the session is terminated on the very start of the communication. Please check the (a) output of the client application, (b) if OnError event is fired.
#7587
Posted: 09/12/2008 08:27:28
by Manfred Domandl (Basic support level)
Joined: 09/11/2008
Posts: 9

Ok,
I don't get an OnError event. The output of the client don't show anything. On the W32 demo I get there after the OnOpenShell event the prompt, also I get there the OnAuthPassword, OnAuthPublicKey, OnFurtherAuthNeeded events, but not on the WIN CE example. I use for access allways the same client (openSSH). On WIN CE the demo app will not show the user, the client software and the tunnel.

Do you have any other idea, or do you need some more informations?

Kind regards
Manfred Domandl
InterCard
#7588
Posted: 09/12/2008 11:15:35
by Ken Ivanov (EldoS Corp.)

How many times do OnReceive and OnSend events fire on your WinCE device? At first glance, the issue seems to be caused by incorrect data exchange setup between TElSSHServer object and the socket.
#7597
Posted: 09/15/2008 03:09:39
by Manfred Domandl (Basic support level)
Joined: 09/11/2008
Posts: 9

The OnReceive and the OnSend events would be fired after starting and before SessionTimeOut that meen each would be fired two times.
May be the code will help...following the code of sshsession and sshlistener:

Code
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using SBSSHCommon;
using SBSSHServer;
using SBSSHKeyStorage;
using SBSSHHandlers;
using SBStringList;
using SBUtils;
using SBSSHConnectionHandler;
using SBSftpHandler;

namespace SSHServer
{
   /// <summary>
   /// Responsible for a single SSH session
   /// </summary>
   public class SSHSession : IDisposable
   {
      #region Public properties

      public object Data
      {
         get { return m_Data; }
         set { m_Data = value; }
      }
      
      public string Status
      {
         get { return m_Status; }
      }
      
      public string Username
      {
         get { return m_Username; }
      }
      
      public string Host
      {
         get { return m_Host; }
      }
      
      public string ClientSoftware
      {
         get { return m_ClientSoftware; }
      }
      
      public DateTime StartTime
      {
         get { return m_StartTime; }
      }

      #endregion

      #region Public events

      public delegate void SessionClosedHandler(SSHSession sender);
      public event SessionClosedHandler SessionClosed;

      public delegate void SessionInfoChangedHandler(SSHSession sender);
      public event SessionInfoChangedHandler SessionInfoChanged;

      #endregion

      #region Public methods

      /// <summary>
      /// Constructor
      /// </summary>
      /// <param name="socket">Socket object for accepted TCP connection</param>
      /// <param name="id">Session identifier</param>
      public SSHSession(Socket socket, int id)
      {
         m_Socket = socket;
         try
         {
            m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, 300));
         }
         catch(Exception exc)
         {
            Logger.Log("SSHSession() : " + exc.Message);
         }

         m_Host = ((IPEndPoint)(socket.RemoteEndPoint)).Address.ToString() + ":" + ((IPEndPoint)(socket.RemoteEndPoint)).Port.ToString();
         m_StartTime = DateTime.Now;
            
            m_SocketSessionTimercb = new System.Threading.TimerCallback(OnSocketSessionTimeout);
            m_SocketSessionTimer = new System.Threading.Timer(m_SocketSessionTimercb, null, 300000, 1000);
            //m_SocketSessionTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnSocketSessionTimeout);
         //m_SocketSessionTimer.AutoReset = true;            
            
         m_synch = new object();

         SetupServer();

         m_Thread = new Thread(new ThreadStart(ReadThread));
         m_Thread.Name = "CFU_BinarySession_Thread";
         m_Thread.Start();
            
      }
      
      /// <summary>
      /// Starts session
      /// </summary>
      public void Start()
      {
         SessionInfoChanged(this);
         RestartSocketSessionTimer();
      }

      /// <summary>
      /// Triggers SessionClosed event
      /// </summary>
      public void CloseSession()
      {
         CleanUp();
         if (this.SessionClosed != null)
         {
            this.SessionClosed(this);
         }         
      }

      #endregion

      #region SSH Server authentication processing
      
      /// <summary>
      /// Is fired when user performs an authentication attempt
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="Username">User login name</param>
      /// <param name="AuthType">Used authentication type</param>
      /// <param name="Accept">Set to true, if user is allowed to perform this type of authentication</param>
      private void SSHServer_OnAuthAttempt(object Sender, string Username, int AuthType, ref bool Accept)
      {
         UserInfo user = null;
         if (Globals.Settings.FindUser(ref user, Username))
         {
            Accept = (user.AuthTypes | AuthType) > 0;
            m_Username = Username;
            m_ClientSoftware = m_SSHServer.ClientSoftwareName;
            SessionInfoChanged(this);
         }
         else
         {
            Accept = false;
         }
      }

      /// <summary>
      /// Is fired when user authentication attempt fails
      /// </summary>
      /// <param name="Sender">ElSSHServer objects</param>
      /// <param name="AuthenticationType">Authentication type that failed</param>
      private void SSHServer_OnAuthFailed(object Sender, int AuthenticationType)
      {
         Logger.Log("Authentication attempt (" + Globals.AuthTypeToStr(AuthenticationType) + ") failed", true);
      }

      /// <summary>
      /// Is fired when user tries password authentication
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="Username">User login name</param>
      /// <param name="Password">User password</param>
      /// <param name="Accept">Set to true, if the provided password is valid</param>
      /// <param name="ForceChangePassword">Set to true to force user to change his password</param>
      private void SSHServer_OnAuthPassword(object Sender, string Username, string Password, ref bool Accept, ref bool ForceChangePassword)
      {
         UserInfo user = null;
         if (Globals.Settings.FindUser(ref user, Username))
         {
            Accept = (user.AuthTypes & SBSSHConstants.Unit.SSH_AUTH_TYPE_PASSWORD) > 0;
            Accept = Accept & user.PasswordValid(Password);
            if (Accept)
            {
               int authFlag;
               if (m_authInfo[Username] == null)
               {
                        authFlag = 0;
               }
               else
               {
                        authFlag = (int)m_authInfo[Username];
               }
               authFlag = authFlag | SBSSHConstants.Unit.SSH_AUTH_TYPE_PASSWORD;
               if ((user.AuthTypes & SBSSHConstants.Unit.SSH_AUTH_TYPE_KEYBOARD) > 0)
               {
                  authFlag = authFlag | SBSSHConstants.Unit.SSH_AUTH_TYPE_KEYBOARD;
               }
               m_authInfo[Username] = authFlag;
            }
         }
         else
         {
            Accept = false;
         }
      }

      /// <summary>
      /// Is fired when user tries public key authentication
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="Username">User login name</param>
      /// <param name="Key">User's public key</param>
      /// <param name="Accept">Set to true if the provided public key is valid</param>
      private void SSHServer_OnAuthPublicKey(object Sender, string Username, TElSSHKey Key, ref bool Accept)
      {
         UserInfo user = null;
         if (Globals.Settings.FindUser(ref user, Username))
         {
            Accept = (user.AuthTypes & SBSSHConstants.Unit.SSH_AUTH_TYPE_PUBLICKEY) > 0;
            Accept = Accept & user.KeyValid(Key);
            if (Accept)
            {
               int authFlag;
               if (m_authInfo[Username] == null)
               {
                  authFlag = 0;
               }
               else
               {
                  authFlag = (int)m_authInfo[Username];
               }
               authFlag = authFlag | SBSSHConstants.Unit.SSH_AUTH_TYPE_PUBLICKEY;
               m_authInfo[Username] = authFlag;
            }
         }
         else
         {
            Accept = false;
         }
      }

      /// <summary>
      /// Is fired when user tries keyboard-interactive authentication
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="Username">User login name</param>
      /// <param name="Submethods">Names of submethods that that the client wishes to use</param>
      /// <param name="Name">Set this to authentication title</param>
      /// <param name="Instruction">Set this to authentication instruction</param>
      /// <param name="Requests">Add the desired requests to this list</param>
      /// <param name="Echoes">Set the bits of this object depending on the corresponding responses should be echoed</param>
      private void SSHServer_OnAuthKeyboard(object Sender, string Username, TElStringList Submethods,
         ref string Name, ref string Instruction, TElStringList Requests, TElBits Echoes)
      {
         UserInfo user = null;
         if ((Globals.Settings.FindUser(ref user, Username)) && ((user.AuthTypes & SBSSHConstants.Unit.SSH_AUTH_TYPE_KEYBOARD) > 0))
         {
                Name = "Keyboard-interactive authentication";
            Instruction = "Please enter the following information";
            Requests.Add("Username: ");
            Requests.Add("Password: ");
            Echoes.Size = 2;
            Echoes[0] = true;
            Echoes[1] = false;
         }
      }

      /// <summary>
      /// Is fired when the keyboard-interactive response is received from client
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="Requests">Requests list from the last keyboard-interactive request</param>
      /// <param name="Responses">User's responses</param>
      /// <param name="Name">Set this to next authentication stage title</param>
      /// <param name="Instruction">Set this to next authentication stage instructions</param>
      /// <param name="NewRequests">Add requests for next authentication stage to this list</param>
      /// <param name="Echoes">Set echo bits accordingly</param>
      /// <param name="Accept">Set to true if the responses are valid, or to false if the authentication process should be continued</param>
      private void SSHServer_OnAuthKeyboardResponse(object Sender, TElStringList Requests, TElStringList Responses,
         ref string Name, ref string Instruction, TElStringList NewRequests, TElBits Echoes, ref bool Accept)
      {
         Accept = false;
         if ((Responses != null) && (Responses.Count == 2))
         {
            string Username = Responses[0];
            string Password = Responses[1];
            UserInfo user = null;
            if (Globals.Settings.FindUser(ref user, Username))
            {
               Accept = (user.AuthTypes & SBSSHConstants.Unit.SSH_AUTH_TYPE_KEYBOARD) > 0;
               Accept = Accept & user.PasswordValid(Password);
               if (Accept)
               {
                  int authFlag;
                  if (m_authInfo[Username] == null)
                  {
                     authFlag = 0;
                  }
                  else
                  {
                     authFlag = (int)m_authInfo[Username];
                  }
                  authFlag = authFlag | SBSSHConstants.Unit.SSH_AUTH_TYPE_KEYBOARD;
                  if ((user.AuthTypes & SBSSHConstants.Unit.SSH_AUTH_TYPE_PASSWORD) > 0)
                  {
                     authFlag = authFlag | SBSSHConstants.Unit.SSH_AUTH_TYPE_PASSWORD;
                  }
                  m_authInfo[Username] = authFlag;
               }
            }
         }
      }

      /// <summary>
      /// Queries if further client authentication is needed
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="Username">User login name</param>
      /// <param name="Needed">Set to true if further authentication is needed, or to false if the authentication stage is completed</param>
      private void SSHServer_OnFurtherAuthNeeded(object Sender, string Username, ref bool Needed)
      {
         UserInfo user = null;
            Needed = true;         
         if (Globals.Settings.FindUser(ref user, Username)) {
            if (m_authInfo[Username] != null)
            {
               int authFlag = (int)m_authInfo[Username];
               if ((user.AuthAll) && (authFlag == user.AuthTypes))
               {
                  Needed = false;
               }
               else if ((!user.AuthAll) && ((authFlag & user.AuthTypes) != 0))
               {
                  Needed = false;
               }
            }
         }
      }

      #endregion SSH Server authentication handling

      #region SSH Server socket-related processing

      /// <summary>
      /// Is fired when ElSSHServer has data to write to socket
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="Buffer">Data to write to socket</param>
      private void SSHServer_OnSend(object Sender, byte[] Buffer)
      {
         try
         {
            int toSend = Buffer.Length;
            int sent;
            int ptr = 0;
            while (toSend > 0)
            {
               sent = m_Socket.Send(Buffer, ptr, toSend, SocketFlags.None);
               ptr += sent;
               toSend -= sent;
            }
         }
         catch(Exception ex)
         {
                Logger.Log("Socket send operation failed: " + ex.Message);
            if (m_SSHServer.Active)
            {
               m_SSHServer.OnSend -= new SBSSHCommon.TSSHSendEvent(SSHServer_OnSend);
               m_SSHServer.Close(true);
            }
            else CloseSession();
         }
      }

      /// <summary>
      /// Is fired when ElSSHServer needs some data to be read from socket
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="Buffer">Place where to put received data</param>
      /// <param name="MaxSize">Maximal amount of data to receive</param>
      /// <param name="Written">Number of bytes actually written</param>
      private void SSHServer_OnReceive(object Sender, ref byte[] Buffer, int MaxSize, out int Written)
      {
         try
         {
            if (m_Socket.Poll(100000, SelectMode.SelectRead))
            {
               Written = m_Socket.Receive(Buffer, MaxSize, SocketFlags.None);
               if (Written == 0)
               {
                  if (m_SSHServer.Active)
                  {
                     m_SSHServer.OnSend -= new SBSSHCommon.TSSHSendEvent(SSHServer_OnSend);
                     m_SSHServer.Close(true);
                  }
                  else CloseSession();
               }
               else
               {
                  RestartSocketSessionTimer();
               }
            }
            else
            {
               Written = 0;
            }
         }
         catch(Exception ex)
         {
            Written = 0;
                Logger.Log("Socket receive operation failed: " + ex.Message);
            if (m_SSHServer.Active)
            {
               m_SSHServer.OnSend -= new SBSSHCommon.TSSHSendEvent(SSHServer_OnSend);
               m_SSHServer.Close(true);
            }
            else CloseSession();
         }
      }
      
      #endregion

      #region SSH Server general-purpose event handlers

      /// <summary>
      /// Is fired when SSH session is closed
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      private void SSHServer_OnCloseConnection(object Sender)
      {
         CloseSession();
         m_Error = true;
      }

      /// <summary>
      /// Is fired if some error occurs during SSH communication
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="ErrorCode">Error code</param>
      private void SSHServer_OnError(object Sender, int ErrorCode)
      {
         Logger.Log("SSH protocol error #" + ErrorCode.ToString());
         m_Error = true;
      }

      #endregion

      #region SSH Server connection-layer event handlers

      /// <summary>
      /// Is fired when a client requests SSH subsystem
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="Connection">Logical connection object</param>
      /// <param name="Subsystem">Subsystem name</param>
      private void SSHServer_OnOpenSubsystem(object Sender, TElSSHTunnelConnection Connection, string Subsystem)
      {
         Logger.Log("Subsystem " + Subsystem + " opened");
         if (Subsystem == "sftp")
         {
            SFTPSession sess = new SFTPSession(Connection);
            m_Status += "SFTP ";
            SessionInfoChanged(this);
         }
      }

      /// <summary>
      /// Is fired when a client requests shell
      /// </summary>
      /// <param name="Sender">ElSSHServer object</param>
      /// <param name="Connection">Logical connection object</param>
        ///
      private void SSHServer_OnOpenShell(object Sender, TElSSHTunnelConnection Connection)
      {
         Logger.Log("Shell requested");
         // System.Type tp = typeof(TElShellSSHSubsystemHandler);
            TElSSHSubsystemThread thread = new TElSSHSubsystemThread(new SBSSHHandlers.TElCustomSSHSubsystemHandler(Connection, true), Connection, true);
         
            thread.Resume();
         m_Status += "Shell ";
         SessionInfoChanged(this);
      }

      #endregion

      #region Private methods
      /// <summary>
      /// Sets up server properties
      /// </summary>
      private void SetupServer()
      {
         short i;
         lock (Globals.Settings)
         {
            try
            {
               TElSSHKey Key = new TElSSHKey();
               byte [] BServerKey = SBUtils.Unit.BytesOfString(Globals.Settings.ServerKey);
               int Result = Key.LoadPrivateKey(BServerKey, BServerKey.Length, "");
               if (Result == 0)
               {
                  m_HostKeys.Add(Key);
               }
            }
            catch(Exception exc)
            {
               Logger.Log("SSHSession.SetupServer - invalid private key"
                                + exc.Message,true);
            }
         }
         m_SSHServer.KeyStorage = m_HostKeys;
         m_SSHServer.AllowedSubsystems.Add("sftp");
         m_SSHServer.SoftwareName = "SSHBlackbox.5";
         m_SSHServer.ForceCompression = Globals.Settings.ForceCompression;
         m_SSHServer.OnAuthAttempt += new TSSHAuthAttemptEvent(SSHServer_OnAuthAttempt);
         m_SSHServer.OnAuthFailed += new SBSSHCommon.TSSHAuthenticationFailedEvent(SSHServer_OnAuthFailed);
         m_SSHServer.OnAuthPassword += new TSSHAuthPasswordEvent(SSHServer_OnAuthPassword);
         m_SSHServer.OnAuthPublicKey += new TSSHAuthPublicKeyEvent(SSHServer_OnAuthPublicKey);
         m_SSHServer.OnAuthKeyboard += new TSSHAuthKeyboardEvent(SSHServer_OnAuthKeyboard);
         m_SSHServer.OnAuthKeyboardResponse += new TSSHAuthKeyboardResponseEvent(SSHServer_OnAuthKeyboardResponse);
         m_SSHServer.OnFurtherAuthNeeded += new TSSHFurtherAuthNeededEvent(SSHServer_OnFurtherAuthNeeded);
         m_SSHServer.OnSend += new SBSSHCommon.TSSHSendEvent(SSHServer_OnSend);
         m_SSHServer.OnReceive += new SBSSHCommon.TSSHReceiveEvent(SSHServer_OnReceive);
         m_SSHServer.OnCloseConnection += new SBSSHCommon.TSSHCloseConnectionEvent(SSHServer_OnCloseConnection);
         m_SSHServer.OnError += new SBSSHCommon.TSSHErrorEvent(SSHServer_OnError);
         m_SSHServer.OnOpenSubsystem += new TSSHOpenSubsystemEvent(SSHServer_OnOpenSubsystem);
         m_SSHServer.OnOpenShell += new TSSHOpenShellEvent(SSHServer_OnOpenShell);
           //m_SSHServer.OnOpenSession += new TSSHOpenSessionEvent(SSHServer_OnOpenSession);
        
        }
        
      /// <summary>
      /// Session thread function
      /// </summary>
      private void ReadThread()
      {
         try
         {   
            m_Error = false;
            m_SSHServer.Open();
            while ((m_Socket != null) && (m_Socket.Connected) && (!m_Error))
            {
               if (m_Socket.Poll(1000000, SelectMode.SelectRead))
               {
                  m_SSHServer.DataAvailable();                  
               }
               else
               {
                  Thread.Sleep(50);
               }
            }            
         }
         catch(Exception ex)
         {
            if (!(ex is ThreadAbortException))
            {
               Logger.Log("ReadThread : " + ex.Message);
               CloseSession();
            }
            else
            {
               if (this.SessionClosed != null)
               {
                  this.SessionClosed(this);
                  m_Thread = null;
               }   
            }            
         }
      }

      private void RestartSocketSessionTimer()
      {
         //m_SocketSessionTimer.Change(0, 1000) = false;
            m_SocketSessionTimer.Change(300000, 1000);
         //m_SocketSessionTimer.Interval = 5 * 60 * 1000;
         //m_SocketSessionTimer.Enabled = true;
      }

      private void CleanUp()
      {
         DoSocketShutdown();

         if (m_SSHServer.Active)
         {
            m_SSHServer.OnSend -= new SBSSHCommon.TSSHSendEvent(SSHServer_OnSend);
            m_SSHServer.Close(true);
         }

         if (m_Thread != null)
         {         
                //m_SocketSessionTimer.Enabled = false;
                //m_SocketSessionTimer.Elapsed -= new System.Timers.ElapsedEventHandler(OnSocketSessionTimeout);   
                //m_SocketSessionTimer.Close();
                m_SocketSessionTimer.Dispose();
            m_Thread.Abort();
            //m_Thread.Join(1200);   
            //m_Thread = null;                                 
         }   
      }
      
      #endregion

      #region IDisposable Members

      public void Dispose()
      {
         CleanUp();
      }

      private void DoSocketShutdown()
      {
         try
         {   
            if (m_Socket != null) //&& (m_Socket.Connected))
            {
               Logger.Log("Closing the socket");
               m_Socket.Shutdown(System.Net.Sockets.SocketShutdown.Both);   
               m_Socket.Close();
               m_Socket = null;
            }
         }
         catch(Exception ex)
         {
            Logger.Log("DoSocketShutdown : " + ex.Message);
         }
      }

      private void CloseSocket()
      {
         if (m_Socket != null)
         {
            try
            {   
               if (m_Socket.Connected)
               {
                  Logger.Log("Closing the socket");
                  m_Socket.Shutdown(SocketShutdown.Both);
                  m_Socket.Close();                     
                  m_Socket = null;
               }
            }
            catch(Exception ex)
            {
               Logger.Log("CloseSocket() : " + ex.Message, true);
            }
         }
      }

      private void OnSocketSessionTimeout(object sender)
      {
         m_SocketSessionTimer.Change(System.Threading.Timeout.Infinite, 1000);
         Logger.Log("Socket closed by timeout");
         CloseSession();
         //m_Thread.Abort();
      }

        

      #endregion

      #region Class members

      private Socket m_Socket = null;
      private Thread m_Thread = null;
      private object m_synch = null;
      private System.Threading.Timer m_SocketSessionTimer = null;
        private System.Threading.TimerCallback m_SocketSessionTimercb = null;
      private Hashtable m_authInfo = new Hashtable();
        private TElSSHServer m_SSHServer = new TElSSHServer();
      private TElSSHMemoryKeyStorage m_HostKeys = new TElSSHMemoryKeyStorage();
      private object m_Data = null;
      private string m_Status = "";
      private string m_Username = "";
      private string m_Host = "";
      private string m_ClientSoftware = "";
      private DateTime m_StartTime;
      private bool m_Error = false;

      #endregion

   }
}

using System;
using System.Threading;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using SBSSHKeyStorage;

namespace SSHServer
{
   /// <summary>
   /// Responsible for listening for incoming connections and processing accepted ones
   /// </summary>
   internal class ServerListener : IDisposable
   {
      public ServerListener()
      {
         m_synch = new object();
         m_arrSessions = new ArrayList();
         m_Event = new ManualResetEvent(false);
         m_Thread = new Thread(new ThreadStart(Listen));
         m_Thread.Name = "SSH_Server_Listener_Thread";
      }            

      #region Public events

      public delegate void SessionStartedHandler(SSHSession sender);
      public event SessionStartedHandler SessionStarted;

      public delegate void SessionClosedHandler(SSHSession sender);
      public event SessionClosedHandler SessionClosed;

      public delegate void SessionInfoChangedHandler(SSHSession sender);
      public event SessionInfoChangedHandler SessionInfoChanged;

      #endregion

      #region IDisposable Members

      public void Dispose()
      {
         //if ((m_Thread != null) && (m_Thread.ThreadState != ThreadState.Unstarted))
            if ((m_Thread != null))
         {      
            m_Event.Reset();
            Stop();

            //kill thread
            m_Thread.Abort();
            m_Thread.Join(1000);                                    
            m_Event.Close();

            //kill sockets (sessions)
            lock(m_synch)
            {            
               for (int i = 0, N = m_arrSessions.Count; i < N; ++i)
               {//stop all sessions
                  SSHSession session=(SSHSession)m_arrSessions[i];
                  System.Diagnostics.Debug.Assert(session!=null);
                  session.SessionClosed-=new SSHSession.SessionClosedHandler(OnSessionClosed);
                  session.CloseSession();
                  session.Dispose();
               }
               m_arrSessions.Clear();
            }
            m_Thread = null;
         }
      }

      #endregion
   
      #region Public methods
      /// <summary>
      /// Starts listening for incoming connections
      /// </summary>
      /// <returns>true, if the listening socket was successfully allocated</returns>
      public bool Start()
      {
         try
         {         
            Logger.Log("Starting SSH server listener...");
               //MD m_SocketListener = new TcpListener(IPAddress.Parse(Globals.Settings.ServerHost),
            m_SocketListener = new TcpListener(IPAddress.Parse("192.168.140.218"),
               Globals.Settings.ServerPort);
            m_SocketListener.Start();   
            m_Thread.Start();   
            m_Event.Set();
            if (Globals.main != null)
            {
               lock(Globals.main)
               {
                  Globals.main.tbTop.Buttons[0].Enabled = false;
                  Globals.main.tbTop.Buttons[1].Enabled = true;
               }
            }
            Globals.ServerStarted = true;
            Logger.Log("SSH server listener started.");
            return true;
         }
         catch(Exception exc)
         {
            Logger.Log("ServerListener.Start : " + exc.Message,true);
            return false;
         }
      }

      /// <summary>
      /// Stops listening for incoming connections
      /// </summary>
      public void Stop()
      {
         try
         {
            if (m_SocketListener != null)
            {
               //stop listener
               Logger.Log("Stopping socket listener");   
               m_SocketListener.Stop();
               if (Globals.main != null)
               {
                  lock(Globals.main)
                  {
                     Globals.main.tbTop.Buttons[0].Enabled = true;
                     Globals.main.tbTop.Buttons[1].Enabled = false;
                  }
               }
               Globals.ServerStarted = false;
               Logger.Log("Socket listener stopped");   
            }
         }
         catch(Exception ex)
         {
            Logger.Log("Exception while stopping socket listener : " + ex.Message);
         }
      }

      #endregion

      #region Private methods

      private Socket AcceptSocket()
      {
         Socket socket = null;
         try
         {
            if (m_SocketListener.Pending())
            {
               socket = m_SocketListener.AcceptSocket();
            }
         }
         catch(Exception ex)
         {
            Logger.Log("AcceptSocket() : " + ex.Message,true);
         }
         return socket;
      }

      private void Listen()
      {   
         while(m_Event.WaitOne())
         {      
            Socket socket = AcceptSocket();         
            if(socket != null)
            {            
               Logger.Log("ServerListener.Listen : New connection available");
               lock(m_synch)
               {               
                  if(m_arrSessions.Count < m_MaxSocketSessions)
                  {
                     //create new session and start it in a new thread                     
                     SSHSession session = new SSHSession(socket, ++m_ClientCount);
                     session.SessionClosed += new SSHSession.SessionClosedHandler(OnSessionClosed);   
                     session.SessionInfoChanged += new SSHServer.SSHSession.SessionInfoChangedHandler(OnSessionInfoChanged);
                     m_arrSessions.Add(session);
                     Logger.Log("Connection accepted. Active connections "  + m_arrSessions.Count.ToString() + " from " + m_MaxSocketSessions.ToString());
                     session.Start();
                     this.SessionStarted(session);
                  }
                  else
                  {   
                     Logger.Log("New connection rejected");
                     try
                     {                  
                        socket.Shutdown(SocketShutdown.Both);
                        socket.Close();
                     }
                     catch(Exception)
                     {
                        ;
                     }                  
                  }
               }
            }
            else
            {
               Thread.Sleep(500);
            }
         }
      }

      #endregion

      #region Event handlers

      private void OnSessionClosed(SSHSession sender)
      {            
         lock(m_synch)
         {   
            m_arrSessions.Remove(sender);
            Logger.Log("ServerListener.OnSessionClosed()");         
         }
         if (this.SessionClosed != null)
         {
                this.SessionClosed(sender);
         }
         sender.SessionClosed -= new SSHSession.SessionClosedHandler(OnSessionClosed);               
         sender.SessionInfoChanged -= new SSHSession.SessionInfoChangedHandler(OnSessionInfoChanged);
      }

      private void OnSessionInfoChanged(SSHSession sender)
      {
            this.SessionInfoChanged(sender);
      }

      #endregion

      #region Class members
      
      private object m_synch = null;
      private ArrayList m_arrSessions = null;    
      private TcpListener m_SocketListener = null;
      private ManualResetEvent m_Event = null;
      private Thread m_Thread = null;
      private int m_MaxSocketSessions = 20;
      private int m_ClientCount = 0;
      
      #endregion

   }
}


*
#7599
Posted: 09/15/2008 05:17:35
by Manfred Domandl (Basic support level)
Joined: 09/11/2008
Posts: 9

Hy,

I got the main problem. I changed the memory setup of my device and know it's running.
Know I get a "handler must be synchronous" exception at m_SSHServer.DataAvailable();
Any idea what could issue the exception?

Thanks in advance.

Kind regards
Manfred Domandl
InterCard
#7608
Posted: 09/15/2008 07:48:03
by Ken Ivanov (EldoS Corp.)

Did I understood you right that you get the OnOpenShell event to work now?

The exception you mentioned is thrown if the subsystem handler passed to TElSSHSubsystemThread constructor is asynchronous. Do you create the TElShellSSHSubsystemHandler is the same way as it is done in the desktop application? The sample uses the following code that should work:

TElSSHSubsystemThread thread = new TElSSHSubsystemThread(new TElShellSSHSubsystemHandler(Connection, true), Connection, true);
thread.Resume();
#7610
Posted: 09/15/2008 08:11:24
by Manfred Domandl (Basic support level)
Joined: 09/11/2008
Posts: 9

Yes, now I will get this event.

Because of the following compile error "Fehler CS1503: 1-Argument: kann nicht von "TElShellSSHSubsystemHandler" in "SBSSHHandlers.TElCustomSSHSubsystemHandler" konvertiert werden."

I changed it to
"TElSSHSubsystemThread thread = new TElSSHSubsystemThread(new SBSSHHandlers.TElCustomSSHSubsystemHandler(Connection, true), Connection, true);"

May be this compile error is because I have to use the CF version?
Also by EldoS: RawDisk
Access locked and protected files in Windows, read and write disks and partitions and more.

Reply

Statistics

Topic viewed 6250 times

Number of guests: 1, registered members: 0, in total hidden: 0




|

Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!