Late receiving of SshChannel.ExtendedDataReceived event

0 votes
asked Aug 17 by Aleksage (220 points)

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);

1 Answer

0 votes
answered Aug 18 by Lukas Matyska (57,170 points)

Unfortunately, this is know limitation of the event approach.

We plan to address this issue in the next update of SSH core (scheduled for next year 2021).

You can workaround the issue by setting:

channel.ExtendedDataMode = SshChannelExtendedDataMode.TreatAsNormalData;

which causes the error data will be part of standard data.

If this is not acceptable solution for you, please let us know and describe what you want to achieve. Maybe, we can think of a different solution.

commented Aug 19 by Aleksage (220 points)
Hello,
Unfortunately, it isn't acceptable for exec request to have mixed stdout and stderr. Separate stdout and stderr is one of the pros of Exec.
Please, let me know if there are some other solutions exept shell manipulations.
commented Aug 19 by Lukas Matyska (57,170 points)
I have sent you an email with link to a hotfix which should solve the issue.
...