Page 1 of 1

TScSSHShell: OnAsyncReceive event never raise

Posted: Fri 06 Jan 2012 14:48
by Fontaine
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.

Posted: Thu 12 Jan 2012 15:31
by Dimon
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.

Posted: Fri 20 Jan 2012 13:28
by Klaus01
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