TScSSHShell: OnAsyncReceive event never raise

Discussion of open issues, suggestions and bugs regarding network security and data protection solution - SecureBridge
Post Reply
Fontaine
Posts: 5
Joined: Fri 09 Dec 2011 14:21
Location: Rennes France

TScSSHShell: OnAsyncReceive event never raise

Post by Fontaine » Fri 06 Jan 2012 14:48

Hello,

with a shell in nonblocking mode, OnAsyncReceive doesn't raise.
part of my code:
class TThreadSshClient : public TThread
{
private:
struct DeviceInfo &Infos;
TScSSHClient *ScSSHClient1;
TScFileStorage *ScFileStorage1;
TScSSHShell *ScSSHShell1;
...
void __fastcall ScSSHClientServerKeyValidate(TObject *Sender, TScKey *NewServerKey, bool &Accept);
void __fastcall ScSSHShellOnAsyncReceive(TObject *Sender);
};

...
ScSSHClient1 = new TScSSHClient(Owner);
ScFileStorage1 = new TScFileStorage(Owner);
ScSSHShell1 = new TScSSHShell(Owner);
ScSSHClient1->KeyStorage = ScFileStorage1;
ScSSHClient1->OnServerKeyValidate = ScSSHClientServerKeyValidate ;
ScSSHShell1->Client = ScSSHClient1;

ScSSHShell1->OnAsyncReceive = ScSSHShellOnAsyncReceive;
ScSSHShell1->NonBlocking = true;
...
//---------------------------------------------------------------------------

void __fastcall TThreadSshClient::ScSSHShellOnAsyncReceive(TObject *Sender)
{
char buffer[10005];
int ReadBytes = ScSSHShell1->ReadBuffer(buffer, sizeof(buffer));

if(ReadBytes == 0)
throw EAbort("Failed. (ReadBytes == 0) Unexpected disconnection");
Text += AnsiString(buffer, ReadBytes);

}

------------------------------------------------------------------------

I made a tempory work around using a loop with a timeout, it's working fine but it's not very satisfying:
...
while (!Terminated && ScSSHShell1->Connected && i_SSHReceivedTimeOutReadBuffer(buffer, sizeof(buffer));
if(ReadBytes != 0)
Text += AnsiString(buffer, ReadBytes);

}
----------------------------------------------------------------

I have also a question about OnAsyncReceive:
when exaclty should it be raise please?
each time there is an action (write read..)or only on read? for each characters or only one time per message?

have you exemple using OnAsyncReceive (there is no demo in secure bridge for C++Builder5)

Thanks for your help.
regards.

Dimon
Devart Team
Posts: 2910
Joined: Mon 05 Mar 2007 16:32

Post by Dimon » Thu 12 Jan 2012 15:31

This problem occurred because you create and start TScSSHClient and TScSSHShell in separate thread. TScSSHShell in NonBlocking mode uses own thread and therefore you don't need to use another thread. You can use this functionality in the main thread without performance penalty.
Or, at least, for solving the problem, you should set although one SSH connection in the main thread.

Klaus01
Posts: 1
Joined: Fri 20 Jan 2012 13:10

Post by Klaus01 » Fri 20 Jan 2012 13:28

Hello,

I've the same problem.
TScSshClient and TScSshShell instancse are created in the same thread.
But is not the main thread.

Code: Select all

procedure TJobs._OnAsyncReceive(sender: TObject);
var
  s: ansiString;
begin
  (sender as TscSshShell).ReadBuffer(s,(sender as TscSshShell).InCount);
  logger.add('ar '+s,0);
end;

Code: Select all

 
function TJobs._doJob(sshTarget: AnsiString):Boolean;
var

  sshClient : TScSshClient;
  sshKeyStorage : TScFileStorage;
  sshChannel : TscSSHChannel;
  sshShell : TScSshShell;

begin
  sshKeyStorage := TScFileStorage.Create(nil);
  sshClient := TScSshClient.Create(nil);
  sshShell := TscSshShell.Create(nil);
  try
    try
      sshClient.KeyStorage := sshKeyStorage;

      sshClient.Authentication  := ScSSHUtil.atPassword;
      sshClient.User := configData.sysUsername;
      sshClient.Password := configData.sysPassword;

      sshClient.HostName := sshTarget;
      sshClient.Port := configData.SSHPort;

      sshClient.OnServerKeyValidate := _onServerKeyValidate;

      sshShell := TscSshShell.Create(nil);
      try
        sshShell.NonBlocking := true;
        sshShell.OnAsyncReceive := _onAsyncReceive;
        sshShell.Client := sshClient;
        sshShell.NonBlocking := true;
        sshShell.Connect;
        if sshShell.Connected then
          begin
            s:='ls -l';
            sshShell.WriteString(s);
            sleep(250);
//            s := sshShell.ReadString;
//            logger.add(s,0);
          end;
      finally
        if sshShell.Connected then
          sshShell.Disconnect;
        if sshClient.Connected then
          sshClient.Disconnect;
        sshShell.Free;
      end;

    except
      on E:Exception do
        begin
          logger.add(format('error - %s',[E.Message]));
        end;

    end;
  finally
    sshClient.Free;
  end;

...
onAsync event will not be raised - for whatever reason.

The application is a command line application.
The instances of TJob will be called in a separate Thread.
That is because the application is trying to access some sshTarget in "parallel".

Maybe there is a stupid failure in that code- but I don't see it.

Best regards
Klaus

Post Reply