Hello,
I use SshChannel.RequestExec for command execution and I have a question regarding the ExtendedDataReceived event synchronization.
Is there any way to ensure that stdErr is empty?
In the example below we synchronized 'ExtendedDataReceived' and 'return' via extDataLock, but, in my opinion, it is possible that return part will capture the lock first.
Task<(String StdOut, String StdErr, long ExitCode)>.Run(() =>
{
...
// Get channel
channel = _sshClient.Session.OpenSession();
channel.ExtendedDataReceived += new EventHandler<SshExtendedDataReceivedEventArgs>((object sender, SshExtendedDataReceivedEventArgs e) =>
{
lock(extDataLock)
{
byte[] data = e.GetData();
String resp = _sshClient.Encoding.GetString(data, 0, data.Length);
stdErr.Append(resp);
}
});
// Send command
channel.RequestExec(Command);
...
// Read responce
byte[] buffer = new byte[4096];
while (true)
{
if (!channel.Poll(some_timeout, SocketSelectMode.SelectRead))
break;
int n = channel.Receive(buffer, 0, buffer.Length);
if (n <= 0)
break;
stdOut.Append(_sshClient.Encoding.GetString(buffer, 0, n));
if (_tokenSource.Token.IsCancellationRequested)
break;
}
...
// Close channel and get ExitCode
if (channel != null)
{
channel.Close();
SshChannelExitStatus exitStatus = channel.ExitStatus;
if (exitStatus != null)
exitCode = (int)exitStatus.ExitCode;
channel.Dispose();
}
...
// Collect results and return
// ISSUE: Empty StdErr because of late event ExtendedDataReceived
lock(extDataLock)
{
return (StdOut: stdOut.ToString(), StdErr: stdErr.ToString(), ExitCode: exitCode);
}
}, _tokenSource.Token);