diff options
Diffstat (limited to 'RSSDP/SsdpDevicePublisher.cs')
| -rw-r--r-- | RSSDP/SsdpDevicePublisher.cs | 142 |
1 files changed, 54 insertions, 88 deletions
diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs index c9e795d56..950e6fec8 100644 --- a/RSSDP/SsdpDevicePublisher.cs +++ b/RSSDP/SsdpDevicePublisher.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Globalization; using System.Linq; using System.Net; +using System.Text; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Net; namespace Rssdp.Infrastructure { @@ -14,8 +15,6 @@ namespace Rssdp.Infrastructure /// </summary> public class SsdpDevicePublisher : DisposableManagedObjectBase, ISsdpDevicePublisher { - private readonly INetworkManager _networkManager; - private ISsdpCommunicationsServer _CommsServer; private string _OSName; private string _OSVersion; @@ -32,43 +31,18 @@ namespace Rssdp.Infrastructure private Random _Random; - private const string ServerVersion = "1.0"; - /// <summary> /// Default constructor. /// </summary> - public SsdpDevicePublisher(ISsdpCommunicationsServer communicationsServer, INetworkManager networkManager, - string osName, string osVersion, bool sendOnlyMatchedHost) + public SsdpDevicePublisher( + ISsdpCommunicationsServer communicationsServer, + string osName, + string osVersion, + bool sendOnlyMatchedHost) { - 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.Length == 0) - { - throw new ArgumentException("osName cannot be an empty string.", nameof(osName)); - } - - if (osVersion == null) - { - throw new ArgumentNullException(nameof(osVersion)); - } - - if (osVersion.Length == 0) - { - throw new ArgumentException("osVersion cannot be an empty string.", nameof(osName)); - } + ArgumentNullException.ThrowIfNull(communicationsServer); + ArgumentNullException.ThrowIfNullOrEmpty(osName); + ArgumentNullException.ThrowIfNullOrEmpty(osVersion); _SupportPnpRootDevice = true; _Devices = new List<SsdpRootDevice>(); @@ -76,17 +50,19 @@ namespace Rssdp.Infrastructure _RecentSearchRequests = new Dictionary<string, SearchRequest>(StringComparer.OrdinalIgnoreCase); _Random = new Random(); - _networkManager = networkManager; _CommsServer = communicationsServer; _CommsServer.RequestReceived += CommsServer_RequestReceived; _OSName = osName; _OSVersion = osVersion; _sendOnlyMatchedHost = sendOnlyMatchedHost; - _CommsServer.BeginListeningForBroadcasts(); + _CommsServer.BeginListeningForMulticast(); + + // Send alive notification once on creation + SendAllAliveNotifications(null); } - public void StartBroadcastingAliveMessages(TimeSpan interval) + public void StartSendingAliveNotifications(TimeSpan interval) { _RebroadcastAliveNotificationsTimer = new Timer(SendAllAliveNotifications, null, TimeSpan.FromSeconds(5), interval); } @@ -102,10 +78,9 @@ namespace Rssdp.Infrastructure /// <param name="device">The <see cref="SsdpDevice"/> instance to add.</param> /// <exception cref="ArgumentNullException">Thrown if the <paramref name="device"/> argument is null.</exception> /// <exception cref="InvalidOperationException">Thrown if the <paramref name="device"/> contains property values that are not acceptable to the UPnP 1.0 specification.</exception> - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "t", Justification = "Capture task to local variable suppresses compiler warning, but task is not really needed.")] public void AddDevice(SsdpRootDevice device) { - if (device == null) + if (device is null) { throw new ArgumentNullException(nameof(device)); } @@ -141,7 +116,7 @@ namespace Rssdp.Infrastructure /// <exception cref="ArgumentNullException">Thrown if the <paramref name="device"/> argument is null.</exception> public async Task RemoveDevice(SsdpRootDevice device) { - if (device == null) + if (device is null) { throw new ArgumentNullException(nameof(device)); } @@ -203,7 +178,7 @@ namespace Rssdp.Infrastructure DisposeRebroadcastTimer(); var commsServer = _CommsServer; - if (commsServer != null) + if (commsServer is not null) { commsServer.RequestReceived -= this.CommsServer_RequestReceived; } @@ -212,7 +187,7 @@ namespace Rssdp.Infrastructure Task.WaitAll(tasks); _CommsServer = null; - if (commsServer != null) + if (commsServer is not null) { if (!commsServer.IsShared) { @@ -228,12 +203,12 @@ namespace Rssdp.Infrastructure string mx, string searchTarget, IPEndPoint remoteEndPoint, - IPAddress receivedOnlocalIpAddress, + IPAddress receivedOnlocalIPAddress, CancellationToken cancellationToken) { if (String.IsNullOrEmpty(searchTarget)) { - WriteTrace(String.Format("Invalid search request received From {0}, Target is null/empty.", remoteEndPoint.ToString())); + WriteTrace(String.Format(CultureInfo.InvariantCulture, "Invalid search request received From {0}, Target is null/empty.", remoteEndPoint.ToString())); return; } @@ -248,7 +223,6 @@ namespace Rssdp.Infrastructure // Wait on random interval up to MX, as per SSDP spec. // Also, as per UPnP 1.1/SSDP spec ignore missing/bank MX header. If over 120, assume random value between 0 and 120. // Using 16 as minimum as that's often the minimum system clock frequency anyway. - int maxWaitInterval = 0; if (String.IsNullOrEmpty(mx)) { // Windows Explorer is poorly behaved and doesn't supply an MX header value. @@ -258,7 +232,7 @@ namespace Rssdp.Infrastructure // return; } - if (!Int32.TryParse(mx, out maxWaitInterval) || maxWaitInterval <= 0) + if (!Int32.TryParse(mx, out var maxWaitInterval) || maxWaitInterval <= 0) { return; } @@ -285,27 +259,25 @@ namespace Rssdp.Infrastructure } else if (searchTarget.Trim().StartsWith("uuid:", StringComparison.OrdinalIgnoreCase)) { - devices = (from device in GetAllDevicesAsFlatEnumerable() where String.Compare(device.Uuid, searchTarget.Substring(5), StringComparison.OrdinalIgnoreCase) == 0 select device).ToArray(); + devices = GetAllDevicesAsFlatEnumerable().Where(d => String.Compare(d.Uuid, searchTarget.Substring(5), StringComparison.OrdinalIgnoreCase) == 0).ToArray(); } else if (searchTarget.StartsWith("urn:", StringComparison.OrdinalIgnoreCase)) { - devices = (from device in GetAllDevicesAsFlatEnumerable() where String.Compare(device.FullDeviceType, searchTarget, StringComparison.OrdinalIgnoreCase) == 0 select device).ToArray(); + devices = GetAllDevicesAsFlatEnumerable().Where(d => String.Compare(d.FullDeviceType, searchTarget, StringComparison.OrdinalIgnoreCase) == 0).ToArray(); } } - if (devices != null) + if (devices is not null) { - var deviceList = devices.ToList(); // WriteTrace(String.Format("Sending {0} search responses", deviceList.Count)); - foreach (var device in deviceList) + foreach (var device in devices) { var root = device.ToRootDevice(); - var source = new IPNetAddress(root.Address, root.PrefixLength); - var destination = new IPNetAddress(remoteEndPoint.Address, root.PrefixLength); - if (!_sendOnlyMatchedHost || source.NetworkAddress.Equals(destination.NetworkAddress)) + + if (!_sendOnlyMatchedHost || root.Address.Equals(receivedOnlocalIPAddress)) { - SendDeviceSearchResponses(device, remoteEndPoint, receivedOnlocalIpAddress, cancellationToken); + SendDeviceSearchResponses(device, remoteEndPoint, receivedOnlocalIPAddress, cancellationToken); } } } @@ -320,27 +292,27 @@ namespace Rssdp.Infrastructure private void SendDeviceSearchResponses( SsdpDevice device, IPEndPoint endPoint, - IPAddress receivedOnlocalIpAddress, + IPAddress receivedOnlocalIPAddress, CancellationToken cancellationToken) { - bool isRootDevice = (device as SsdpRootDevice) != null; + bool isRootDevice = (device as SsdpRootDevice) is not null; if (isRootDevice) { - SendSearchResponse(SsdpConstants.UpnpDeviceTypeRootDevice, device, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice), endPoint, receivedOnlocalIpAddress, cancellationToken); + SendSearchResponse(SsdpConstants.UpnpDeviceTypeRootDevice, device, GetUsn(device.Udn, SsdpConstants.UpnpDeviceTypeRootDevice), endPoint, receivedOnlocalIPAddress, cancellationToken); if (this.SupportPnpRootDevice) { - SendSearchResponse(SsdpConstants.PnpDeviceTypeRootDevice, device, GetUsn(device.Udn, SsdpConstants.PnpDeviceTypeRootDevice), endPoint, receivedOnlocalIpAddress, cancellationToken); + SendSearchResponse(SsdpConstants.PnpDeviceTypeRootDevice, device, GetUsn(device.Udn, SsdpConstants.PnpDeviceTypeRootDevice), endPoint, receivedOnlocalIPAddress, cancellationToken); } } - SendSearchResponse(device.Udn, device, device.Udn, endPoint, receivedOnlocalIpAddress, cancellationToken); + SendSearchResponse(device.Udn, device, device.Udn, endPoint, receivedOnlocalIPAddress, cancellationToken); - SendSearchResponse(device.FullDeviceType, device, GetUsn(device.Udn, device.FullDeviceType), endPoint, receivedOnlocalIpAddress, cancellationToken); + SendSearchResponse(device.FullDeviceType, device, GetUsn(device.Udn, device.FullDeviceType), endPoint, receivedOnlocalIPAddress, cancellationToken); } private string GetUsn(string udn, string fullDeviceType) { - return String.Format("{0}::{1}", udn, fullDeviceType); + return String.Format(CultureInfo.InvariantCulture, "{0}::{1}", udn, fullDeviceType); } private async void SendSearchResponse( @@ -348,22 +320,20 @@ namespace Rssdp.Infrastructure SsdpDevice device, string uniqueServiceName, IPEndPoint endPoint, - IPAddress receivedOnlocalIpAddress, + IPAddress receivedOnlocalIPAddress, CancellationToken cancellationToken) { - var rootDevice = device.ToRootDevice(); - - // var additionalheaders = FormatCustomHeadersForResponse(device); - const string header = "HTTP/1.1 200 OK"; + var rootDevice = device.ToRootDevice(); var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); values["EXT"] = ""; values["DATE"] = DateTime.UtcNow.ToString("r"); + values["HOST"] = "239.255.255.250:1900"; values["CACHE-CONTROL"] = "max-age = " + rootDevice.CacheLifetime.TotalSeconds; values["ST"] = searchTarget; - values["SERVER"] = string.Format("{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); + values["SERVER"] = string.Format(CultureInfo.InvariantCulture, "{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, SsdpConstants.ServerVersion); values["USN"] = uniqueServiceName; values["LOCATION"] = rootDevice.Location.ToString(); @@ -372,9 +342,9 @@ namespace Rssdp.Infrastructure try { await _CommsServer.SendMessage( - System.Text.Encoding.UTF8.GetBytes(message), + Encoding.UTF8.GetBytes(message), endPoint, - receivedOnlocalIpAddress, + receivedOnlocalIPAddress, cancellationToken) .ConfigureAwait(false); } @@ -497,7 +467,7 @@ namespace Rssdp.Infrastructure values["DATE"] = DateTime.UtcNow.ToString("r"); values["CACHE-CONTROL"] = "max-age = " + rootDevice.CacheLifetime.TotalSeconds; values["LOCATION"] = rootDevice.Location.ToString(); - values["SERVER"] = string.Format("{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); + values["SERVER"] = string.Format(CultureInfo.InvariantCulture, "{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, SsdpConstants.ServerVersion); values["NTS"] = "ssdp:alive"; values["NT"] = notificationType; values["USN"] = uniqueServiceName; @@ -522,7 +492,7 @@ namespace Rssdp.Infrastructure } tasks.Add(SendByeByeNotification(device, device.Udn, device.Udn, cancellationToken)); - tasks.Add(SendByeByeNotification(device, String.Format("urn:{0}", device.FullDeviceType), GetUsn(device.Udn, device.FullDeviceType), cancellationToken)); + tasks.Add(SendByeByeNotification(device, String.Format(CultureInfo.InvariantCulture, "urn:{0}", device.FullDeviceType), GetUsn(device.Udn, device.FullDeviceType), cancellationToken)); foreach (var childDevice in device.Devices) { @@ -532,7 +502,6 @@ namespace Rssdp.Infrastructure return Task.WhenAll(tasks); } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "byebye", Justification = "Correct value for this type of notification in SSDP.")] private Task SendByeByeNotification(SsdpDevice device, string notificationType, string uniqueServiceName, CancellationToken cancellationToken) { const string header = "NOTIFY * HTTP/1.1"; @@ -542,7 +511,7 @@ namespace Rssdp.Infrastructure // If needed later for non-server devices, these headers will need to be dynamic values["HOST"] = "239.255.255.250:1900"; values["DATE"] = DateTime.UtcNow.ToString("r"); - values["SERVER"] = string.Format("{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); + values["SERVER"] = string.Format(CultureInfo.InvariantCulture, "{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, SsdpConstants.ServerVersion); values["NTS"] = "ssdp:byebye"; values["NT"] = notificationType; values["USN"] = uniqueServiceName; @@ -550,7 +519,7 @@ namespace Rssdp.Infrastructure var message = BuildMessage(header, values); var sendCount = IsDisposed ? 1 : 3; - WriteTrace(String.Format("Sent byebye notification"), device); + WriteTrace(String.Format(CultureInfo.InvariantCulture, "Sent byebye notification"), device); return _CommsServer.SendMulticastMessage(message, sendCount, _sendOnlyMatchedHost ? device.ToRootDevice().Address : null, cancellationToken); } @@ -558,7 +527,7 @@ namespace Rssdp.Infrastructure { var timer = _RebroadcastAliveNotificationsTimer; _RebroadcastAliveNotificationsTimer = null; - if (timer != null) + if (timer is not null) { timer.Dispose(); } @@ -576,17 +545,14 @@ namespace Rssdp.Infrastructure { return nonzeroCacheLifetimesQuery.Min(); } - else - { - return TimeSpan.Zero; - } + + return TimeSpan.Zero; } private string GetFirstHeaderValue(System.Net.Http.Headers.HttpRequestHeaders httpRequestHeaders, string headerName) { string retVal = null; - IEnumerable<String> values = null; - if (httpRequestHeaders.TryGetValues(headerName, out values) && values != null) + if (httpRequestHeaders.TryGetValues(headerName, out var values) && values is not null) { retVal = values.FirstOrDefault(); } @@ -598,7 +564,7 @@ namespace Rssdp.Infrastructure private void WriteTrace(string text) { - if (LogFunction != null) + if (LogFunction is not null) { LogFunction(text); } @@ -608,7 +574,7 @@ namespace Rssdp.Infrastructure private void WriteTrace(string text, SsdpDevice device) { var rootDevice = device as SsdpRootDevice; - if (rootDevice != null) + if (rootDevice is not null) { WriteTrace(text + " " + device.DeviceType + " - " + device.Uuid + " - " + rootDevice.Location); } @@ -634,7 +600,7 @@ namespace Rssdp.Infrastructure // else if (!e.Message.Headers.Contains("MAN")) // WriteTrace("Ignoring search request - missing MAN header."); // else - ProcessSearchRequest(GetFirstHeaderValue(e.Message.Headers, "MX"), GetFirstHeaderValue(e.Message.Headers, "ST"), e.ReceivedFrom, e.LocalIpAddress, CancellationToken.None); + ProcessSearchRequest(GetFirstHeaderValue(e.Message.Headers, "MX"), GetFirstHeaderValue(e.Message.Headers, "ST"), e.ReceivedFrom, e.LocalIPAddress, CancellationToken.None); } } @@ -648,7 +614,7 @@ namespace Rssdp.Infrastructure public string Key { - get { return this.SearchTarget + ":" + this.EndPoint.ToString(); } + get { return this.SearchTarget + ":" + this.EndPoint; } } public bool IsOld() |
