@@ -31,6 +31,8 @@ namespace MongoDB.Driver.Core.Connections
3131 /// </summary>
3232 internal sealed class TcpStreamFactory : IStreamFactory
3333 {
34+ private static readonly byte [ ] __ensureConnectedBuffer = new byte [ 1 ] ;
35+
3436 // fields
3537 private readonly TcpStreamSettings _settings ;
3638
@@ -165,10 +167,18 @@ private void ConfigureConnectedSocket(Socket socket)
165167
166168 private void Connect ( Socket socket , EndPoint endPoint , CancellationToken cancellationToken )
167169 {
168- var isSocketDisposed = false ;
170+ var callbackState = new ConnectOperationState ( socket ) ;
169171 using var timeoutCancellationTokenSource = new CancellationTokenSource ( _settings . ConnectTimeout ) ;
170172 using var combinedCancellationTokenSource = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken , timeoutCancellationTokenSource . Token ) ;
171- using var cancellationSubscription = combinedCancellationTokenSource . Token . Register ( DisposeSocket ) ;
173+ using var cancellationSubscription = combinedCancellationTokenSource . Token . Register ( state =>
174+ {
175+ var operationState = ( ConnectOperationState ) state ;
176+ if ( operationState . IsSucceeded )
177+ {
178+ return ;
179+ }
180+ DisposeSocket ( operationState . Socket ) ;
181+ } , callbackState ) ;
172182
173183 try
174184 {
@@ -185,13 +195,12 @@ private void Connect(Socket socket, EndPoint endPoint, CancellationToken cancell
185195#else
186196 socket . Connect ( endPoint ) ;
187197#endif
198+ EnsureConnected ( socket ) ;
199+ callbackState . IsSucceeded = true ;
188200 }
189201 catch
190202 {
191- if ( ! isSocketDisposed )
192- {
193- DisposeSocket ( ) ;
194- }
203+ DisposeSocket ( socket ) ;
195204
196205 cancellationToken . ThrowIfCancellationRequested ( ) ;
197206 if ( timeoutCancellationTokenSource . IsCancellationRequested )
@@ -202,9 +211,8 @@ private void Connect(Socket socket, EndPoint endPoint, CancellationToken cancell
202211 throw ;
203212 }
204213
205- void DisposeSocket ( )
214+ static void DisposeSocket ( Socket socket )
206215 {
207- isSocketDisposed = true ;
208216 try
209217 {
210218 socket . Dispose ( ) ;
@@ -214,6 +222,23 @@ void DisposeSocket()
214222 // Ignore any exceptions.
215223 }
216224 }
225+
226+ static void EnsureConnected ( Socket socket )
227+ {
228+ bool originalBlockingState = socket . Blocking ;
229+ socket . Blocking = false ;
230+
231+ try
232+ {
233+ // Try to use the socket to ensure it's connected. On MacOS with net6.0 sometimes Connect is completed successfully even after the socket disposal.
234+ socket . Send ( __ensureConnectedBuffer , 0 , 0 ) ;
235+ }
236+ finally
237+ {
238+ // Restore original blocking state
239+ socket . Blocking = originalBlockingState ;
240+ }
241+ }
217242 }
218243
219244 private async Task ConnectAsync ( Socket socket , EndPoint endPoint , CancellationToken cancellationToken )
@@ -376,5 +401,10 @@ public int Compare(EndPoint x, EndPoint y)
376401 return 0 ;
377402 }
378403 }
404+
405+ private sealed record ConnectOperationState ( Socket Socket )
406+ {
407+ public bool IsSucceeded { get ; set ; }
408+ }
379409 }
380410}
0 commit comments