private async Task<Socket> ConnectSocketAsync(string host, int port, CancellationToken cancellationToken)
{
IPAddress[] addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
ExceptionDispatchInfo lastException = null;
foreach (IPAddress address in addresses)
{
var socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
using (cancellationToken.Register(s => ((Socket)s).Dispose(), socket))
using (_abortSource.Token.Register(s => ((Socket)s).Dispose(), socket))
{
try
{
await socket.ConnectAsync(address, port).ConfigureAwait(false);
}
catch (ObjectDisposedException ode)
{
// If the socket was disposed because cancellation was requested, translate the exception
// into a new OperationCanceledException. Otherwise, let the original ObjectDisposedexception propagate.
CancellationToken token = cancellationToken.IsCancellationRequested ? cancellationToken : _abortSource.Token;
if (token.IsCancellationRequested)
{
throw new OperationCanceledException(new OperationCanceledException().Message, ode, token);
}
}
}
cancellationToken.ThrowIfCancellationRequested(); // in case of a race and socket was disposed after the await
_abortSource.Token.ThrowIfCancellationRequested();
return socket;
}
catch (Exception exc)
{
socket.Dispose();
lastException = ExceptionDispatchInfo.Capture(exc);
}
}
lastException?.Throw();
Debug.Fail("We should never get here. We should have already returned or an exception should have been thrown.");
throw new WebSocketException(SR.net_webstatus_ConnectFailure);
}