From 0130209cdce07dc042b075c6cf972a7eb1339861 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 7 Dec 2016 15:02:34 -0500 Subject: [PATCH] improve ipv6 error handling --- Emby.Common.Implementations/Net/NetSocket.cs | 7 ++- .../Net/SocketAcceptor.cs | 6 ++- .../Net/SocketFactory.cs | 14 +----- Emby.Server.Core/ApplicationHost.cs | 47 +++++++++++++++---- MediaBrowser.Model/Net/ISocket.cs | 12 +++++ .../Net/EndPointListener.cs | 20 +++++++- 6 files changed, 80 insertions(+), 26 deletions(-) diff --git a/Emby.Common.Implementations/Net/NetSocket.cs b/Emby.Common.Implementations/Net/NetSocket.cs index 62ca3d6ac1..bc012dfe2d 100644 --- a/Emby.Common.Implementations/Net/NetSocket.cs +++ b/Emby.Common.Implementations/Net/NetSocket.cs @@ -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 onAccept, Func isClosed) { - _acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed); + _acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode); _acceptor.StartAccept(); } diff --git a/Emby.Common.Implementations/Net/SocketAcceptor.cs b/Emby.Common.Implementations/Net/SocketAcceptor.cs index bddb7a079a..d4c6d33e52 100644 --- a/Emby.Common.Implementations/Net/SocketAcceptor.cs +++ b/Emby.Common.Implementations/Net/SocketAcceptor.cs @@ -11,8 +11,9 @@ namespace Emby.Common.Implementations.Net private readonly Socket _originalSocket; private readonly Func _isClosed; private readonly Action _onAccept; + private readonly bool _isDualMode; - public SocketAcceptor(ILogger logger, Socket originalSocket, Action onAccept, Func isClosed) + public SocketAcceptor(ILogger logger, Socket originalSocket, Action onAccept, Func 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 diff --git a/Emby.Common.Implementations/Net/SocketFactory.cs b/Emby.Common.Implementations/Net/SocketFactory.cs index 79310e0173..1f41ffff5c 100644 --- a/Emby.Common.Implementations/Net/SocketFactory.cs +++ b/Emby.Common.Implementations/Net/SocketFactory.cs @@ -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); } } diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs index f7fe02fbaa..06c761f218 100644 --- a/Emby.Server.Core/ApplicationHost.cs +++ b/Emby.Server.Core/ApplicationHost.cs @@ -1305,19 +1305,49 @@ namespace Emby.Server.Core public async Task> GetLocalIpAddresses() { - var addresses = NetworkManager.GetLocalIpAddresses().ToList(); - var list = new List(); + 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(); + + 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 _validAddressResults = new ConcurrentDictionary(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, diff --git a/MediaBrowser.Model/Net/ISocket.cs b/MediaBrowser.Model/Net/ISocket.cs index 371fbc5675..aed35bce89 100644 --- a/MediaBrowser.Model/Net/ISocket.cs +++ b/MediaBrowser.Model/Net/ISocket.cs @@ -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 onAccept, Func isClosed); } + + public class SocketCreateException : Exception + { + public SocketCreateException(string errorCode, Exception originalException) + : base(errorCode, originalException) + { + ErrorCode = errorCode; + } + + public string ErrorCode { get; private set; } + } } diff --git a/SocketHttpListener.Portable/Net/EndPointListener.cs b/SocketHttpListener.Portable/Net/EndPointListener.cs index 52385e2ba7..690dedd092 100644 --- a/SocketHttpListener.Portable/Net/EndPointListener.cs +++ b/SocketHttpListener.Portable/Net/EndPointListener.cs @@ -26,7 +26,7 @@ namespace SocketHttpListener.Net Dictionary 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);