Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public TcpClient(IPEndPoint localEP)

// Initializes a new instance of the System.Net.Sockets.TcpClient class and connects to the specified port on
// the specified host.
public TcpClient(string hostname, int port)
public TcpClient(string hostname, int port) : this(AddressFamily.Unknown)
{
ArgumentNullException.ThrowIfNull(hostname);

Expand All @@ -64,8 +64,6 @@ public TcpClient(string hostname, int port)
throw new ArgumentOutOfRangeException(nameof(port));
}

_family = AddressFamily.Unknown;

try
{
Connect(hostname, port);
Expand Down Expand Up @@ -129,87 +127,10 @@ public void Connect(string hostname, int port)
throw new ArgumentOutOfRangeException(nameof(port));
}

// Check for already connected and throw here. This check
// is not required in the other connect methods as they
// will throw from WinSock. Here, the situation is more
// complex since we have to resolve a hostname so it's
// easier to simply block the request up front.
if (_active)
{
throw new SocketException((int)SocketError.IsConnected);
}

// IPv6: We need to process each of the addresses returned from
// DNS when trying to connect. Use of AddressList[0] is
// bad form.
IPAddress[] addresses = Dns.GetHostAddresses(hostname);
ExceptionDispatchInfo? lastex = null;

try
{
foreach (IPAddress address in addresses)
{
try
{
if (_clientSocket == null)
{
// We came via the <hostname,port> constructor. Set the address family appropriately,
// create the socket and try to connect.
Debug.Assert(address.AddressFamily == AddressFamily.InterNetwork || address.AddressFamily == AddressFamily.InterNetworkV6);
if ((address.AddressFamily == AddressFamily.InterNetwork && Socket.OSSupportsIPv4) || Socket.OSSupportsIPv6)
{
var socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
if (address.IsIPv4MappedToIPv6)
{
socket.DualMode = true;
}

// Use of Interlocked.Exchanged ensures _clientSocket is written before Disposed is read.
Interlocked.Exchange(ref _clientSocket!, socket);
if (Disposed)
{
// Dispose the socket so it throws ObjectDisposedException when we Connect.
socket.Dispose();
}

try
{
socket.Connect(address, port);
}
catch
{
_clientSocket = null!;
throw;
}
}
Client.Connect(hostname, port);
_family = Client.AddressFamily;
_active = true;

_family = address.AddressFamily;
_active = true;
break;
}
else if (address.AddressFamily == _family || _family == AddressFamily.Unknown)
{
// Only use addresses with a matching family
Connect(new IPEndPoint(address, port));
_active = true;
break;
}
}
catch (Exception ex) when (!(ex is OutOfMemoryException))
{
lastex = ExceptionDispatchInfo.Capture(ex);
}
}
}
finally
{
if (!_active)
{
// The connect failed - rethrow the last error we had
lastex?.Throw();
throw new SocketException((int)SocketError.NotConnected);
}
}
}

// Connects the Client to the specified port on the specified host.
Expand Down