Merge pull request #978 from fasheng/fix-dlna-multiple-interfaces

Fix DLNA for multiple interfaces on linux
This commit is contained in:
Vasily 2019-02-27 19:23:31 +03:00 committed by GitHub
commit 3769453541
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 131 additions and 33 deletions

View File

@ -7,6 +7,7 @@ namespace Emby.Dlna.Configuration
public bool EnableServer { get; set; } public bool EnableServer { get; set; }
public bool EnableDebugLog { get; set; } public bool EnableDebugLog { get; set; }
public bool BlastAliveMessages { get; set; } public bool BlastAliveMessages { get; set; }
public bool SendOnlyMatchedHost { get; set; }
public int ClientDiscoveryIntervalSeconds { get; set; } public int ClientDiscoveryIntervalSeconds { get; set; }
public int BlastAliveMessageIntervalSeconds { get; set; } public int BlastAliveMessageIntervalSeconds { get; set; }
public string DefaultUserId { get; set; } public string DefaultUserId { get; set; }
@ -16,6 +17,7 @@ namespace Emby.Dlna.Configuration
EnablePlayTo = true; EnablePlayTo = true;
EnableServer = true; EnableServer = true;
BlastAliveMessages = true; BlastAliveMessages = true;
SendOnlyMatchedHost = true;
ClientDiscoveryIntervalSeconds = 60; ClientDiscoveryIntervalSeconds = 60;
BlastAliveMessageIntervalSeconds = 1800; BlastAliveMessageIntervalSeconds = 1800;
} }

View File

@ -169,9 +169,10 @@ namespace Emby.Dlna.Main
{ {
if (_communicationsServer == null) if (_communicationsServer == null)
{ {
var enableMultiSocketBinding = _environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows; var enableMultiSocketBinding = _environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows ||
_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Linux;
_communicationsServer = new SsdpCommunicationsServer(_socketFactory, _networkManager, _logger, enableMultiSocketBinding) _communicationsServer = new SsdpCommunicationsServer(_config, _socketFactory, _networkManager, _logger, enableMultiSocketBinding)
{ {
IsShared = true IsShared = true
}; };
@ -229,7 +230,7 @@ namespace Emby.Dlna.Main
try try
{ {
_Publisher = new SsdpDevicePublisher(_communicationsServer, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion); _Publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion, _config.GetDlnaConfiguration().SendOnlyMatchedHost);
_Publisher.LogFunction = LogMessage; _Publisher.LogFunction = LogMessage;
_Publisher.SupportPnpRootDevice = false; _Publisher.SupportPnpRootDevice = false;
@ -251,11 +252,11 @@ namespace Emby.Dlna.Main
foreach (var address in addresses) foreach (var address in addresses)
{ {
// TODO: Remove this condition on platforms that support it if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
//if (address.AddressFamily == IpAddressFamily.InterNetworkV6) {
//{ // Not support IPv6 right now
// continue; continue;
//} }
var fullService = "urn:schemas-upnp-org:device:MediaServer:1"; var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
@ -268,6 +269,8 @@ namespace Emby.Dlna.Main
{ {
CacheLifetime = TimeSpan.FromSeconds(1800), //How long SSDP clients can cache this info. CacheLifetime = TimeSpan.FromSeconds(1800), //How long SSDP clients can cache this info.
Location = uri, // Must point to the URL that serves your devices UPnP description document. Location = uri, // Must point to the URL that serves your devices UPnP description document.
Address = address,
SubnetMask = _networkManager.GetLocalIpSubnetMask(address),
FriendlyName = "Jellyfin", FriendlyName = "Jellyfin",
Manufacturer = "Jellyfin", Manufacturer = "Jellyfin",
ModelName = "Jellyfin Server", ModelName = "Jellyfin Server",

View File

@ -1579,7 +1579,7 @@ namespace Emby.Server.Implementations
if (addresses.Count == 0) if (addresses.Count == 0)
{ {
addresses.AddRange(NetworkManager.GetLocalIpAddresses()); addresses.AddRange(NetworkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces));
} }
var resultList = new List<IpAddressInfo>(); var resultList = new List<IpAddressInfo>();

View File

@ -79,13 +79,13 @@ namespace Emby.Server.Implementations.Networking
private IpAddressInfo[] _localIpAddresses; private IpAddressInfo[] _localIpAddresses;
private readonly object _localIpAddressSyncLock = new object(); private readonly object _localIpAddressSyncLock = new object();
public IpAddressInfo[] GetLocalIpAddresses() public IpAddressInfo[] GetLocalIpAddresses(bool ignoreVirtualInterface = true)
{ {
lock (_localIpAddressSyncLock) lock (_localIpAddressSyncLock)
{ {
if (_localIpAddresses == null) if (_localIpAddresses == null)
{ {
var addresses = GetLocalIpAddressesInternal().Result.Select(ToIpAddressInfo).ToArray(); var addresses = GetLocalIpAddressesInternal(ignoreVirtualInterface).Result.Select(ToIpAddressInfo).ToArray();
_localIpAddresses = addresses; _localIpAddresses = addresses;
@ -95,9 +95,9 @@ namespace Emby.Server.Implementations.Networking
} }
} }
private async Task<List<IPAddress>> GetLocalIpAddressesInternal() private async Task<List<IPAddress>> GetLocalIpAddressesInternal(bool ignoreVirtualInterface)
{ {
var list = GetIPsDefault() var list = GetIPsDefault(ignoreVirtualInterface)
.ToList(); .ToList();
if (list.Count == 0) if (list.Count == 0)
@ -383,7 +383,7 @@ namespace Emby.Server.Implementations.Networking
return Dns.GetHostAddressesAsync(hostName); return Dns.GetHostAddressesAsync(hostName);
} }
private List<IPAddress> GetIPsDefault() private List<IPAddress> GetIPsDefault(bool ignoreVirtualInterface)
{ {
NetworkInterface[] interfaces; NetworkInterface[] interfaces;
@ -414,7 +414,7 @@ namespace Emby.Server.Implementations.Networking
// Try to exclude virtual adapters // Try to exclude virtual adapters
// http://stackoverflow.com/questions/8089685/c-sharp-finding-my-machines-local-ip-address-and-not-the-vms // http://stackoverflow.com/questions/8089685/c-sharp-finding-my-machines-local-ip-address-and-not-the-vms
var addr = ipProperties.GatewayAddresses.FirstOrDefault(); var addr = ipProperties.GatewayAddresses.FirstOrDefault();
if (addr == null || string.Equals(addr.Address.ToString(), "0.0.0.0", StringComparison.OrdinalIgnoreCase)) if (addr == null || ignoreVirtualInterface && string.Equals(addr.Address.ToString(), "0.0.0.0", StringComparison.OrdinalIgnoreCase))
{ {
return new List<IPAddress>(); return new List<IPAddress>();
} }
@ -636,6 +636,66 @@ namespace Emby.Server.Implementations.Networking
return false; return false;
} }
public bool IsInSameSubnet(IpAddressInfo address1, IpAddressInfo address2, IpAddressInfo subnetMask)
{
IPAddress network1 = GetNetworkAddress(ToIPAddress(address1), ToIPAddress(subnetMask));
IPAddress network2 = GetNetworkAddress(ToIPAddress(address2), ToIPAddress(subnetMask));
return network1.Equals(network2);
}
private IPAddress GetNetworkAddress(IPAddress address, IPAddress subnetMask)
{
byte[] ipAdressBytes = address.GetAddressBytes();
byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
if (ipAdressBytes.Length != subnetMaskBytes.Length)
{
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
}
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for (int i = 0; i < broadcastAddress.Length; i++)
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i]));
}
return new IPAddress(broadcastAddress);
}
public IpAddressInfo GetLocalIpSubnetMask(IpAddressInfo address)
{
NetworkInterface[] interfaces;
IPAddress ipaddress = ToIPAddress(address);
try
{
var validStatuses = new[] { OperationalStatus.Up, OperationalStatus.Unknown };
interfaces = NetworkInterface.GetAllNetworkInterfaces()
.Where(i => validStatuses.Contains(i.OperationalStatus))
.ToArray();
}
catch (Exception ex)
{
Logger.LogError(ex, "Error in GetAllNetworkInterfaces");
return null;
}
foreach (NetworkInterface ni in interfaces)
{
if (ni.GetIPProperties().GatewayAddresses.FirstOrDefault() != null)
{
foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
{
if (ip.Address.Equals(ipaddress) && ip.IPv4Mask != null)
{
return ToIpAddressInfo(ip.IPv4Mask);
}
}
}
}
return null;
}
public static IpEndPointInfo ToIpEndPointInfo(IPEndPoint endpoint) public static IpEndPointInfo ToIpEndPointInfo(IPEndPoint endpoint)
{ {
if (endpoint == null) if (endpoint == null)

View File

@ -53,7 +53,7 @@ namespace MediaBrowser.Common.Net
/// <returns><c>true</c> if [is in local network] [the specified endpoint]; otherwise, <c>false</c>.</returns> /// <returns><c>true</c> if [is in local network] [the specified endpoint]; otherwise, <c>false</c>.</returns>
bool IsInLocalNetwork(string endpoint); bool IsInLocalNetwork(string endpoint);
IpAddressInfo[] GetLocalIpAddresses(); IpAddressInfo[] GetLocalIpAddresses(bool ignoreVirtualInterface);
IpAddressInfo ParseIpAddress(string ipAddress); IpAddressInfo ParseIpAddress(string ipAddress);
@ -62,5 +62,8 @@ namespace MediaBrowser.Common.Net
Task<IpAddressInfo[]> GetHostAddressesAsync(string host); Task<IpAddressInfo[]> GetHostAddressesAsync(string host);
bool IsAddressInSubnets(string addressString, string[] subnets); bool IsAddressInSubnets(string addressString, string[] subnets);
bool IsInSameSubnet(IpAddressInfo address1, IpAddressInfo address2, IpAddressInfo subnetMask);
IpAddressInfo GetLocalIpSubnetMask(IpAddressInfo address);
} }
} }

View File

@ -178,6 +178,7 @@ namespace MediaBrowser.Model.Configuration
public string[] LocalNetworkSubnets { get; set; } public string[] LocalNetworkSubnets { get; set; }
public string[] LocalNetworkAddresses { get; set; } public string[] LocalNetworkAddresses { get; set; }
public string[] CodecsUsed { get; set; } public string[] CodecsUsed { get; set; }
public bool IgnoreVirtualInterfaces { get; set; }
public bool EnableExternalContentInSuggestions { get; set; } public bool EnableExternalContentInSuggestions { get; set; }
public bool RequireHttps { get; set; } public bool RequireHttps { get; set; }
public bool IsBehindProxy { get; set; } public bool IsBehindProxy { get; set; }
@ -205,6 +206,7 @@ namespace MediaBrowser.Model.Configuration
CodecsUsed = Array.Empty<string>(); CodecsUsed = Array.Empty<string>();
ImageExtractionTimeoutMs = 0; ImageExtractionTimeoutMs = 0;
PathSubstitutions = Array.Empty<PathSubstitution>(); PathSubstitutions = Array.Empty<PathSubstitution>();
IgnoreVirtualInterfaces = false;
EnableSimpleArtistDetection = true; EnableSimpleArtistDetection = true;
DisplaySpecialsWithinSeasons = true; DisplaySpecialsWithinSeasons = true;

View File

@ -10,6 +10,7 @@ namespace MediaBrowser.Model.Net
public static IpAddressInfo IPv6Loopback = new IpAddressInfo("::1", IpAddressFamily.InterNetworkV6); public static IpAddressInfo IPv6Loopback = new IpAddressInfo("::1", IpAddressFamily.InterNetworkV6);
public string Address { get; set; } public string Address { get; set; }
public IpAddressInfo SubnetMask { get; set; }
public IpAddressFamily AddressFamily { get; set; } public IpAddressFamily AddressFamily { get; set; }
public IpAddressInfo(string address, IpAddressFamily addressFamily) public IpAddressInfo(string address, IpAddressFamily addressFamily)

View File

@ -45,8 +45,8 @@ namespace Rssdp.Infrastructure
/// <summary> /// <summary>
/// Sends a message to the SSDP multicast address and port. /// Sends a message to the SSDP multicast address and port.
/// </summary> /// </summary>
Task SendMulticastMessage(string message, CancellationToken cancellationToken); Task SendMulticastMessage(string message, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken);
Task SendMulticastMessage(string message, int sendCount, CancellationToken cancellationToken); Task SendMulticastMessage(string message, int sendCount, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken);
#endregion #endregion

View File

@ -3,6 +3,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" /> <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" /> <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
<ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>

View File

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Controller.Configuration;
namespace Rssdp.Infrastructure namespace Rssdp.Infrastructure
{ {
@ -45,6 +46,7 @@ namespace Rssdp.Infrastructure
private readonly ILogger _logger; private readonly ILogger _logger;
private ISocketFactory _SocketFactory; private ISocketFactory _SocketFactory;
private readonly INetworkManager _networkManager; private readonly INetworkManager _networkManager;
private readonly IServerConfigurationManager _config;
private int _LocalPort; private int _LocalPort;
private int _MulticastTtl; private int _MulticastTtl;
@ -74,9 +76,11 @@ namespace Rssdp.Infrastructure
/// Minimum constructor. /// Minimum constructor.
/// </summary> /// </summary>
/// <exception cref="ArgumentNullException">The <paramref name="socketFactory"/> argument is null.</exception> /// <exception cref="ArgumentNullException">The <paramref name="socketFactory"/> argument is null.</exception>
public SsdpCommunicationsServer(ISocketFactory socketFactory, INetworkManager networkManager, ILogger logger, bool enableMultiSocketBinding) public SsdpCommunicationsServer(IServerConfigurationManager config, ISocketFactory socketFactory,
INetworkManager networkManager, ILogger logger, bool enableMultiSocketBinding)
: this(socketFactory, 0, SsdpConstants.SsdpDefaultMulticastTimeToLive, networkManager, logger, enableMultiSocketBinding) : this(socketFactory, 0, SsdpConstants.SsdpDefaultMulticastTimeToLive, networkManager, logger, enableMultiSocketBinding)
{ {
_config = config;
} }
/// <summary> /// <summary>
@ -236,15 +240,15 @@ namespace Rssdp.Infrastructure
} }
} }
public Task SendMulticastMessage(string message, CancellationToken cancellationToken) public Task SendMulticastMessage(string message, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
{ {
return SendMulticastMessage(message, SsdpConstants.UdpResendCount, cancellationToken); return SendMulticastMessage(message, SsdpConstants.UdpResendCount, fromLocalIpAddress, cancellationToken);
} }
/// <summary> /// <summary>
/// Sends a message to the SSDP multicast address and port. /// Sends a message to the SSDP multicast address and port.
/// </summary> /// </summary>
public async Task SendMulticastMessage(string message, int sendCount, CancellationToken cancellationToken) public async Task SendMulticastMessage(string message, int sendCount, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
{ {
if (message == null) throw new ArgumentNullException(nameof(message)); if (message == null) throw new ArgumentNullException(nameof(message));
@ -264,7 +268,7 @@ namespace Rssdp.Infrastructure
IpAddress = new IpAddressInfo(SsdpConstants.MulticastLocalAdminAddress, IpAddressFamily.InterNetwork), IpAddress = new IpAddressInfo(SsdpConstants.MulticastLocalAdminAddress, IpAddressFamily.InterNetwork),
Port = SsdpConstants.MulticastPort Port = SsdpConstants.MulticastPort
}, cancellationToken).ConfigureAwait(false); }, fromLocalIpAddress, cancellationToken).ConfigureAwait(false);
await Task.Delay(100, cancellationToken).ConfigureAwait(false); await Task.Delay(100, cancellationToken).ConfigureAwait(false);
} }
@ -332,14 +336,15 @@ namespace Rssdp.Infrastructure
#region Private Methods #region Private Methods
private Task SendMessageIfSocketNotDisposed(byte[] messageData, IpEndPointInfo destination, CancellationToken cancellationToken) private Task SendMessageIfSocketNotDisposed(byte[] messageData, IpEndPointInfo destination, IpAddressInfo fromLocalIpAddress, CancellationToken cancellationToken)
{ {
var sockets = _sendSockets; var sockets = _sendSockets;
if (sockets != null) if (sockets != null)
{ {
sockets = sockets.ToList(); sockets = sockets.ToList();
var tasks = sockets.Select(s => SendFromSocket(s, messageData, destination, cancellationToken)); var tasks = sockets.Where(s => (fromLocalIpAddress == null || fromLocalIpAddress.Equals(s.LocalIPAddress)))
.Select(s => SendFromSocket(s, messageData, destination, cancellationToken));
return Task.WhenAll(tasks); return Task.WhenAll(tasks);
} }
@ -363,11 +368,11 @@ namespace Rssdp.Infrastructure
if (_enableMultiSocketBinding) if (_enableMultiSocketBinding)
{ {
foreach (var address in _networkManager.GetLocalIpAddresses()) foreach (var address in _networkManager.GetLocalIpAddresses(_config.Configuration.IgnoreVirtualInterfaces))
{ {
if (address.AddressFamily == IpAddressFamily.InterNetworkV6) if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
{ {
// Not supported ? // Not support IPv6 right now
continue; continue;
} }

View File

@ -354,7 +354,7 @@ namespace Rssdp.Infrastructure
var message = BuildMessage(header, values); var message = BuildMessage(header, values);
return _CommunicationsServer.SendMulticastMessage(message, cancellationToken); return _CommunicationsServer.SendMulticastMessage(message, null, cancellationToken);
} }
private void ProcessSearchResponseMessage(HttpResponseMessage message, IpAddressInfo localIpAddress) private void ProcessSearchResponseMessage(HttpResponseMessage message, IpAddressInfo localIpAddress)

View File

@ -7,6 +7,7 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Common.Net;
using Rssdp; using Rssdp;
namespace Rssdp.Infrastructure namespace Rssdp.Infrastructure
@ -16,10 +17,12 @@ namespace Rssdp.Infrastructure
/// </summary> /// </summary>
public class SsdpDevicePublisher : DisposableManagedObjectBase, ISsdpDevicePublisher public class SsdpDevicePublisher : DisposableManagedObjectBase, ISsdpDevicePublisher
{ {
private readonly INetworkManager _networkManager;
private ISsdpCommunicationsServer _CommsServer; private ISsdpCommunicationsServer _CommsServer;
private string _OSName; private string _OSName;
private string _OSVersion; private string _OSVersion;
private bool _sendOnlyMatchedHost;
private bool _SupportPnpRootDevice; private bool _SupportPnpRootDevice;
@ -37,9 +40,11 @@ namespace Rssdp.Infrastructure
/// <summary> /// <summary>
/// Default constructor. /// Default constructor.
/// </summary> /// </summary>
public SsdpDevicePublisher(ISsdpCommunicationsServer communicationsServer, string osName, string osVersion) public SsdpDevicePublisher(ISsdpCommunicationsServer communicationsServer, INetworkManager networkManager,
string osName, string osVersion, bool sendOnlyMatchedHost)
{ {
if (communicationsServer == null) throw new ArgumentNullException(nameof(communicationsServer)); if (communicationsServer == null) throw new ArgumentNullException(nameof(communicationsServer));
if (networkManager == null) throw new ArgumentNullException(nameof(networkManager));
if (osName == null) throw new ArgumentNullException(nameof(osName)); if (osName == null) throw new ArgumentNullException(nameof(osName));
if (osName.Length == 0) throw new ArgumentException("osName cannot be an empty string.", nameof(osName)); if (osName.Length == 0) throw new ArgumentException("osName cannot be an empty string.", nameof(osName));
if (osVersion == null) throw new ArgumentNullException(nameof(osVersion)); if (osVersion == null) throw new ArgumentNullException(nameof(osVersion));
@ -51,10 +56,12 @@ namespace Rssdp.Infrastructure
_RecentSearchRequests = new Dictionary<string, SearchRequest>(StringComparer.OrdinalIgnoreCase); _RecentSearchRequests = new Dictionary<string, SearchRequest>(StringComparer.OrdinalIgnoreCase);
_Random = new Random(); _Random = new Random();
_networkManager = networkManager;
_CommsServer = communicationsServer; _CommsServer = communicationsServer;
_CommsServer.RequestReceived += CommsServer_RequestReceived; _CommsServer.RequestReceived += CommsServer_RequestReceived;
_OSName = osName; _OSName = osName;
_OSVersion = osVersion; _OSVersion = osVersion;
_sendOnlyMatchedHost = sendOnlyMatchedHost;
_CommsServer.BeginListeningForBroadcasts(); _CommsServer.BeginListeningForBroadcasts();
} }
@ -249,10 +256,14 @@ namespace Rssdp.Infrastructure
//WriteTrace(String.Format("Sending {0} search responses", deviceList.Count)); //WriteTrace(String.Format("Sending {0} search responses", deviceList.Count));
foreach (var device in deviceList) foreach (var device in deviceList)
{
if (!_sendOnlyMatchedHost ||
_networkManager.IsInSameSubnet(device.ToRootDevice().Address, remoteEndPoint.IpAddress, device.ToRootDevice().SubnetMask))
{ {
SendDeviceSearchResponses(device, remoteEndPoint, receivedOnlocalIpAddress, cancellationToken); SendDeviceSearchResponses(device, remoteEndPoint, receivedOnlocalIpAddress, cancellationToken);
} }
} }
}
else else
{ {
//WriteTrace(String.Format("Sending 0 search responses.")); //WriteTrace(String.Format("Sending 0 search responses."));
@ -427,7 +438,7 @@ namespace Rssdp.Infrastructure
var message = BuildMessage(header, values); var message = BuildMessage(header, values);
_CommsServer.SendMulticastMessage(message, cancellationToken); _CommsServer.SendMulticastMessage(message, _sendOnlyMatchedHost ? rootDevice.Address : null, cancellationToken);
//WriteTrace(String.Format("Sent alive notification"), device); //WriteTrace(String.Format("Sent alive notification"), device);
} }
@ -472,7 +483,7 @@ namespace Rssdp.Infrastructure
var sendCount = IsDisposed ? 1 : 3; var sendCount = IsDisposed ? 1 : 3;
WriteTrace(String.Format("Sent byebye notification"), device); WriteTrace(String.Format("Sent byebye notification"), device);
return _CommsServer.SendMulticastMessage(message, sendCount, cancellationToken); return _CommsServer.SendMulticastMessage(message, sendCount, _sendOnlyMatchedHost ? device.ToRootDevice().Address : null, cancellationToken);
} }
private void DisposeRebroadcastTimer() private void DisposeRebroadcastTimer()

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Text; using System.Text;
using System.Xml; using System.Xml;
using Rssdp.Infrastructure; using Rssdp.Infrastructure;
using MediaBrowser.Model.Net;
namespace Rssdp namespace Rssdp
{ {
@ -52,6 +53,15 @@ namespace Rssdp
/// </summary> /// </summary>
public Uri Location { get; set; } public Uri Location { get; set; }
/// <summary>
/// Gets or sets the Address used to check if the received message from same interface with this device/tree. Required.
/// </summary>
public IpAddressInfo Address { get; set; }
/// <summary>
/// Gets or sets the SubnetMask used to check if the received message from same interface with this device/tree. Required.
/// </summary>
public IpAddressInfo SubnetMask { get; set; }
/// <summary> /// <summary>
/// The base URL to use for all relative url's provided in other propertise (and those of child devices). Optional. /// The base URL to use for all relative url's provided in other propertise (and those of child devices). Optional.