TScSSHShell.ExecuteCommand - Sleep(50)

Discussion of open issues, suggestions and bugs regarding network security and data protection solution - SecureBridge
Post Reply
DanielT
Posts: 3
Joined: Thu 08 Feb 2018 14:36

TScSSHShell.ExecuteCommand - Sleep(50)

Post by DanielT » Thu 08 Feb 2018 14:51

Hi,

we are using the SecureBridge Components TScSSHClient and TScSSHShell to communicate over SSH.

I was wondering about a call to 'Sleep(50)' in method TScSSHShell.ExecuteCommand, while reading the stream until it has become closed. Doing so turns out to be actually quite slow. I tried to reduce the waited time and ended up removing the call completely. The communication still worked as expected, but about 10 times faster (but I tested it in our LAN only yet to be honest).

Could you explain where this sleep(50) originates from or why it is required?

Thanks and best regards,
Daniel

ViktorV
Devart Team
Posts: 3168
Joined: Wed 30 Jul 2014 07:16

Re: TScSSHShell.ExecuteCommand - Sleep(50)

Post by ViktorV » Fri 09 Feb 2018 13:54

Since often the shell slowly returns the result, our numerous studies have shown that to correctly retrieve the entire result, you should execute the specified sleep(50). If you have SecureBridge source code, you can delete this sleep.

DanielT
Posts: 3
Joined: Thu 08 Feb 2018 14:36

Re: TScSSHShell.ExecuteCommand - Sleep(50)

Post by DanielT » Fri 09 Feb 2018 22:48

Hi,

thank you very much for the swift response.

Yes, we have the SecureBridge source code and tried to delete this sleep. That's where curiosity had us.

What we wonder is:
  • The data from the stream is read until the stream has become closed. As SSH (if not for mesh) works on TCP, we would consider the stream to be reliable and should thus not be closed before the TCP connection signals all data to be transferred.
  • If it's actually to wait for 'something it does not yet know how long it will take', then why using 50ms? And what could that be? A single command could easily take longer than 50ms to return anything, as well as network latency.
  • If it's just meant to reduce the load on the thread, we really would consider to reduce or remove this delay, at least for high performance/local connections, where latency <<50ms is not uncommon.
Please feel free to correct/support where I'm wrong/right ;-)
I would also be very grateful if you could share an example (like a part of one of your studies, a specific command to execute or a description of an environment to execute a command in or such), to enlighten the cause for this delay.

Best regards,
Daniel

Btw: Should you need any customer data to check whether we are eligible for support, please let me know (I would try to make contact via the customer portal then).

ViktorV
Devart Team
Posts: 3168
Joined: Wed 30 Jul 2014 07:16

Re: TScSSHShell.ExecuteCommand - Sleep(50)

Post by ViktorV » Mon 12 Feb 2018 12:26

In general, your comments are correct. The delay discussed was introduced to improve performance when working with slow SSH servers in a slow network. We will investigate this behavior and try to optimize it taking into account the actual data.

mdbs99
Posts: 3
Joined: Mon 14 Jan 2019 19:30

Re: TScSSHShell.ExecuteCommand - Sleep(50)

Post by mdbs99 » Mon 14 Jan 2019 19:50

I have the same issue here.
Actually, I haven't understood why `ExecuteCommand` needs to close connection first, calling `SetConnected(False)`. That turns things much more slow...

If I use `NonBlocking+OnAsyncReceive`, I can receive all data. However, I don't know when it will finish and that is a problem to me: how to know if I can release my thread?

I would like to know if it is possible:
1. do not call sleep
2. do not call `SetConnected` on `ExecuteCommand`

Finally, why `ExecuteCommand` is so different then `NonBlocking+OnAsyncReceive`? For example: if I use `ExecuteCommand` and type `ls`, I can see the results - the same for NonBlocking. However, if I type `cd ..` I just see data in NonBlocking mode.

best regards
Marcos Douglas

DanielT
Posts: 3
Joined: Thu 08 Feb 2018 14:36

Re: TScSSHShell.ExecuteCommand - Sleep(50)

Post by DanielT » Mon 14 Jan 2019 20:59

Hello Marcos,

> Actually, I haven't understood why `ExecuteCommand` needs to close connection first, calling `SetConnected(False)`.
and
> Finally, why `ExecuteCommand` is so different then `NonBlocking+OnAsyncReceive`?

That's due to the specification of the SSH protocol. See https://www.ietf.org/rfc/rfc4254.txt Chapter 6.5 (Starting a Shell or Command). The 'exec' message is specified to run a command and return all results till the command terminates (in some way), closing the connection. This is used in ExecuteCommand.

ExecuteCommand has the advantage that you don't have to deal with the shell and have a real indicator on the termination. On the downside, the specification requires a separate connection to do so, resulting in quite some overhead if you want to execute many commands.

> However, if I type `cd ..` I just see data in NonBlocking mode.

'CD ..' has no output on its own, it just changes the current directory of the current shell. Using ExecuteCommand acts similar to running each single command in its own shell. As such 'ExecuteCommand('cd..')' won't do anything ...

The 'NonBlocking' approach opens a shell (the 'shell' message in the specification), which keeps track of its state (like the current directory). As such, it can handle more than just one command and would also return some data.
It has the disadvantage, that it only transfers text. As such, you would have to think of a method to determine the termination of a single command on your own.

ViktorV
Devart Team
Posts: 3168
Joined: Wed 30 Jul 2014 07:16

Re: TScSSHShell.ExecuteCommand - Sleep(50)

Post by ViktorV » Tue 15 Jan 2019 09:51

DanielT comments are correct.
The shell channel particularity is that after command executing, using the TScSSHShell.ExecuteCommand method, the channel will be closed by the server after receiving a command execution result, regardless of a value of the TScSSHShell.NonBlocking property and a client cannot affect it.
You can connect to the server and send commands to the server using the TScSSHShell.WriteString or TScSSHShell.WriteBuffer methods, after their execution the channel is not closed: https://www.devart.com/sbridge/docs/tsc ... string.htm, https://www.devart.com/sbridge/docs/tsc ... buffer.htm

mdbs99
Posts: 3
Joined: Mon 14 Jan 2019 19:30

Re: TScSSHShell.ExecuteCommand - Sleep(50)

Post by mdbs99 » Tue 15 Jan 2019 12:03

Hi @DanielT
That's due to the specification of the SSH protocol. See https://www.ietf.org/rfc/rfc4254.txt Chapter 6.5 (Starting a Shell or Command). The 'exec' message is specified to run a command and return all results till the command terminates (in some way), closing the connection. This is used in ExecuteCommand.
Maybe I didn't understand. The RFC says: "The program can be a shell, an application program, or a subsystem with a host-independent name".
So, shell, program or subsystem. `ExecuteCommand` is using 'program' in that case, right?
At the end of RFC says: "The server SHOULD NOT halt the execution of the protocol stack when starting a shell or a program. All input and output from these SHOULD be redirected to the channel or to the encrypted tunnel."
In my understanding is the opposite, ie, the client should not close the connection in 'shell' or 'program' mode.
ExecuteCommand has the advantage that you don't have to deal with the shell and have a real indicator on the termination.
Yes, this is want I need.
On the downside, the specification requires a separate connection to do so, resulting in quite some overhead if you want to execute many commands.
Separate connection or not was encapsulated into the component - we might not think about it.
The overhead is because 'sleep()' calls and closing connection...
'CD ..' has no output on its own, it just changes the current directory of the current shell.
I know that. However, I would like to show for users what is happening. If you try 'NonBlocking' , you will see that 'cd ..' brings data on 'OnAsyncReceive'. IMHO, both should have the same behavior... but this is not the main issue.

--

Hi @ViktorV
The shell channel particularity is that after command executing, using the TScSSHShell.ExecuteCommand method, the channel will be closed by the server after receiving a command execution result, regardless of a value of the TScSSHShell.NonBlocking property and a client cannot affect it.
I understood the behavior by design. However, I haven't understood why might be like that. What the advantages closing connection first?
Нou can connect to the server and send commands to the server using the TScSSHShell.WriteString or TScSSHShell.WriteBuffer methods, after their execution the channel is not closed:
Yes. The problem is that I don't know when all data has finished. That's why I would like to use `ExecuteCommand`, which uses 'ReadAllData' protected method - not public, not available.

The 'sleep()' calls I can just remove, replace by events (callbacks) or just decrease the number. But I would like to understand the disadvantages, if I remove `SetConnected(False)` and related code.

Thanks.

ViktorV
Devart Team
Posts: 3168
Joined: Wed 30 Jul 2014 07:16

Re: TScSSHShell.ExecuteCommand - Sleep(50)

Post by ViktorV » Thu 17 Jan 2019 11:43

When calling the TScSSHShell.ExecuteCommand method, the 'exec' request type is sent, which, according to the RFC, starts the execution of the given command only. This type of the request does not imply the execution of other commands, so after executing the command and sending the entire result to the client, the server closes the channel, which is fully consistent with the documentation. This behavior is typical for all known SSH servers and we cannot influence this.
Yes. The problem is that I don't know when all data has finished. That's why I would like to use `ExecuteCommand`, which uses 'ReadAllData' protected method - not public, not available.
We noted earlier that the SSH protocol allows using only 2 request types for your task - 'shell' or 'exec'. Each of these requests has its pros and cons. Therefore, you should choose a more optimal path for you. Once again, we advise you to pay attention to the 'shell' request and abandon the 'exec'. The 'shell' request is executed when calling the TScSSHShell.Connect method and commands are sent using the TScSSHShell.WriteString or TScSSHShell.WriteBuffer methods.

mdbs99
Posts: 3
Joined: Mon 14 Jan 2019 19:30

Re: TScSSHShell.ExecuteCommand - Sleep(50)

Post by mdbs99 » Thu 17 Jan 2019 13:18

@ViktorV

I'm already using `shell`, which has the best performance. However, how the app can know when the stream is done?
For example: imagine that we need to save each command typed into a row on a grid. Each row should have the server, command, and output. As the output (could) come on pieces, the program might include more than one row for the same command.

In your opinion, which would be the best approach to know the end of the stream? It shouldn't be hard-coded, though.

ViktorV
Devart Team
Posts: 3168
Joined: Wed 30 Jul 2014 07:16

Re: TScSSHShell.ExecuteCommand - Sleep(50)

Post by ViktorV » Fri 18 Jan 2019 10:45

We cannot give you any advice because the SSH protocol does not send the size of the data resulting from the end of the operation. Also, the shell does not return any standardized characters that define the end of the result.

Post Reply