Repository navigation
Fix Mono socket read timeouts and retain explicit algorithm selection - #1814
Open
oznetmaster wants to merge 3 commits into
Open
oznetmaster wants to merge 3 commits into
oznetmaster wants to merge 3 commits into
Conversation
… comp atibility- KeyExchange: replace culture-sensitive LINQ equality (==) algorithm negotiation with an explicit ordinal string comparison (SelectAlgorithm helper), since default string equality can behave inconsistently across runtimes/cultures. - SocketAbstraction: Socket.ReceiveTimeout (SO_RCVTIMEO) is not reliably enforced on some Mono-derived runtimes when the TCP handshake completes but the remote peer subsequently stops responding without sending RST/FIN, causing blocking reads to hang indefinitely instead of timing out. Add a Socket.Poll-based deadline wait (PollWithDeadline) which maps directly onto the underlying select()/poll() syscall and reliably unblocks on timeout regardless of platform. Discovered and validated while running this library embedded in a Crestron Home processor driver (Mono-based .NET runtime) for SSH-based device management.
oznetmaster
requested review from
Rob-Hague,
WojciechNagorski and
drieseng
as code owners
July 30, 2026 13:44
The Socket.Poll-based read timeout implementation changes the exception reported when the client socket is closed while a blocking read is in progress: Socket.Poll consistently throws SocketError.Interrupted (regardless of target framework), and on .NET Framework the socket can also be disposed between the Poll and the subsequent Receive call, resulting in an ObjectDisposedException. Update HandleSocks to swallow both of these expected shutdown-related exceptions instead of raising them via the Exception event, restoring the previous behavior where closing a forwarded port with an active SOCKS handshake in progress does not fire spurious exceptions.
Retain upstream removal of unused socket helpers, preserve zero and infinite read timeouts, and keep AsTimeout input validation before polling. Add bounded regressions and describe the reproduced Mono WouldBlock retry behavior. Prepared with OpenAI Codex; Neil Colvin supplied context and authorized the update.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Enforce finite socket-read deadlines on Mono and preserve unlimited timeouts
On Linux Mono 6.8, a silent peer produces SocketException.WouldBlock when a synchronous
receive timeout expires. SSH.NET treats that code as resumable and keeps retrying, so a
150 ms library read remains blocked until an independent watchdog closes the peer.
Using a polling deadline makes this read throw SshOperationTimeoutException instead.
This refresh merges current develop, retaining upstream's deletion of unused ReadPartial
and ClearReadBuffer. It preserves zero and -1 as unlimited waits and existing AsTimeout
validation. Three added regression cases fail on the previous PR and pass after correction.
The explicit client-preference algorithm loops remain. They preserve the inspected
LINQ query's ordinal string equality and preference order; the earlier explanation that
standard string == was culture-sensitive was incorrect. A processor-specific LINQ issue
was the original motivation, but this refresh does not claim to reproduce that issue.
Validation: all five library target frameworks build with no warnings/errors. Focused
Windows unit checks pass 102/102 each on net462, net8.0 and net10.0. Actual Linux Mono
loopback checks reproduce the retry problem and the correction, with external bounds.
No processor DLLs were replaced.
Review limits: the deadline bounds the complete read instead of resetting for each
Receive. A zero-length read differs on Mono, and the DateTime deadline remains subject
to wall-clock adjustment. These deserve explicit review before merge.
The full suite is not green: the PR run before the final input-guard correction had
2397 passed, 2 failed and 26 skipped; unchanged develop had 2267 passed, 132 failed and
26 skipped. Both PR failures also occurred in the baseline. Many baseline failures were
address-in-use errors; this is evidence for comparison, not a claim that all are harmless.
No Docker integration or fresh Crestron processor validation was performed.
AI disclosure: OpenAI Codex performed the source review, local code/test changes and automated validation. Neil Colvin supplied the processor context and authorized this update. This does not claim independent manual code review or processor validation by Neil.
Upstream CI on 9a75dc1: Linux, Windows, Windows .NET integration and Windows .NET Framework integration all passed. Package publishing jobs were skipped for the pull request. CI run.