EldoS | Feel safer!

Software components for data protection, secure storage and transfer

SSHClient problem with threads

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.
#4278
Posted: 11/11/2007 13:23:24
by Dejan Caric (Basic support level)
Joined: 11/11/2007
Posts: 3

Hello ppl!
I have a big problem using SSHClient.
I have sample form with 3 txtboxes and one button.
1 txtbox is for the response I get from SSHClient
1 txtbox is used for send requests to SSHClient
1 txtbox is user for log witch notifies me about connection status.
When I click on the button, I create instance of one of my class and it makes SSH connection with Atmel micro controller.
Here's the source of my class
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using SBSSHClient;
using SBSSHCommon;
using SBUtils;
using SBSSHKeyStorage;
using System.Net;
using System.Threading;

namespace SSHControler
{
    public delegate void SSHControlerEventHandler(object sender, SSHControlerEventArgs e);

    class SSHConnector
    {
        public event SSHControlerEventHandler LogEvent;
        public event SSHControlerEventHandler ResponseEvent;
        public event SSHControlerEventHandler ErrorEvent;

        protected virtual void OnLogEvent(SSHControlerEventArgs e)
        {
            if (LogEvent != null)
                LogEvent(this, e);
        }

        protected virtual void OnResponseEvent(SSHControlerEventArgs e)
        {
            if (ResponseEvent != null)
                ResponseEvent(this, e);
        }

        protected virtual void OnErrorEvent(SSHControlerEventArgs e)
        {
            if (ErrorEvent != null)
                ErrorEvent(this, e);
        }

        private Socket clientSocket;
        private TElSSHClient sshClient;
        private TElShellSSHTunnel sshTunnel;
        private TElSSHTunnelList sshTunnelList;
        private TElSSHTunnelConnection sshTunnelConnection;
        private TElSSHMemoryKeyStorage keyStorage;
        private bool connected = false;

        private byte[] clientSocketReceiveBuf = new byte[8192];
        private int clientSocketReceiveLen = 0;

        public SSHConnector()
        {
            Init();
        }

        private void Init()
        {
            sshClient = new TElSSHClient();
            sshClient.OnSend += new SBSSHCommon.TSSHSendEvent(sshClient_OnSend);
            sshClient.OnReceive += new SBSSHCommon.TSSHReceiveEvent(sshClient_OnReceive);
            sshClient.OnOpenConnection += new SBSSHCommon.TSSHOpenConnectionEvent(sshClient_OnOpenConnection);
            sshClient.OnCloseConnection += new SBSSHCommon.TSSHCloseConnectionEvent(sshClient_OnCloseConnection);
            sshClient.OnDebugData += new SBSSHCommon.TSSHDataEvent(sshClient_OnDebugData);
            sshClient.OnError += new SBSSHCommon.TSSHErrorEvent(sshClient_OnError);
            sshClient.OnAuthenticationSuccess += new SBUtils.TNotifyEvent(sshClient_OnAuthenticationSuccess);
            sshClient.OnAuthenticationFailed += new SBSSHCommon.TSSHAuthenticationFailedEvent(sshClient_OnAuthenticationFailed);
            sshClient.OnAuthenticationKeyboard += new TSSHAuthenticationKeyboardEvent(sshClient_OnAuthenticationKeyboard);
            sshClient.OnKeyValidate += new TSSHKeyValidateEvent(sshClient_OnKeyValidate);
            sshTunnel = new TElShellSSHTunnel();
            sshTunnel.OnOpen += new TTunnelEvent(sshTunnel_OnOpen);
            sshTunnel.OnClose += new TTunnelEvent(sshTunnel_OnClose);
            sshTunnel.OnError += new SBSSHCommon.TTunnelErrorEvent(sshTunnel_OnError);
            sshTunnelList = new TElSSHTunnelList();
            sshTunnel.TunnelList = sshTunnelList;
            sshClient.TunnelList = sshTunnelList;
            keyStorage = new TElSSHMemoryKeyStorage();
            sshClient.KeyStorage = keyStorage;
        }

        public void Connect()
        {
            //Thread t = new Thread(new ThreadStart(ConnectionThread));
            //t.Start();
            ConnectionThread();
        }

        private void ConnectionThread()
        {
            if (!connected)
            {
                connected = true;
                try
                {
                    sshTunnelConnection = null;
                    sshClient.Versions = 0;
                    sshClient.Versions |= SBSSHCommon.Unit.sbSSH2;
                    sshClient.UserName = "djokica";
                    sshClient.Password = "kuronja";
                    keyStorage.Clear();
                    TElSSHKey key = new TElSSHKey();

                    sshClient.AuthenticationTypes &= ~(SBSSHConstants.Unit.SSH_AUTH_TYPE_PUBLICKEY);



                    IPAddress hostadd = Dns.Resolve("192.168.100.98").AddressList[0];
                    IPEndPoint epHost = new IPEndPoint(hostadd, Convert.ToInt32("22", 10));
                    clientSocket = new Socket(AddressFamily.InterNetwork,
                        SocketType.Stream, ProtocolType.Tcp);
                    clientSocket.BeginConnect(epHost, new AsyncCallback(clientSocket_OnOpenConnection), null);
                }
                catch (Exception ex)
                {
                    OnErrorEvent(new SSHControlerEventArgs("error1 " + ex.Message));
                    Reset();
                }
            }
            else
                Reset();
        }

        public void Reset()
        {
            if (!connected)
                return;
            connected = false;

            if (sshClient.Active)
                sshClient.Close(true);

            if (clientSocket != null)
            {
                try { clientSocket.Close(); }
                catch (Exception) { }
                finally { clientSocket = null; }
            }
        }

        public void sendRequest(string s)
        {
            try
            {
                if (sshTunnelConnection != null)
                {
                    string message = s + "\r";
                    byte[] buf = Encoding.UTF8.GetBytes(message);
                    sshTunnelConnection.SendData(buf);
                }
            }
            catch (Exception ex)
            {
                OnErrorEvent(new SSHControlerEventArgs("error2: " + ex.Message));
            }
        }

        #region SSHClient Callbacks

        private void sshClient_OnKeyValidate(object Sender, TElSSHKey ServerKey, ref bool Validate)
        {
            OnLogEvent(new SSHControlerEventArgs("Server key received"));
            Validate = true; // NEVER do this. You MUST check the key validity somehow
        }

        private void sshClient_OnSend(object Sender, byte[] Buffer)
        {
            try
            {
                clientSocket.BeginSend(Buffer, 0, Buffer.Length, 0,
                    new AsyncCallback(clientSocket_OnSend), null);

            }
            catch (Exception ex)
            {
                OnErrorEvent(new SSHControlerEventArgs("error3: " + ex.Message));
                Reset();
            }
        }

        private void sshClient_OnReceive(object Sender, ref byte[] Buffer, int MaxSize, out int Written)
        {
            Written = Math.Min(MaxSize, clientSocketReceiveLen);
            if (Written > 0)
            {
                Array.Copy(clientSocketReceiveBuf, 0, Buffer, 0, Written);
                Array.Copy(clientSocketReceiveBuf, Written, clientSocketReceiveBuf, 0, clientSocketReceiveLen - Written);
                clientSocketReceiveLen -= Written;
            }
        }

        private void sshClient_OnOpenConnection(object Sender)
        {
            OnLogEvent(new SSHControlerEventArgs("Connection started"));
            OnLogEvent(new SSHControlerEventArgs("Server: " + sshClient.ServerSoftwareName));
            OnLogEvent(new SSHControlerEventArgs("Version: SSHv2"));
            OnLogEvent(new SSHControlerEventArgs("Kex algorithm: " + sshClient.KexAlgorithm));
            OnLogEvent(new SSHControlerEventArgs("Block algorithm: " + sshClient.EncryptionAlgorithmServerToClient));
            OnLogEvent(new SSHControlerEventArgs("Compression algorithm: " + sshClient.CompressionAlgorithmServerToClient));
            OnLogEvent(new SSHControlerEventArgs("MAC algorithm: " + sshClient.MacAlgorithmServerToClient));
        }

        private void sshClient_OnCloseConnection(object Sender)
        {
            OnLogEvent(new SSHControlerEventArgs("SSH connection closed"));
            Reset();
        }

        private void sshClient_OnDebugData(object Sender, byte[] Buffer)
        {
            OnLogEvent(new SSHControlerEventArgs("[Debug data] " + Encoding.Default.GetString(Buffer)));
        }

        private void sshClient_OnError(object Sender, int ErrorCode)
        {
            OnLogEvent(new SSHControlerEventArgs("Error 4" + Convert.ToString(ErrorCode, 10)));
        }

        private void sshClient_OnAuthenticationSuccess(object Sender)
        {
            OnLogEvent(new SSHControlerEventArgs("Authentication successeded"));
        }

        private void sshClient_OnAuthenticationFailed(object Sender, int AuthenticationType)
        {
            OnLogEvent(new SSHControlerEventArgs("Authentication failed for type " + Convert.ToString(AuthenticationType, 10)));
        }

        delegate void AuthKeyboardHandler(object Sender, SBStringList.TElStringList Prompts,
            bool[] Echo, SBStringList.TElStringList Responses);
        private void sshClient_OnAuthenticationKeyboard(object Sender, SBStringList.TElStringList Prompts,
            bool[] Echo, SBStringList.TElStringList Responses)
        {
            //if (InvokeRequired)
            //{
            //    AuthKeyboardHandler d = new AuthKeyboardHandler(sshClient_OnAuthenticationKeyboard);
            //    Invoke(d, new object[] { Sender, Prompts, Echo, Responses });
            //}

            //else
            //{
            //    Responses.Clear();
            //    for (int i = 0; i < Prompts.Count; i++)
            //    {
            //        string Response = "";
            //        //if (PromptForm.Prompt(Prompts[i], Echo[i], ref Response))
            //        //    Responses.Add(Response);
            //        //else
            //        Responses.Add("");
            //    }
            //}
        }
        #endregion

        #region SSHTunnel Callbacks

        private void sshTunnel_OnOpen(object Sender, TElSSHTunnelConnection TunnelConnection)
        {
            sshTunnelConnection = TunnelConnection;
            sshTunnelConnection.OnData += new SBSSHCommon.TSSHDataEvent(sshTunnelConnection_OnData);
            sshTunnelConnection.OnError += new SBSSHCommon.TSSHErrorEvent(sshTunnelConnection_OnError);
            sshTunnelConnection.OnClose += new SBSSHCommon.TSSHChannelCloseEvent(sshTunnelConnection_OnClose);
        }

        private void sshTunnel_OnClose(object Sender, TElSSHTunnelConnection TunnelConnection)
        {
        }

        private void sshTunnel_OnError(object Sender, int ErrorCode, object data)
        {
            OnLogEvent(new SSHControlerEventArgs("Tunnel error: " + ErrorCode));
        }

        #endregion

        #region SSHTunnelConnection Callbacks

        private void sshTunnelConnection_OnData(object Sender, byte[] Buffer)
        {
            String s = Encoding.ASCII.GetString(Buffer);
            OnResponseEvent(new SSHControlerEventArgs(s));
        }

        private void sshTunnelConnection_OnError(object Sender, int ErrorCode)
        {
            OnLogEvent(new SSHControlerEventArgs("Connection error: " + ErrorCode));
        }

        private void sshTunnelConnection_OnClose(object Sender, SBSSHCommon.TSSHCloseType CloseType)
        {
            OnLogEvent(new SSHControlerEventArgs("Shell connection closed"));
        }

        #endregion

        #region ClientSocket Callbacks

        private void clientSocket_OnOpenConnection(IAsyncResult ar)
        {
            try
            {
                clientSocket.EndConnect(ar);
                sshClient.Open();
                clientSocket.BeginReceive(clientSocketReceiveBuf, 0,
                    clientSocketReceiveBuf.Length, 0,
                    new AsyncCallback(clientSocket_OnReceive),
                    null);


                OnLogEvent(new SSHControlerEventArgs("Client socket connected"));

            }
            catch (ObjectDisposedException e1)
            {
                OnErrorEvent(new SSHControlerEventArgs("DISPOSED"));
            }
            catch (ArgumentNullException e2)
            {
                OnErrorEvent(new SSHControlerEventArgs("AR NULL"));
            }
            catch (SocketException e3)
            {
                OnErrorEvent(new SSHControlerEventArgs("SOCKEET EXCEPTION: " + e3.Message));
            }
            catch (Exception ex)
            {
                OnErrorEvent(new SSHControlerEventArgs("OVDE $$$: " + ex.Message));
                Reset();
            }
        }

        private void clientSocket_OnReceive(IAsyncResult ar)
        {
            try
            {
                clientSocketReceiveLen = clientSocket.EndReceive(ar);
                while (clientSocketReceiveLen > 0)
                {
                    sshClient.DataAvailable();
                }
                clientSocket.BeginReceive(clientSocketReceiveBuf, 0,
                    clientSocketReceiveBuf.Length, 0,
                    new AsyncCallback(clientSocket_OnReceive), null);
            }
            catch (Exception ex)
            {
                OnErrorEvent(new SSHControlerEventArgs("error5: " + ex.Message));
                Reset();
            }
        }

        private void clientSocket_OnSend(IAsyncResult ar)
        {
            try
            {
                clientSocket.EndSend(ar);
            }
            catch (Exception ex)
            {
                OnErrorEvent(new SSHControlerEventArgs(ex.Message));
                Reset();
            }
        }

        #endregion

    }

    #region CustomEvents
    public class SSHControlerEventArgs : EventArgs
    {
        private string s;
        public SSHControlerEventArgs(string s)
        {
            this.s = s;
        }

        public string Message
        {
            get { return s; }
        }
    }
    #endregion
}


And here is the code of Test form
Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using SBSSHClient;
using SBSSHCommon;
using SBUtils;
using SBSSHKeyStorage;
using System.Net;
using System.Threading;


namespace SSHControler
{
    public partial class Form1 : Form
    {

        SSHConnector ctrl;
        bool upis = false;

        public Form1()
        {
            InitializeComponent();
            ctrl = new SSHConnector();
            ctrl.ErrorEvent += new SSHControlerEventHandler(showError);
            ctrl.LogEvent += new SSHControlerEventHandler(showLog);
            ctrl.ResponseEvent += new SSHControlerEventHandler(showResponse);
          
        }

        private void showError(object sender, SSHControlerEventArgs e)
        {
            MessageBox.Show(e.Message);
        }

        private void showLog(object sender, SSHControlerEventArgs e)
        {
            textBox7.Text += e.Message + Environment.NewLine;
        }

        private void showResponse(object sender, SSHControlerEventArgs e)
        {
            textBox5.Text += e.Message;
            if (upis == false)
            {
                //ctrl.sendRequest("x 234 6443");
                upis = true;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread t = new Thread(new ThreadStart(connectThread));
            t.Start();
        }

        private void connectThread()
        {
            ctrl.Connect();
        }

        private void textBox6_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                ctrl.sendRequest(textBox6.Text);
                textBox6.Clear();
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ctrl.Reset();
        }
              
      
    }
}


When I click on button1 and call ctrl.Connect() directly, application freezes for 4 or 5 seconds.
I want to escape that freezing so I put that method in thread as shown.
Now I'm getting error:
Code
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.


Help!
#4279
Posted: 11/11/2007 13:43:23
by Eugene Mayevski (EldoS Corp.)

You can not use the component from within several threads in parallel. ElSimpleSSHClient class is synchronous and it will block on all of it's operation. If you need asynchronous processing, you can use ElSSHClient.


Sincerely yours
Eugene Mayevski
#4280
Posted: 11/11/2007 17:02:22
by Dejan Caric (Basic support level)
Joined: 11/11/2007
Posts: 3

Is there any sample project with asynchronous processing?
I couldn't find it in samples.
Thank you
#4281
Posted: 11/12/2007 00:51:57
by Eugene Mayevski (EldoS Corp.)

From the readme for one of the samples:

This sample illustrates use of TElSFTPClient and supplementary classes
(TElSSHClient, TElShellSSHTunnel and TElSSHTunnelConnection) with .NET
Framework sockets. Sockets are used in asynchronous mode.



Sincerely yours
Eugene Mayevski
#4284
Posted: 11/12/2007 05:29:06
by Dejan Caric (Basic support level)
Joined: 11/11/2007
Posts: 3

I have rechecked my code hundreds of times and I can not see whats wrong.
I'm using ElSSHClient, not the ElSimpleSSHClient and the problem still exists.
I have posted the code so if anyone knows the solution I would be very grateful.
#4285
Posted: 11/12/2007 07:32:26
by Ken Ivanov (EldoS Corp.)

It would be great if you create a ticket in the Helpdesk system and post a complete project that can be used to reproduce the problem there.
Also by EldoS: CallbackRegistry
A component to monitor and control Windows registry access and create virtual registry keys.

Reply

Statistics

Topic viewed 2991 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!