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

View File

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

View File

@ -46,21 +46,11 @@ namespace Emby.Common.Implementations.Net
socket.DualMode = true; socket.DualMode = true;
} }
return new NetSocket(socket, _logger); return new NetSocket(socket, _logger, dualMode);
} }
catch (SocketException ex) catch (SocketException ex)
{ {
if (dualMode) throw new SocketCreateException(ex.SocketErrorCode.ToString(), ex);
{
_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;
} }
} }

View File

@ -1305,7 +1305,17 @@ namespace Emby.Server.Core
public async Task<List<IpAddressInfo>> GetLocalIpAddresses() public async Task<List<IpAddressInfo>> GetLocalIpAddresses()
{ {
var addresses = NetworkManager.GetLocalIpAddresses().ToList(); var addresses = ServerConfigurationManager
.Configuration
.LocalNetworkAddresses
.Select(NormalizeConfiguredLocalAddress)
.Where(i => i != null)
.ToList();
if (addresses.Count == 0)
{
addresses.AddRange(NetworkManager.GetLocalIpAddresses());
var list = new List<IpAddressInfo>(); var list = new List<IpAddressInfo>();
foreach (var address in addresses) foreach (var address in addresses)
@ -1317,7 +1327,27 @@ namespace Emby.Server.Core
} }
} }
return list; addresses = 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); private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
@ -1553,7 +1583,8 @@ namespace Emby.Server.Core
throw new NotImplementedException(); throw new NotImplementedException();
} }
var process = ProcessFactory.Create(new ProcessOptions { var process = ProcessFactory.Create(new ProcessOptions
{
FileName = url, FileName = url,
EnableRaisingEvents = true, EnableRaisingEvents = true,
UseShellExecute = true, UseShellExecute = true,

View File

@ -4,6 +4,7 @@ namespace MediaBrowser.Model.Net
{ {
public interface ISocket : IDisposable public interface ISocket : IDisposable
{ {
bool DualMode { get; }
IpEndPointInfo LocalEndPoint { get; } IpEndPointInfo LocalEndPoint { get; }
IpEndPointInfo RemoteEndPoint { get; } IpEndPointInfo RemoteEndPoint { get; }
void Close(); void Close();
@ -13,4 +14,15 @@ namespace MediaBrowser.Model.Net
void StartAccept(Action<ISocket> onAccept, Func<bool> isClosed); 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; Dictionary<HttpConnection, HttpConnection> unregistered;
private readonly ILogger _logger; private readonly ILogger _logger;
private bool _closed; private bool _closed;
private readonly bool _enableDualMode; private bool _enableDualMode;
private readonly ICryptoProvider _cryptoProvider; private readonly ICryptoProvider _cryptoProvider;
private readonly IStreamFactory _streamFactory; private readonly IStreamFactory _streamFactory;
private readonly ISocketFactory _socketFactory; private readonly ISocketFactory _socketFactory;
@ -64,8 +64,24 @@ namespace SocketHttpListener.Net
} }
private void CreateSocket() private void CreateSocket()
{
try
{ {
sock = _socketFactory.CreateSocket(endpoint.IpAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp, _enableDualMode); 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); sock.Bind(endpoint);