From 39047638cc60a0b298a05f30b167d6ee6783383d Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Mon, 24 Apr 2017 15:36:18 -0700 Subject: [PATCH] Add debug logging in address binding when IPv6Any fails --- KestrelHttpServer.sln | 1 + .../CoreStrings.resx | 3 ++ .../Internal/AddressBinder.cs | 2 ++ .../Properties/CoreStrings.Designer.cs | 14 ++++++++++ .../AddressBinderTests.cs | 5 +++- test/shared/MockLogger.cs | 28 +++++++++++++++++++ 6 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 test/shared/MockLogger.cs diff --git a/KestrelHttpServer.sln b/KestrelHttpServer.sln index 2fba69b809..3c10b81d05 100644 --- a/KestrelHttpServer.sln +++ b/KestrelHttpServer.sln @@ -25,6 +25,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0EF2AC test\shared\KestrelTestLoggerFactory.cs = test\shared\KestrelTestLoggerFactory.cs test\shared\LifetimeNotImplemented.cs = test\shared\LifetimeNotImplemented.cs test\shared\MockFrameControl.cs = test\shared\MockFrameControl.cs + test\shared\MockLogger.cs = test\shared\MockLogger.cs test\shared\MockSocketOutput.cs = test\shared\MockSocketOutput.cs test\shared\MockSystemClock.cs = test\shared\MockSystemClock.cs test\shared\StringExtensions.cs = test\shared\StringExtensions.cs diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Core/CoreStrings.resx b/src/Microsoft.AspNetCore.Server.Kestrel.Core/CoreStrings.resx index f1605f6630..03a86be5db 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Core/CoreStrings.resx +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Core/CoreStrings.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Failed to bind to http://[::]:{port} (IPv6Any). Attempting to bind to http://0.0.0.0:{port} instead. + Cannot write to response body after connection has been upgraded. diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Core/Internal/AddressBinder.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Core/Internal/AddressBinder.cs index e30418727b..d041c3bec0 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Core/Internal/AddressBinder.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Core/Internal/AddressBinder.cs @@ -206,6 +206,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal } catch (Exception ex) when (!(ex is IOException)) { + context.Logger.LogDebug(CoreStrings.FormatFallbackToIPv4Any(parsedAddress.Port)); + // for machines that do not support IPv6 options = new ListenOptions(new IPEndPoint(IPAddress.Any, parsedAddress.Port)); await BindEndpointAsync(options, context).ConfigureAwait(false); diff --git a/src/Microsoft.AspNetCore.Server.Kestrel.Core/Properties/CoreStrings.Designer.cs b/src/Microsoft.AspNetCore.Server.Kestrel.Core/Properties/CoreStrings.Designer.cs index 0deecaa6d1..c97aefeac9 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel.Core/Properties/CoreStrings.Designer.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel.Core/Properties/CoreStrings.Designer.cs @@ -10,6 +10,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core private static readonly ResourceManager _resourceManager = new ResourceManager("Microsoft.AspNetCore.Server.Kestrel.Core.CoreStrings", typeof(CoreStrings).GetTypeInfo().Assembly); + /// + /// Failed to bind to http://[::]:{port} (IPv6Any). Attempting to bind to http://0.0.0.0:{port} instead. + /// + internal static string FallbackToIPv4Any + { + get => GetString("FallbackToIPv4Any"); + } + + /// + /// Failed to bind to http://[::]:{port} (IPv6Any). Attempting to bind to http://0.0.0.0:{port} instead. + /// + internal static string FormatFallbackToIPv4Any(object port) + => string.Format(CultureInfo.CurrentCulture, GetString("FallbackToIPv4Any", "port"), port); + /// /// Cannot write to response body after connection has been upgraded. /// diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/AddressBinderTests.cs b/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/AddressBinderTests.cs index 762e3191f1..655bbaea25 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/AddressBinderTests.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests/AddressBinderTests.cs @@ -8,6 +8,7 @@ using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Logging.Abstractions; using Xunit; @@ -88,6 +89,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [InlineData("http://contoso.com:80")] public async Task FallbackToIPv4WhenIPv6AnyBindFails(string address) { + var logger = new MockLogger(); var addresses = new ServerAddressesFeature(); addresses.Addresses.Add(address); var options = new List(); @@ -97,7 +99,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests await AddressBinder.BindAsync(addresses, options, - NullLogger.Instance, + logger, endpoint => { if (endpoint.IPEndPoint.Address == IPAddress.IPv6Any) @@ -116,6 +118,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests Assert.True(ipV4Attempt, "Should have attempted to bind to IPAddress.Any"); Assert.True(ipV6Attempt, "Should have attempted to bind to IPAddress.IPv6Any"); + Assert.Contains(logger.Messages, f => f.Equals(CoreStrings.FormatFallbackToIPv4Any(80))); } } } diff --git a/test/shared/MockLogger.cs b/test/shared/MockLogger.cs new file mode 100644 index 0000000000..677d0687de --- /dev/null +++ b/test/shared/MockLogger.cs @@ -0,0 +1,28 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions.Internal; + +namespace Microsoft.AspNetCore.Testing +{ + public class MockLogger : ILogger + { + private List _messages = new List(); + + public IDisposable BeginScope(TState state) + => NullScope.Instance; + + public bool IsEnabled(LogLevel logLevel) + => true; + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + _messages.Add(formatter(state, exception)); + } + + public IReadOnlyList Messages => _messages; + } +}