public async Task ConnectAsync(Address address, ConnectionFactory factory)
{
IPAddress[] ipAddresses;
IPAddress ip;
if (IPAddress.TryParse(address.Host, out ip))
{
ipAddresses = new IPAddress[] { ip };
}
else
{
ipAddresses = await TaskExtensions.GetHostAddressesAsync(address.Host);
}
// need to handle both IPv4 and IPv6
Socket socket = null;
Exception exception = null;
for (int i = 0; i < ipAddresses.Length; i++)
{
if (ipAddresses[i] == null ||
(ipAddresses[i].AddressFamily == AddressFamily.InterNetwork && !Socket.OSSupportsIPv4) ||
(ipAddresses[i].AddressFamily == AddressFamily.InterNetworkV6 && !Socket.OSSupportsIPv6))
{
continue;
}
socket = new Socket(ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
await socket.ConnectAsync(ipAddresses[i], address.Port);
exception = null;
break;
}
catch (Exception e)
{
exception = e;
socket.Dispose();
socket = null;
}
}
if (socket == null)
{
throw exception ?? new SocketException((int)SocketError.AddressNotAvailable);
}
if (factory.tcpSettings != null)
{
factory.tcpSettings.Configure(socket);
}
IAsyncTransport transport;
if (address.UseSsl)
{
SslStream sslStream;
var ssl = factory.SslInternal;
if (ssl == null)
{
sslStream = new SslStream(new NetworkStream(socket));
await sslStream.AuthenticateAsClientAsync(address.Host);
}
else
{
sslStream = new SslStream(new NetworkStream(socket), false, ssl.RemoteCertificateValidationCallback, ssl.LocalCertificateSelectionCallback);
await sslStream.AuthenticateAsClientAsync(address.Host, ssl.ClientCertificates,
ssl.Protocols, ssl.CheckCertificateRevocation);
}
transport = new SslSocket(this, sslStream);
}
else
{
transport = new TcpSocket(this, socket);
}
this.socketTransport = transport;
this.writer = new Writer(this, this.socketTransport);
}