Skip to content

Commit 4ba8706

Browse files
committed
Refactor SshChannelStream read logic to handle timeouts and EOF more robustly
1 parent 7092fa5 commit 4ba8706

File tree

1 file changed

+30
-20
lines changed

1 file changed

+30
-20
lines changed

src/NullOpsDevs.LibSsh/Core/SshChannelStream.cs

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,34 +78,44 @@ private int ReadCore(Span<byte> buffer)
7878
// Pin the managed buffer and read directly into it
7979
fixed (byte* bufferPtr = buffer)
8080
{
81-
var bytesRead = LibSshNative.libssh2_channel_read_ex(
82-
_channel,
83-
_streamId,
84-
(sbyte*)bufferPtr,
85-
(nuint)buffer.Length);
86-
87-
if (bytesRead < 0)
81+
while (true)
8882
{
89-
// Check for read timeout explicitly
90-
if (bytesRead == LibSshNative.LIBSSH2_ERROR_TIMEOUT)
83+
var bytesRead = LibSshNative.libssh2_channel_read_ex(
84+
_channel,
85+
_streamId,
86+
(sbyte*)bufferPtr,
87+
(nuint)buffer.Length);
88+
89+
// Success - got data
90+
if (bytesRead > 0)
91+
return (int)bytesRead;
92+
93+
// Clean EOF
94+
if (bytesRead == 0)
9195
{
92-
throw new SshException(
93-
"SSH channel read timed out. Consider calling DisableReadTimeout() or increasing the timeout with SetReadTimeout().",
94-
SshError.Timeout);
96+
_isEof = true;
97+
return 0;
9598
}
9699

97-
// Other errors - treat as EOF for stream purposes
98-
_isEof = true;
99-
return 0;
100-
}
100+
// TIMEOUT in blocking mode - check if channel actually has EOF
101+
if (bytesRead == LibSshNative.LIBSSH2_ERROR_TIMEOUT)
102+
{
103+
// Check if the remote end has signaled EOF
104+
if (LibSshNative.libssh2_channel_eof(_channel) == 1)
105+
{
106+
_isEof = true;
107+
return 0;
108+
}
109+
110+
// No EOF yet - libssh2 is just being dumb, wait and retry
111+
Thread.Sleep(300);
112+
continue;
113+
}
101114

102-
if (bytesRead == 0)
103-
{
115+
// Actual error - treat as EOF
104116
_isEof = true;
105117
return 0;
106118
}
107-
108-
return (int)bytesRead;
109119
}
110120
}
111121

0 commit comments

Comments
 (0)