浏览代码

improve ipv6 error handling

Luke Pulverenti 8 年之前
父节点
当前提交
0130209cdc

+ 5 - 2
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<ISocket> onAccept, Func<bool> isClosed)
         {
-            _acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed);
+            _acceptor = new SocketAcceptor(_logger, Socket, onAccept, isClosed, DualMode);
 
             _acceptor.StartAccept();
         }

+ 4 - 2
Emby.Common.Implementations/Net/SocketAcceptor.cs

@@ -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

+ 2 - 12
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);
             }
         }
 

+ 39 - 8
Emby.Server.Core/ApplicationHost.cs

@@ -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,

+ 12 - 0
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<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; }
+    }
 }

+ 18 - 2
SocketHttpListener.Portable/Net/EndPointListener.cs

@@ -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);