1using System;
2using System.IO;
3using System.Linq;
4using System.Net;
5using System.Net.Http;
6using System.Net.NetworkInformation;
7using System.Net.Security;
8using System.Net.Sockets;
9using System.Text;
10using System.Threading;
11using System.Threading.Tasks;
12using NzbDrone.Common.Cache;
…lines 13–247 unchanged (235 lines)
248
249 private CredentialCache GetCredentialCache()
250 {
251 return _credentialCache.Get("credentialCache", () => new CredentialCache());
252 }
253
254 private static bool HasRoutableIPv4Address()
255 {
256 // Get all IPv4 addresses from all interfaces and return true if there are any with non-loopback addresses
257 var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
258
259 return networkInterfaces.Any(ni =>
260 ni.OperationalStatus == OperationalStatus.Up &&
261 ni.GetIPProperties().UnicastAddresses.Any(ip =>
262 ip.Address.AddressFamily == AddressFamily.InterNetwork &&
263 !IPAddress.IsLoopback(ip.Address)));
264 }
265
266 private static async ValueTask<Stream> onConnect(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
267 {
268 // Until .NET supports an implementation of Happy Eyeballs (https://tools.ietf.org/html/rfc8305#section-2), let's make IPv4 fallback work in a simple way.
269 // This issue is being tracked at https://github.com/dotnet/runtime/issues/26177 and expected to be fixed in .NET 6.
270 if (useIPv6)
…lines 271–282 unchanged (12 lines)
283 }
284
285 return await attemptConnection(AddressFamily.InterNetworkV6, context, localToken);
286 }
287 catch
288 {
289 // Do not retry IPv6 if a routable IPv4 address is available, otherwise continue to attempt IPv6 connections.
290 useIPv6 = !HasRoutableIPv4Address();
291 }
292 finally
293 {
294 hasResolvedIPv6Availability = true;
295 }
296 }
…lines 297–327 unchanged (31 lines)