33using System . Net ;
44using System . Net . Sockets ;
55using System . Threading ;
6+ #if NET6_0_OR_GREATER == false
67using System . Threading . Tasks ;
8+ #endif
79
810using Renci . SshNet . Common ;
911
1012namespace Renci . SshNet . Abstractions
1113{
1214 internal static partial class SocketAbstraction
1315 {
14- public static bool CanRead ( Socket socket )
15- {
16- if ( socket . Connected )
17- {
18- return socket . Poll ( - 1 , SelectMode . SelectRead ) && socket . Available > 0 ;
19- }
20-
21- return false ;
22- }
23-
24- /// <summary>
25- /// Returns a value indicating whether the specified <see cref="Socket"/> can be used
26- /// to send data.
27- /// </summary>
28- /// <param name="socket">The <see cref="Socket"/> to check.</param>
29- /// <returns>
30- /// <see langword="true"/> if <paramref name="socket"/> can be written to; otherwise, <see langword="false"/>.
31- /// </returns>
32- public static bool CanWrite ( Socket socket )
33- {
34- if ( socket != null && socket . Connected )
35- {
36- return socket . Poll ( - 1 , SelectMode . SelectWrite ) ;
37- }
38-
39- return false ;
40- }
41-
42- public static Socket Connect ( IPEndPoint remoteEndpoint , TimeSpan connectTimeout )
43- {
44- var socket = new Socket ( remoteEndpoint . AddressFamily , SocketType . Stream , ProtocolType . Tcp ) { NoDelay = true } ;
45- ConnectCore ( socket , remoteEndpoint , connectTimeout , ownsSocket : true ) ;
46- return socket ;
47- }
48-
4916 public static void Connect ( Socket socket , IPEndPoint remoteEndpoint , TimeSpan connectTimeout )
5017 {
51- ConnectCore ( socket , remoteEndpoint , connectTimeout , ownsSocket : false ) ;
52- }
53-
54- public static async Task ConnectAsync ( Socket socket , IPEndPoint remoteEndpoint , CancellationToken cancellationToken )
55- {
56- await socket . ConnectAsync ( remoteEndpoint , cancellationToken ) . ConfigureAwait ( false ) ;
57- }
58-
59- private static void ConnectCore ( Socket socket , IPEndPoint remoteEndpoint , TimeSpan connectTimeout , bool ownsSocket )
60- {
61- var connectCompleted = new ManualResetEvent ( initialState : false ) ;
62- var args = new SocketAsyncEventArgs
63- {
64- UserToken = connectCompleted ,
65- RemoteEndPoint = remoteEndpoint
66- } ;
67- args . Completed += ConnectCompleted ;
18+ using var connectCompleted = new ManualResetEventSlim ( initialState : false ) ;
19+ using var args = new SocketAsyncEventArgs
20+ {
21+ RemoteEndPoint = remoteEndpoint
22+ } ;
23+ args . Completed += ( _ , _ ) => connectCompleted . Set ( ) ;
6824
6925 if ( socket . ConnectAsync ( args ) )
7026 {
71- if ( ! connectCompleted . WaitOne ( connectTimeout ) )
27+ if ( ! connectCompleted . Wait ( connectTimeout ) )
7228 {
73- // avoid ObjectDisposedException in ConnectCompleted
74- args . Completed -= ConnectCompleted ;
75- if ( ownsSocket )
76- {
77- // dispose Socket
78- socket . Dispose ( ) ;
79- }
80-
81- // dispose ManualResetEvent
82- connectCompleted . Dispose ( ) ;
83-
84- // dispose SocketAsyncEventArgs
85- args . Dispose ( ) ;
29+ socket . Dispose ( ) ;
8630
8731 throw new SshOperationTimeoutException ( string . Format ( CultureInfo . InvariantCulture ,
8832 "Connection failed to establish within {0:F0} milliseconds." ,
8933 connectTimeout . TotalMilliseconds ) ) ;
9034 }
9135 }
9236
93- // dispose ManualResetEvent
94- connectCompleted . Dispose ( ) ;
95-
9637 if ( args . SocketError != SocketError . Success )
9738 {
9839 var socketError = ( int ) args . SocketError ;
9940
100- if ( ownsSocket )
101- {
102- // dispose Socket
103- socket . Dispose ( ) ;
104- }
105-
106- // dispose SocketAsyncEventArgs
107- args . Dispose ( ) ;
108-
10941 throw new SocketException ( socketError ) ;
11042 }
111-
112- // dispose SocketAsyncEventArgs
113- args . Dispose ( ) ;
114- }
115-
116- public static void ClearReadBuffer ( Socket socket )
117- {
118- var timeout = TimeSpan . FromMilliseconds ( 500 ) ;
119- var buffer = new byte [ 256 ] ;
120- int bytesReceived ;
121-
122- do
123- {
124- bytesReceived = ReadPartial ( socket , buffer , 0 , buffer . Length , timeout ) ;
125- }
126- while ( bytesReceived > 0 ) ;
127- }
128-
129- public static int ReadPartial ( Socket socket , byte [ ] buffer , int offset , int size , TimeSpan timeout )
130- {
131- socket . ReceiveTimeout = timeout . AsTimeout ( nameof ( timeout ) ) ;
132-
133- try
134- {
135- return socket . Receive ( buffer , offset , size , SocketFlags . None ) ;
136- }
137- catch ( SocketException ex )
138- {
139- if ( ex . SocketErrorCode == SocketError . TimedOut )
140- {
141- throw new SshOperationTimeoutException ( string . Format ( CultureInfo . InvariantCulture ,
142- "Socket read operation has timed out after {0:F0} milliseconds." ,
143- timeout . TotalMilliseconds ) ) ;
144- }
145-
146- throw ;
147- }
14843 }
14944
15045 public static void ReadContinuous ( Socket socket , byte [ ] buffer , int offset , int size , Action < byte [ ] , int , int > processReceivedBytesAction )
@@ -206,41 +101,6 @@ public static int ReadByte(Socket socket, TimeSpan timeout)
206101 return buffer [ 0 ] ;
207102 }
208103
209- /// <summary>
210- /// Sends a byte using the specified <see cref="Socket"/>.
211- /// </summary>
212- /// <param name="socket">The <see cref="Socket"/> to write to.</param>
213- /// <param name="value">The value to send.</param>
214- /// <exception cref="SocketException">The write failed.</exception>
215- public static void SendByte ( Socket socket , byte value )
216- {
217- var buffer = new [ ] { value } ;
218- _ = socket . Send ( buffer ) ;
219- }
220-
221- /// <summary>
222- /// Receives data from a bound <see cref="Socket"/>.
223- /// </summary>
224- /// <param name="socket">The <see cref="Socket"/> to read from.</param>
225- /// <param name="size">The number of bytes to receive.</param>
226- /// <param name="timeout">Specifies the amount of time after which the call will time out.</param>
227- /// <returns>
228- /// The bytes received.
229- /// </returns>
230- /// <remarks>
231- /// If no data is available for reading, the <see cref="Read(Socket, int, TimeSpan)"/> method will
232- /// block until data is available or the time-out value is exceeded. If the time-out value is exceeded, the
233- /// <see cref="Read(Socket, int, TimeSpan)"/> call will throw a <see cref="SshOperationTimeoutException"/>.
234- /// If you are in non-blocking mode, and there is no data available in the in the protocol stack buffer, the
235- /// <see cref="Read(Socket, int, TimeSpan)"/> method will complete immediately and throw a <see cref="SocketException"/>.
236- /// </remarks>
237- public static byte [ ] Read ( Socket socket , int size , TimeSpan timeout )
238- {
239- var buffer = new byte [ size ] ;
240- _ = Read ( socket , buffer , 0 , size , timeout ) ;
241- return buffer ;
242- }
243-
244104 /// <summary>
245105 /// Receives data from a bound <see cref="Socket"/> into a receive buffer.
246106 /// </summary>
@@ -258,10 +118,6 @@ public static byte[] Read(Socket socket, int size, TimeSpan timeout)
258118 /// block until data is available or the time-out value is exceeded. If the time-out value is exceeded, the
259119 /// <see cref="Read(Socket, byte[], int, int, TimeSpan)"/> call will throw a <see cref="SshOperationTimeoutException"/>.
260120 /// </para>
261- /// <para>
262- /// If you are in non-blocking mode, and there is no data available in the in the protocol stack buffer, the
263- /// <see cref="Read(Socket, byte[], int, int, TimeSpan)"/> method will complete immediately and throw a <see cref="SocketException"/>.
264- /// </para>
265121 /// </remarks>
266122 public static int Read ( Socket socket , byte [ ] buffer , int offset , int size , TimeSpan readTimeout )
267123 {
@@ -301,10 +157,5 @@ public static ValueTask<int> ReadAsync(Socket socket, byte[] buffer, Cancellatio
301157 return socket . ReceiveAsync ( new ArraySegment < byte > ( buffer , 0 , buffer . Length ) , SocketFlags . None , cancellationToken ) ;
302158 }
303159#endif
304- private static void ConnectCompleted ( object sender , SocketAsyncEventArgs e )
305- {
306- var eventWaitHandle = ( ManualResetEvent ) e . UserToken ;
307- _ = eventWaitHandle ? . Set ( ) ;
308- }
309160 }
310161}
0 commit comments