Include address in error message when address already in use (#1086).

This commit is contained in:
Cesar Blum Silveira 2016-10-03 15:12:47 -07:00
parent f1f66448f4
commit 2c94884da9
2 changed files with 74 additions and 22 deletions

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
@ -109,8 +110,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel
if (!parsedAddress.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase))
{
_disposables.Push(engine.CreateServer(
parsedAddress));
try
{
_disposables.Push(engine.CreateServer(parsedAddress));
}
catch (AggregateException ex)
{
if ((ex.InnerException as UvException)?.StatusCode == Constants.EADDRINUSE)
{
throw new IOException($"Failed to bind to address {parsedAddress}: address already in use.", ex);
}
throw;
}
}
else
{
@ -120,24 +132,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel
}
var ipv4Address = parsedAddress.WithHost("127.0.0.1");
var exceptions = new List<UvException>();
var exceptions = new List<Exception>();
try
{
_disposables.Push(engine.CreateServer(ipv4Address));
}
catch (AggregateException ex)
catch (AggregateException ex) when (ex.InnerException is UvException)
{
var uvException = ex.InnerException as UvException;
if (uvException != null && uvException.StatusCode != Constants.EADDRINUSE)
if ((ex.InnerException as UvException).StatusCode == Constants.EADDRINUSE)
{
_logger.LogWarning(0, ex, $"Unable to bind to {parsedAddress.ToString()} on the IPv4 loopback interface.");
exceptions.Add(uvException);
throw new IOException($"Failed to bind to address {parsedAddress.ToString()} on the IPv4 loopback interface: port already in use.", ex);
}
else
{
throw;
_logger.LogWarning(0, ex, $"Unable to bind to {parsedAddress.ToString()} on the IPv4 loopback interface.");
exceptions.Add(ex.InnerException);
}
}
@ -147,26 +157,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel
{
_disposables.Push(engine.CreateServer(ipv6Address));
}
catch (AggregateException ex)
catch (AggregateException ex) when (ex.InnerException is UvException)
{
var uvException = ex.InnerException as UvException;
if (uvException != null && uvException.StatusCode != Constants.EADDRINUSE)
if ((ex.InnerException as UvException).StatusCode == Constants.EADDRINUSE)
{
_logger.LogWarning(0, ex, $"Unable to bind to {parsedAddress.ToString()} on the IPv6 loopback interface.");
exceptions.Add(uvException);
throw new IOException($"Failed to bind to address {parsedAddress.ToString()} on the IPv6 loopback interface: port already in use.", ex);
}
else
{
throw;
_logger.LogWarning(0, ex, $"Unable to bind to {parsedAddress.ToString()} on the IPv6 loopback interface.");
exceptions.Add(ex.InnerException);
}
}
if (exceptions.Count == 2)
{
var ex = new AggregateException(exceptions);
_logger.LogError(0, ex, $"Unable to bind to {parsedAddress.ToString()} on any loopback interface.");
throw ex;
throw new IOException($"Failed to bind to address {parsedAddress.ToString()}.", new AggregateException(exceptions));
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
@ -97,6 +98,49 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
}
}
[Fact]
public void ThrowsWhenBindingToIPv4AddressInUse()
{
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
var port = GetNextPort();
socket.Bind(new IPEndPoint(IPAddress.Loopback, port));
var hostBuilder = new WebHostBuilder()
.UseKestrel()
.UseUrls($"http://127.0.0.1:{port}")
.Configure(ConfigureEchoAddress);
using (var host = hostBuilder.Build())
{
var exception = Assert.Throws<IOException>(() => host.Start());
Assert.Equal($"Failed to bind to address http://127.0.0.1:{port}: address already in use.", exception.Message);
}
}
}
[ConditionalFact]
[IPv6SupportedCondition]
public void ThrowsWhenBindingToIPv6AddressInUse()
{
using (var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp))
{
var port = GetNextPort();
socket.Bind(new IPEndPoint(IPAddress.IPv6Loopback, port));
var hostBuilder = new WebHostBuilder()
.UseKestrel()
.UseUrls($"http://[::1]:{port}")
.Configure(ConfigureEchoAddress);
using (var host = hostBuilder.Build())
{
var exception = Assert.Throws<IOException>(() => host.Start());
Assert.Equal($"Failed to bind to address http://[::1]:{port}: address already in use.", exception.Message);
}
}
}
[Fact]
public void ThrowsWhenBindingLocalhostToIPv4AddressInUse()
{
@ -138,8 +182,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
using (var host = hostBuilder.Build())
{
var exception = Assert.Throws<AggregateException>(() => host.Start());
Assert.Contains(exception.InnerExceptions, ex => ex is UvException);
var exception = Assert.Throws<IOException>(() => host.Start());
Assert.Equal(
$"Failed to bind to address http://localhost:{port} on the {(addressFamily == AddressFamily.InterNetwork ? "IPv4" : "IPv6")} loopback interface: port already in use.",
exception.Message);
}
}
}