improve ipv6 error handling

This commit is contained in:
Luke Pulverenti 2016-12-07 15:02:34 -05:00
parent 20c2499797
commit 0130209cdc
6 changed files with 80 additions and 26 deletions

View File

@ -13,7 +13,9 @@ namespace Emby.Common.Implementations.Net
public Socket Socket { get; private set; }
private readonly ILogger _logger;
public NetSocket(Socket socket, ILogger logger)
public bool DualMode { get; private set; }
public NetSocket(Socket socket, ILogger logger, bool isDualMode)
{
if (socket == null)
{
@ -26,6 +28,7 @@ namespace Emby.Common.Implementations.Net
Socket = socket;
_logger = logger;
DualMode = isDualMode;
}
public IpEndPointInfo LocalEndPoint
@ -81,7 +84,7 @@ namespace Emby.Common.Implementations.Net
private SocketAcceptor _acceptor;
public void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed)
{
_acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed);
_acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode);
_acceptor.StartAccept();
}

View File

@ -11,8 +11,9 @@ namespace Emby.Common.Implementations.Net
private readonly Socket _originalSocket;
private readonly Func<bool> _isClosed;
private readonly Action<ISocket> _onAccept;
private readonly bool _isDualMode;
public SocketAcceptor(ILogger logger, Socket originalSocket, Action<ISocket> onAccept, Func<bool> isClosed)
public SocketAcceptor(ILogger logger, Socket originalSocket, Action<ISocket> onAccept, Func<bool> isClosed, bool isDualMode)
{
if (logger == null)
{
@ -34,6 +35,7 @@ namespace Emby.Common.Implementations.Net
_logger = logger;
_originalSocket = originalSocket;
_isClosed = isClosed;
_isDualMode = isDualMode;
_onAccept = onAccept;
}
@ -115,7 +117,7 @@ namespace Emby.Common.Implementations.Net
if (acceptSocket != null)
{
//ProcessAccept(acceptSocket);
_onAccept(new NetSocket(acceptSocket, _logger));
_onAccept(new NetSocket(acceptSocket, _logger, _isDualMode));
}
// Accept the next connection request

View File

@ -46,21 +46,11 @@ namespace Emby.Common.Implementations.Net
socket.DualMode = true;
}
return new NetSocket(socket, _logger);
return new NetSocket(socket, _logger, dualMode);
}
catch (SocketException ex)
{
if (dualMode)
{
_logger.Error("Error creating dual mode socket: {0}. Will retry with ipv4-only.", ex.SocketErrorCode);
if (ex.SocketErrorCode == SocketError.AddressFamilyNotSupported)
{
return CreateSocket(IpAddressFamily.InterNetwork, socketType, protocolType, false);
}
}
throw;
throw new SocketCreateException(ex.SocketErrorCode.ToString(), ex);
}
}

View File

@ -1305,19 +1305,49 @@ namespace Emby.Server.Core
public async Task<List<IpAddressInfo>> GetLocalIpAddresses()
{
var addresses = NetworkManager.GetLocalIpAddresses().ToList();
var list = new List<IpAddressInfo>();
var addresses = ServerConfigurationManager
.Configuration
.LocalNetworkAddresses
.Select(NormalizeConfiguredLocalAddress)
.Where(i => i != null)
.ToList();
foreach (var address in addresses)
if (addresses.Count == 0)
{
var valid = await IsIpAddressValidAsync(address).ConfigureAwait(false);
if (valid)
addresses.AddRange(NetworkManager.GetLocalIpAddresses());
var list = new List<IpAddressInfo>();
foreach (var address in addresses)
{
list.Add(address);
var valid = await IsIpAddressValidAsync(address).ConfigureAwait(false);
if (valid)
{
list.Add(address);
}
}
addresses = list;
}
return list;
return addresses;
}
private IpAddressInfo NormalizeConfiguredLocalAddress(string address)
{
var index = address.Trim('/').IndexOf('/');
if (index != -1)
{
address = address.Substring(index + 1);
}
IpAddressInfo result;
if (NetworkManager.TryParseIpAddress(address.Trim('/'), out result))
{
return result;
}
return null;
}
private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
@ -1553,7 +1583,8 @@ namespace Emby.Server.Core
throw new NotImplementedException();
}
var process = ProcessFactory.Create(new ProcessOptions {
var process = ProcessFactory.Create(new ProcessOptions
{
FileName = url,
EnableRaisingEvents = true,
UseShellExecute = true,

View File

@ -4,6 +4,7 @@ namespace MediaBrowser.Model.Net
{
public interface ISocket : IDisposable
{
bool DualMode { get; }
IpEndPointInfo LocalEndPoint { get; }
IpEndPointInfo RemoteEndPoint { get; }
void Close();
@ -13,4 +14,15 @@ namespace MediaBrowser.Model.Net
void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed);
}
public class SocketCreateException : Exception
{
public SocketCreateException(string errorCode, Exception originalException)
: base(errorCode, originalException)
{
ErrorCode = errorCode;
}
public string ErrorCode { get; private set; }
}
}

View File

@ -26,7 +26,7 @@ namespace SocketHttpListener.Net
Dictionary<HttpConnection, HttpConnection> unregistered;
private readonly ILogger _logger;
private bool _closed;
private readonly bool _enableDualMode;
private bool _enableDualMode;
private readonly ICryptoProvider _cryptoProvider;
private readonly IStreamFactory _streamFactory;
private readonly ISocketFactory _socketFactory;
@ -65,7 +65,23 @@ namespace SocketHttpListener.Net
private void CreateSocket()
{
sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
try
{
sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
}
catch (SocketCreateException ex)
{
if (_enableDualMode && endpoint.IpAddress.Equals(IpAddressInfo.IPv6Any) && string.Equals(ex.ErrorCode, "AddressFamilyNotSupported", StringComparison.OrdinalIgnoreCase))
{
endpoint = new IpEndPointInfo(IpAddressInfo.Any, endpoint.Port);
_enableDualMode = false;
sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode);
}
else
{
throw;
}
}
sock.Bind(endpoint);