Skip to content

Commit 347d289

Browse files
Fix hung dispose caused by infinite socket timeout
Co-authored-by: Rob Hague <rob.hague00@gmail.com>
1 parent b0d01df commit 347d289

File tree

1 file changed

+19
-1
lines changed

1 file changed

+19
-1
lines changed

src/Renci.SshNet/Session.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1788,22 +1788,40 @@ internal static string ToHex(byte[] bytes)
17881788
/// when the value of <see cref="Socket.Available"/> is obtained. To workaround this issue
17891789
/// we synchronize reads from the <see cref="Socket"/>.
17901790
/// </para>
1791+
/// <para>
1792+
/// We assume the socket is still connected if the read lock cannot be acquired immediately.
1793+
/// In this case, we just return <see langword="true"/> without actually waiting to acquire
1794+
/// the lock. We don't want to wait for the read lock if another thread already has it because
1795+
/// there are cases where the other thread holding the lock can be waiting indefinitely for
1796+
/// a socket read operation to complete.
1797+
/// </para>
17911798
/// </remarks>
17921799
private bool IsSocketConnected()
17931800
{
1801+
#pragma warning disable S2222 // Locks should be released on all paths
17941802
lock (_socketDisposeLock)
17951803
{
17961804
if (!_socket.IsConnected())
17971805
{
17981806
return false;
17991807
}
18001808

1801-
lock (_socketReadLock)
1809+
if (!Monitor.TryEnter(_socketReadLock))
1810+
{
1811+
return true;
1812+
}
1813+
1814+
try
18021815
{
18031816
var connectionClosedOrDataAvailable = _socket.Poll(0, SelectMode.SelectRead);
18041817
return !(connectionClosedOrDataAvailable && _socket.Available == 0);
18051818
}
1819+
finally
1820+
{
1821+
Monitor.Exit(_socketReadLock);
1822+
}
18061823
}
1824+
#pragma warning restore S2222 // Locks should be released on all paths
18071825
}
18081826

18091827
/// <summary>

0 commit comments

Comments
 (0)