private IAsyncResult BeginConnectEx(EndPoint remoteEP, bool flowContext, AsyncCallback callback, object state)
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(this);
// This will check the permissions for connect.
EndPoint endPointSnapshot = remoteEP;
Internals.SocketAddress socketAddress = flowContext ? CheckCacheRemote(ref endPointSnapshot, true) : SnapshotAndSerialize(ref endPointSnapshot);
// The socket must be bound first.
// The calling method--BeginConnect--will ensure that this method is only
// called if _rightEndPoint is not null, of that the endpoint is an IPEndPoint.
if (_rightEndPoint == null)
{
if (endPointSnapshot.AddressFamily == AddressFamily.InterNetwork)
{
InternalBind(new IPEndPoint(IPAddress.Any, 0));
}
else if (endPointSnapshot.AddressFamily != AddressFamily.Unix)
{
InternalBind(new IPEndPoint(IPAddress.IPv6Any, 0));
}
}
// Allocate the async result and the event we'll pass to the thread pool.
ConnectOverlappedAsyncResult asyncResult = new ConnectOverlappedAsyncResult(this, endPointSnapshot, state, callback);
// If context flowing is enabled, set it up here. No need to lock since the context isn't used until the callback.
if (flowContext)
{
asyncResult.StartPostingAsyncOp(false);
}
EndPoint oldEndPoint = _rightEndPoint;
if (_rightEndPoint == null)
{
_rightEndPoint = endPointSnapshot;
}
SocketError errorCode;
try
{
errorCode = SocketPal.ConnectAsync(this, _handle, socketAddress.Buffer, socketAddress.Size, asyncResult);
}
catch
{
// If ConnectEx throws we need to unpin the socketAddress buffer.
// _rightEndPoint will always equal oldEndPoint.
asyncResult.InternalCleanup();
_rightEndPoint = oldEndPoint;
throw;
}
if (errorCode == SocketError.Success)
{
SetToConnected();
}
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Interop.Winsock.connect returns:{errorCode}");
errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
// Throw an appropriate SocketException if the native call fails synchronously.
if (errorCode != SocketError.Success)
{
// Update the internal state of this socket according to the error before throwing.
_rightEndPoint = oldEndPoint;
SocketException socketException = new SocketException((int)errorCode);
UpdateStatusAfterSocketError(socketException);
if (NetEventSource.IsEnabled) NetEventSource.Error(this, socketException);
throw socketException;
}
// We didn't throw, so indicate that we're returning this result to the user. This may call the callback.
// This is a nop if the context isn't being flowed.
asyncResult.FinishPostingAsyncOp(ref Caches.ConnectClosureCache);
if (NetEventSource.IsEnabled)
{
NetEventSource.Info(this, $"{endPointSnapshot} returning AsyncResult:{asyncResult}");
NetEventSource.Exit(this, asyncResult);
}
return asyncResult;
}