The static Socket.ConnectAsync method creates one or more Sockets to use to establish the connection, and that Socket is then returned when the connection is made successfully. When the connection fails, it's supposed to Dispose of the created Socket(s). But it's failing to do so when something other than a DnsEndPoint is supplied, hitting this code path:
https://github.com/dotnet/corefx/blob/4fc38265fb35fd6bfc982b8e35a2545502e596b3/src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs#L3975-L3976
that creates the Socket but then uses the public ConnectAsync(SocketAsyncEventArgs), which can't Dispose of the Socket because it doesn't know that it's one internally created (since it's a public method and the caller owns the Socket instance). This ends up leaking a socket handle / file descriptor until the Socket / SafeHandle's finalizer runs to close it, eventually.
This issue exists in both .NET Core and .NET Framework, and appears to have existed for a long time. However, it's showing up as an issue for SocketsHttpHandler, due to this optimization:
https://github.com/dotnet/corefx/blob/4fc38265fb35fd6bfc982b8e35a2545502e596b3/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs#L57-L59
where SocketsHttpHandler is trying to take the more optimized IPEndPoint path when an IP address is supplied. This then means that HttpClient failed connects end up leaking a handle / file descriptor similarly until the finalizer runs, which if lots of requests are being made, could result in "too many open files" errors on Unix.
I'm marking this as a 2.1 issue just for the SocketsHttpHandler fix, as it's a new issue in 2.1. The Sockets issue should be addressed, but it's long-standing and can be deferred to 2.2.
The static Socket.ConnectAsync method creates one or more Sockets to use to establish the connection, and that Socket is then returned when the connection is made successfully. When the connection fails, it's supposed to Dispose of the created Socket(s). But it's failing to do so when something other than a DnsEndPoint is supplied, hitting this code path:
https://github.com/dotnet/corefx/blob/4fc38265fb35fd6bfc982b8e35a2545502e596b3/src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs#L3975-L3976
that creates the Socket but then uses the public
ConnectAsync(SocketAsyncEventArgs), which can't Dispose of the Socket because it doesn't know that it's one internally created (since it's a public method and the caller owns the Socket instance). This ends up leaking a socket handle / file descriptor until the Socket / SafeHandle's finalizer runs to close it, eventually.This issue exists in both .NET Core and .NET Framework, and appears to have existed for a long time. However, it's showing up as an issue for SocketsHttpHandler, due to this optimization:
https://github.com/dotnet/corefx/blob/4fc38265fb35fd6bfc982b8e35a2545502e596b3/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs#L57-L59
where SocketsHttpHandler is trying to take the more optimized IPEndPoint path when an IP address is supplied. This then means that HttpClient failed connects end up leaking a handle / file descriptor similarly until the finalizer runs, which if lots of requests are being made, could result in "too many open files" errors on Unix.
I'm marking this as a 2.1 issue just for the SocketsHttpHandler fix, as it's a new issue in 2.1. The Sockets issue should be addressed, but it's long-standing and can be deferred to 2.2.