| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 | using System;using System.Net.Sockets;using Renci.SshNet.Abstractions;namespace Renci.SshNet{    public partial class Session    {#if FEATURE_SOCKET_POLL        /// <summary>        /// Gets a value indicating whether the socket is connected.        /// </summary>        /// <param name="isConnected"><c>true</c> if the socket is connected; otherwise, <c>false</c></param>        /// <remarks>        /// <para>        /// As a first check we verify whether <see cref="Socket.Connected"/> is        /// <c>true</c>. However, this only returns the state of the socket as of        /// the last I/O operation.        /// </para>        /// <para>        /// Therefore we use the combination of <see cref="Socket.Poll(int, SelectMode)"/> with mode <see cref="SelectMode.SelectRead"/>        /// and <see cref="Socket.Available"/> to verify if the socket is still connected.        /// </para>        /// <para>        /// The MSDN doc mention the following on the return value of <see cref="Socket.Poll(int, SelectMode)"/>        /// with mode <see cref="SelectMode.SelectRead"/>:        /// <list type="bullet">        ///     <item>        ///         <description><c>true</c> if data is available for reading;</description>        ///     </item>        ///     <item>        ///         <description><c>true</c> if the connection has been closed, reset, or terminated; otherwise, returns <c>false</c>.</description>        ///     </item>        /// </list>        /// </para>        /// <para>        /// <c>Conclusion:</c> when the return value is <c>true</c> - but no data is available for reading - then        /// the socket is no longer connected.        /// </para>        /// <para>        /// When a <see cref="Socket"/> is used from multiple threads, there's a race condition        /// between the invocation of <see cref="Socket.Poll(int, SelectMode)"/> and the moment        /// when the value of <see cref="Socket.Available"/> is obtained. To workaround this issue        /// we synchronize reads from the <see cref="Socket"/>.        /// </para>        /// </remarks>#else        /// <summary>        /// Gets a value indicating whether the socket is connected.        /// </summary>        /// <param name="isConnected"><c>true</c> if the socket is connected; otherwise, <c>false</c></param>        /// <remarks>        /// We verify whether <see cref="Socket.Connected"/> is <c>true</c>. However, this only returns the state        /// of the socket as of the last I/O operation.        /// </remarks>#endif        partial void IsSocketConnected(ref bool isConnected)        {            DiagnosticAbstraction.Log(string.Format("[{0}] {1} Checking socket", ToHex(SessionId), DateTime.Now.Ticks));            lock (_socketDisposeLock)            {#if FEATURE_SOCKET_POLL                if (!_socket.IsConnected())                {                    isConnected = false;                    return;                }                lock (_socketReadLock)                {                    var connectionClosedOrDataAvailable = _socket.Poll(0, SelectMode.SelectRead);                    isConnected = !(connectionClosedOrDataAvailable && _socket.Available == 0);                }#else                isConnected = _socket.IsConnected();#endif // FEATURE_SOCKET_POLL            }            DiagnosticAbstraction.Log(string.Format("[{0}] {1} Checked socket", ToHex(SessionId), DateTime.Now.Ticks));        }    }}
 |