EldoS | Feel safer!

Software components for data protection, secure storage and transfer

SimpleSSHClient.ReceiveData halts when CmdSSHTunnel is feeded manually

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.
#24091
Posted: 03/14/2013 06:04:12
by Xichen Li (Basic support level)
Joined: 03/13/2013
Posts: 3

Dear SecureBlackBox support,

Thank you very much for your time!

As attached below, I have a helper class for the TElSimpleSSHClient to mimic the "ExecuteCommand" without the need of initializing and destroying the SSH connection/handshakes everytime. That is to say, one can just call TElSimpleSSHClient.Open and then multiple times of TElSimpleSSHClient.IssueCommand. The reason is for some cluster, every SSH connection/handshake involves a cumbersome one-time-short-message.

However, the IssueCommand procedure halts at the "ReceiveData" line for about 1 minute. I have no idea of what is happening behind the scene. Could you help to comment?

Best wishes,
Xichen Li

Code
unit uHelper;

interface

uses
  SBSSHClient, SBSSHCommon, SBSimpleSSH, Windows, SysUtils;

type

  TElSimpleSSHClientHelper = class helper for TElSimpleSSHClient
  public
    procedure IssueCommand(const Cmd: RawByteString);
  end;

implementation

procedure TElSimpleSSHClientHelper.IssueCommand(const Cmd: RawByteString);
var
  OldTunnelConnection: TElSSHTunnelConnection;
  NewCmdTunnel: TElCommandSSHTunnel;
  vTick1, vTick2, vFrequency, TimeInSeconds: Int64;
  CanReceiveData: Boolean;
  Buf, ErrBuf: TBytes;
  BufSize, ErrBufSize: Integer;
begin
  // FConnection is also involved in OnTunnelOpen/OnTunnelClose
  OldTunnelConnection := Self.FConnection;

  NewCmdTunnel := TElCommandSSHTunnel.Create(nil);
  with NewCmdTunnel do
  begin
    Commands.Add(Cmd);
    Environment.Assign(Self.FEnvironment);
    TerminalInfo := Self.FTerminalInfo;
    RequestTerminal := Self.FRequestTerminal;
    TunnelList := Self.FTunnelList;
    OnOpen := Self.OnTunnelOpen;
    OnClose := Self.OnTunnelClose;
  end;
  NewCmdTunnel.Open;

  QueryPerformanceCounter(vTick1);
  while True do
  begin
    QueryPerformanceFrequency(vFrequency);
    QueryPerformanceCounter(vTick2);
    TimeInSeconds := Round((vTick2 - vTick1) * 1.0 / vFrequency * 1.0);

    // 60 seconds
    if TimeInSeconds > 60 then
      Break;

    if Active then
      CanReceiveData := True
    else
      // 0.5 second
      CanReceiveData := CanReceive(500);

    if CanReceiveData then
    begin
      BufSize := 65536;
      ErrBufSize := 65536;
      SetLength(Buf, BufSize); SetLength(ErrBuf, ErrBufSize);
      // Even if the command output is not needed,
      // it seems ReceiveData has to be called to wait,
      // otherwise the command will not be executed...
      Self.ReceiveData(@Buf[0], BufSize, @ErrBuf[0], ErrBufSize);
    end;

    if Active then
      // 0.1 second
      Sleep(100)
    else
      Break;
  end;

  NewCmdTunnel.Free;
  Self.FConnection := OldTunnelConnection;
end;

end.
#24093
Posted: 03/14/2013 06:13:14
by Vsevolod Ievgiienko (EldoS Corp.)

Thank you for contacting us.

Please refer to the sample from \EldoS\SecureBlackbox.VCL\Samples\Delphi\SSHBlackbox\Client\SimpleSSH folder for the correct data receiving loop.
#24094
Posted: 03/14/2013 06:20:03
by Xichen Li (Basic support level)
Joined: 03/13/2013
Posts: 3

Dear Vsevolod,

Thank you for your kind help.

In fact, the data receiving loop comes from the SimpleSSH sample. I have only changed the "string" buffer to "TBytes", and added "timing" statements. The reason for unexpected halting at "ReceiveData" must come from some activities of the new TELCommandSSHTunnel behind the scene. Could you help to comment?

Best wishes,
Xichen Li
#24095
Posted: 03/14/2013 06:24:52
by Vsevolod Ievgiienko (EldoS Corp.)

Try to modify the code this way:

Code
...
if not Active then
  CanReceiveData := False
else
  // 0.5 second
  CanReceiveData := CanReceive(500);

if CanReceiveData then
begin
...
#24097
Posted: 03/14/2013 06:42:39
by Xichen Li (Basic support level)
Joined: 03/13/2013
Posts: 3

Dear Vsevolod,

Thank you for your knowledgeable comment! That is the cause! The class helper version and inheritance version of the working "IssueCommand" are attached for reference purpose.

Best wishes,
Xichen Li

class helper version

Code
unit uHelper;

interface

uses
  SBSSHClient, SBSSHCommon, SBSimpleSSH, Windows, SysUtils;

type

  TElSimpleSSHClientHelper = class helper for TElSimpleSSHClient
  public
    procedure IssueCommand(const Cmd: string);
  end;

implementation

procedure TElSimpleSSHClientHelper.IssueCommand(const Cmd: string);
var
  OldTunnelConnection: TElSSHTunnelConnection;
  NewCmdTunnel: TElCommandSSHTunnel;
  vTick1, vTick2, vFrequency, TimeInSeconds: Int64;
  CanReceiveData: Boolean;
  Buf, ErrBuf: TBytes;
  BufSize, ErrBufSize: Integer;
begin
  // FConnection is also involved in OnTunnelOpen/OnTunnelClose
  OldTunnelConnection := Self.FConnection;

  NewCmdTunnel := TElCommandSSHTunnel.Create(nil);
  with NewCmdTunnel do
  begin
    Commands.Add(Cmd);
    Environment.Assign(Self.FEnvironment);
    TerminalInfo := Self.FTerminalInfo;
    RequestTerminal := Self.FRequestTerminal;
    TunnelList := Self.FTunnelList;
    OnOpen := Self.OnTunnelOpen;
    OnClose := Self.OnTunnelClose;
  end;
  NewCmdTunnel.Open;

  QueryPerformanceCounter(vTick1);
  while True do
  begin
    QueryPerformanceFrequency(vFrequency);
    QueryPerformanceCounter(vTick2);
    TimeInSeconds := Round((vTick2 - vTick1) * 1.0 / vFrequency * 1.0);

    // 60 seconds
    if TimeInSeconds > 60 then
      Break;

    if not Active then
      CanReceiveData := False
    else
      // 0.5 second
      CanReceiveData := CanReceive(500);

    if CanReceiveData then
    begin
      BufSize := 65536;
      ErrBufSize := 65536;
      SetLength(Buf, BufSize); SetLength(ErrBuf, ErrBufSize);
      // Even if the command output is not needed,
      // it seems ReceiveData has to be called to wait,
      // otherwise the command will not be executed...
      Self.ReceiveData(@Buf[0], BufSize, @ErrBuf[0], ErrBufSize);
    end;

    if Active then
      // 0.1 second
      Sleep(100)
    else
      Break;
  end;

  NewCmdTunnel.Free;
  Self.FConnection := OldTunnelConnection;
end;

end.


inheritance version

Code
unit uChild;

interface

uses
  SBSSHClient, SBSSHCommon, SBSimpleSSH, Windows, SysUtils;

type

  TMySimpleSSHClient = class(TElSimpleSSHClient)
  public
    procedure IssueCommand(const Cmd: string);
  end;

implementation

procedure TMySimpleSSHClient.IssueCommand(const Cmd: string);
var
  OldTunnelConnection: TElSSHTunnelConnection;
  NewCmdTunnel: TElCommandSSHTunnel;
  vTick1, vTick2, vFrequency, TimeInSeconds: Int64;
  CanReceiveData: Boolean;
  Buf, ErrBuf: TBytes;
  BufSize, ErrBufSize: Integer;
begin
  // FConnection is also involved in OnTunnelOpen/OnTunnelClose
  OldTunnelConnection := Self.FConnection;

  NewCmdTunnel := TElCommandSSHTunnel.Create(nil);
  with NewCmdTunnel do
  begin
    Commands.Add(Cmd);
    Environment.Assign(Self.FEnvironment);
    TerminalInfo := Self.FTerminalInfo;
    RequestTerminal := Self.FRequestTerminal;
    TunnelList := Self.FTunnelList;
    OnOpen := Self.OnTunnelOpen;
    OnClose := Self.OnTunnelClose;
  end;
  NewCmdTunnel.Open;

  QueryPerformanceCounter(vTick1);
  while True do
  begin
    QueryPerformanceFrequency(vFrequency);
    QueryPerformanceCounter(vTick2);
    TimeInSeconds := Round((vTick2 - vTick1) * 1.0 / vFrequency * 1.0);

    // 60 seconds
    if TimeInSeconds > 60 then
      Break;

    if not Active then
      CanReceiveData := False
    else
      // 0.5 second
      CanReceiveData := CanReceive(500);

    if CanReceiveData then
    begin
      BufSize := 65536;
      ErrBufSize := 65536;
      SetLength(Buf, BufSize); SetLength(ErrBuf, ErrBufSize);
      // Even if the command output is not needed,
      // it seems ReceiveData has to be called to wait,
      // otherwise the command will not be executed...
      Self.ReceiveData(@Buf[0], BufSize, @ErrBuf[0], ErrBufSize);
    end;

    if Active then
      // 0.1 second
      Sleep(100)
    else
      Break;
  end;

  NewCmdTunnel.Free;
  Self.FConnection := OldTunnelConnection;
end;

end.
Also by EldoS: CallbackRegistry
A component to monitor and control Windows registry access and create virtual registry keys.

Reply

Statistics

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