add udp error handling
This commit is contained in:
parent
67ad1db6b7
commit
25312d7d03
|
@ -102,29 +102,10 @@ namespace Emby.Common.Implementations.Net
|
||||||
{
|
{
|
||||||
taskSource.TrySetException(ex);
|
taskSource.TrySetException(ex);
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException ex)
|
|
||||||
{
|
|
||||||
taskSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
catch (InvalidOperationException ex)
|
|
||||||
{
|
|
||||||
taskSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
catch (SecurityException ex)
|
|
||||||
{
|
|
||||||
taskSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
}, null);
|
}, null);
|
||||||
}
|
}
|
||||||
catch (SocketException ex)
|
catch (Exception ex)
|
||||||
{
|
|
||||||
taskSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
catch (ObjectDisposedException ex)
|
|
||||||
{
|
|
||||||
taskSource.TrySetException(ex);
|
|
||||||
}
|
|
||||||
catch (SecurityException ex)
|
|
||||||
{
|
{
|
||||||
taskSource.TrySetException(ex);
|
taskSource.TrySetException(ex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Emby.Common.Implementations.Networking
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<IPAddress> _localIpAddresses;
|
private List<IPAddress> _localIpAddresses;
|
||||||
private readonly object _localIpAddressSyncLock = new object();
|
private readonly object _localIpAddressSyncLock = new object();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -51,24 +51,24 @@ namespace Emby.Common.Implementations.Networking
|
||||||
return _localIpAddresses;
|
return _localIpAddresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<IPAddress> GetLocalIpAddressesInternal()
|
private IEnumerable<IPAddress> GetLocalIpAddressesInternal()
|
||||||
{
|
{
|
||||||
var list = GetIPsDefault()
|
var list = GetIPsDefault()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (list.Count == 0)
|
if (list.Count == 0)
|
||||||
{
|
{
|
||||||
list.AddRange(GetLocalIpAddressesFallback().Result);
|
list.AddRange(GetLocalIpAddressesFallback().Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.Where(FilterIpAddress).DistinctBy(i => i.ToString());
|
return list.Where(FilterIpAddress).DistinctBy(i => i.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool FilterIpAddress(IPAddress address)
|
private bool FilterIpAddress(IPAddress address)
|
||||||
{
|
{
|
||||||
var addressString = address.ToString ();
|
var addressString = address.ToString();
|
||||||
|
|
||||||
if (addressString.StartsWith("169.", StringComparison.OrdinalIgnoreCase))
|
if (addressString.StartsWith("169.", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ namespace Emby.Common.Implementations.Networking
|
||||||
{
|
{
|
||||||
var prefix = addressString.Substring(0, lengthMatch);
|
var prefix = addressString.Substring(0, lengthMatch);
|
||||||
|
|
||||||
if (GetLocalIpAddresses().Any(i => i.ToString().StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
|
if (GetLocalIpAddresses().Any(i => i.ToString().StartsWith(prefix, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -200,45 +200,50 @@ namespace Emby.Common.Implementations.Networking
|
||||||
return Dns.GetHostAddressesAsync(hostName);
|
return Dns.GetHostAddressesAsync(hostName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<IPAddress> GetIPsDefault()
|
private List<IPAddress> GetIPsDefault()
|
||||||
{
|
{
|
||||||
NetworkInterface[] interfaces;
|
NetworkInterface[] interfaces;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
interfaces = NetworkInterface.GetAllNetworkInterfaces();
|
var validStatuses = new[] { OperationalStatus.Up, OperationalStatus.Unknown };
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.ErrorException("Error in GetAllNetworkInterfaces", ex);
|
|
||||||
return new List<IPAddress>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return interfaces.SelectMany(network => {
|
interfaces = NetworkInterface.GetAllNetworkInterfaces()
|
||||||
|
.Where(i => validStatuses.Contains(i.OperationalStatus))
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.ErrorException("Error in GetAllNetworkInterfaces", ex);
|
||||||
|
return new List<IPAddress>();
|
||||||
|
}
|
||||||
|
|
||||||
try
|
return interfaces.SelectMany(network =>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
Logger.Debug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus);
|
Logger.Debug("Querying interface: {0}. Type: {1}. Status: {2}", network.Name, network.NetworkInterfaceType, network.OperationalStatus);
|
||||||
|
|
||||||
var properties = network.GetIPProperties();
|
var properties = network.GetIPProperties();
|
||||||
|
|
||||||
return properties.UnicastAddresses
|
return properties.UnicastAddresses
|
||||||
.Where(i => i.IsDnsEligible)
|
.Where(i => i.IsDnsEligible)
|
||||||
.Select(i => i.Address)
|
.Select(i => i.Address)
|
||||||
.Where(i => i.AddressFamily == AddressFamily.InterNetwork)
|
.Where(i => i.AddressFamily == AddressFamily.InterNetwork)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.ErrorException("Error querying network interface", ex);
|
Logger.ErrorException("Error querying network interface", ex);
|
||||||
return new List<IPAddress>();
|
return new List<IPAddress>();
|
||||||
}
|
}
|
||||||
|
|
||||||
}).DistinctBy(i => i.ToString())
|
}).DistinctBy(i => i.ToString())
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IEnumerable<IPAddress>> GetLocalIpAddressesFallback()
|
private async Task<IEnumerable<IPAddress>> GetLocalIpAddressesFallback()
|
||||||
{
|
{
|
||||||
var host = await Dns.GetHostEntryAsync(Dns.GetHostName()).ConfigureAwait(false);
|
var host = await Dns.GetHostEntryAsync(Dns.GetHostName()).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|
|
@ -240,6 +240,8 @@ namespace Emby.Dlna.Main
|
||||||
|
|
||||||
var addresses = (await _appHost.GetLocalIpAddresses().ConfigureAwait(false)).ToList();
|
var addresses = (await _appHost.GetLocalIpAddresses().ConfigureAwait(false)).ToList();
|
||||||
|
|
||||||
|
var udn = CreateUuid(_appHost.SystemId);
|
||||||
|
|
||||||
foreach (var address in addresses)
|
foreach (var address in addresses)
|
||||||
{
|
{
|
||||||
//if (IPAddress.IsLoopback(address))
|
//if (IPAddress.IsLoopback(address))
|
||||||
|
@ -250,8 +252,6 @@ namespace Emby.Dlna.Main
|
||||||
|
|
||||||
var addressString = address.ToString();
|
var addressString = address.ToString();
|
||||||
|
|
||||||
var udn = CreateUuid(addressString);
|
|
||||||
|
|
||||||
var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
|
var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
|
||||||
|
|
||||||
_logger.Info("Registering publisher for {0} on {1}", fullService, addressString);
|
_logger.Info("Registering publisher for {0} on {1}", fullService, addressString);
|
||||||
|
@ -299,7 +299,12 @@ namespace Emby.Dlna.Main
|
||||||
|
|
||||||
private string CreateUuid(string text)
|
private string CreateUuid(string text)
|
||||||
{
|
{
|
||||||
return text.GetMD5().ToString("N");
|
Guid guid;
|
||||||
|
if (!Guid.TryParse(text, out guid))
|
||||||
|
{
|
||||||
|
guid = text.GetMD5();
|
||||||
|
}
|
||||||
|
return guid.ToString("N");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetProperies(SsdpDevice device, string fullDeviceType)
|
private void SetProperies(SsdpDevice device, string fullDeviceType)
|
||||||
|
|
|
@ -228,7 +228,7 @@ namespace Emby.Dlna.Service
|
||||||
var headers = string.Join(", ", request.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
|
var headers = string.Join(", ", request.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
|
||||||
builder.AppendFormat("Headers: {0}", headers);
|
builder.AppendFormat("Headers: {0}", headers);
|
||||||
builder.AppendLine();
|
builder.AppendLine();
|
||||||
builder.Append(request.InputXml);
|
//builder.Append(request.InputXml);
|
||||||
|
|
||||||
Logger.LogMultiline("Control request", LogSeverity.Debug, builder);
|
Logger.LogMultiline("Control request", LogSeverity.Debug, builder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,9 +124,17 @@ namespace Emby.Server.Implementations.Security
|
||||||
//the rest of the lines should be pairs of features and timestamps
|
//the rest of the lines should be pairs of features and timestamps
|
||||||
for (var i = 2; i < contents.Length; i = i + 2)
|
for (var i = 2; i < contents.Length; i = i + 2)
|
||||||
{
|
{
|
||||||
var feat = Guid.Parse(contents[i]);
|
var line = contents[i];
|
||||||
|
if (string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
SetUpdateRecord(feat, new DateTime(Convert.ToInt64(contents[i + 1])));
|
Guid feat;
|
||||||
|
if (Guid.TryParse(line, out feat))
|
||||||
|
{
|
||||||
|
SetUpdateRecord(feat, new DateTime(Convert.ToInt64(contents[i + 1])));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,17 +78,6 @@ namespace Rssdp.Infrastructure
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Partial constructor.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="socketFactory">An implementation of the <see cref="ISocketFactory"/> interface that can be used to make new unicast and multicast sockets. Cannot be null.</param>
|
|
||||||
/// <param name="localPort">The specific local port to use for all sockets created by this instance. Specify zero to indicate the system should choose a free port itself.</param>
|
|
||||||
/// <exception cref="System.ArgumentNullException">The <paramref name="socketFactory"/> argument is null.</exception>
|
|
||||||
public SsdpCommunicationsServer(ISocketFactory socketFactory, int localPort)
|
|
||||||
: this(socketFactory, localPort, SsdpConstants.SsdpDefaultMulticastTimeToLive)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Full constructor.
|
/// Full constructor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -170,7 +159,12 @@ namespace Rssdp.Infrastructure
|
||||||
EnsureSendSocketCreated();
|
EnsureSendSocketCreated();
|
||||||
|
|
||||||
// SSDP spec recommends sending messages multiple times (not more than 3) to account for possible packet loss over UDP.
|
// SSDP spec recommends sending messages multiple times (not more than 3) to account for possible packet loss over UDP.
|
||||||
await Repeat(SsdpConstants.UdpResendCount, TimeSpan.FromMilliseconds(100), () => SendMessageIfSocketNotDisposed(messageData, destination)).ConfigureAwait(false);
|
for (var i = 0; i < SsdpConstants.UdpResendCount; i++)
|
||||||
|
{
|
||||||
|
await SendMessageIfSocketNotDisposed(messageData, destination).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await Task.Delay(100).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -188,8 +182,17 @@ namespace Rssdp.Infrastructure
|
||||||
EnsureSendSocketCreated();
|
EnsureSendSocketCreated();
|
||||||
|
|
||||||
// SSDP spec recommends sending messages multiple times (not more than 3) to account for possible packet loss over UDP.
|
// SSDP spec recommends sending messages multiple times (not more than 3) to account for possible packet loss over UDP.
|
||||||
await Repeat(SsdpConstants.UdpResendCount, TimeSpan.FromMilliseconds(100),
|
for (var i = 0; i < SsdpConstants.UdpResendCount; i++)
|
||||||
() => SendMessageIfSocketNotDisposed(messageData, new IpEndPointInfo() { IpAddress = new IpAddressInfo { Address = SsdpConstants.MulticastLocalAdminAddress }, Port = SsdpConstants.MulticastPort })).ConfigureAwait(false);
|
{
|
||||||
|
await SendMessageIfSocketNotDisposed(messageData, new IpEndPointInfo
|
||||||
|
{
|
||||||
|
IpAddress = new IpAddressInfo { Address = SsdpConstants.MulticastLocalAdminAddress },
|
||||||
|
Port = SsdpConstants.MulticastPort
|
||||||
|
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await Task.Delay(100).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -255,28 +258,16 @@ namespace Rssdp.Infrastructure
|
||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
||||||
private async Task SendMessageIfSocketNotDisposed(byte[] messageData, IpEndPointInfo destination)
|
private Task SendMessageIfSocketNotDisposed(byte[] messageData, IpEndPointInfo destination)
|
||||||
{
|
{
|
||||||
var socket = _SendSocket;
|
var socket = _SendSocket;
|
||||||
if (socket != null)
|
if (socket != null)
|
||||||
{
|
{
|
||||||
await _SendSocket.SendAsync(messageData, messageData.Length, destination).ConfigureAwait(false);
|
return _SendSocket.SendAsync(messageData, messageData.Length, destination);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ThrowIfDisposed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task Repeat(int repetitions, TimeSpan delay, Func<Task> work)
|
ThrowIfDisposed();
|
||||||
{
|
return Task.FromResult(true);
|
||||||
for (int cnt = 0; cnt < repetitions; cnt++)
|
|
||||||
{
|
|
||||||
await work().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (delay != TimeSpan.Zero)
|
|
||||||
await Task.Delay(delay).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IUdpSocket ListenForBroadcastsAsync()
|
private IUdpSocket ListenForBroadcastsAsync()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user