Merge branch 'master' into SSDP

This commit is contained in:
Cody Robibero
2020-06-20 15:33:13 -06:00
committed by GitHub
1243 changed files with 27665 additions and 13122 deletions

View File

@@ -13,9 +13,6 @@ namespace Rssdp.Infrastructure
/// </summary>
public class SsdpDeviceLocator : DisposableManagedObjectBase
{
#region Fields & Constants
private List<DiscoveredSsdpDevice> _Devices;
private ISsdpCommunicationsServer _CommunicationsServer;
@@ -25,16 +22,15 @@ namespace Rssdp.Infrastructure
private readonly TimeSpan DefaultSearchWaitTime = TimeSpan.FromSeconds(4);
private readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1);
#endregion
#region Constructors
/// <summary>
/// Default constructor.
/// </summary>
public SsdpDeviceLocator(ISsdpCommunicationsServer communicationsServer)
{
if (communicationsServer == null) throw new ArgumentNullException(nameof(communicationsServer));
if (communicationsServer == null)
{
throw new ArgumentNullException(nameof(communicationsServer));
}
_CommunicationsServer = communicationsServer;
_CommunicationsServer.ResponseReceived += CommsServer_ResponseReceived;
@@ -42,10 +38,6 @@ namespace Rssdp.Infrastructure
_Devices = new List<DiscoveredSsdpDevice>();
}
#endregion
#region Events
/// <summary>
/// Raised for when
/// <list type="bullet">
@@ -76,12 +68,6 @@ namespace Rssdp.Infrastructure
/// <seealso cref="StopListeningForNotifications"/>
public event EventHandler<DeviceUnavailableEventArgs> DeviceUnavailable;
#endregion
#region Public Methods
#region Search Overloads
public void RestartBroadcastTimer(TimeSpan dueTime, TimeSpan period)
{
lock (_timerLock)
@@ -120,7 +106,6 @@ namespace Rssdp.Infrastructure
}
catch (Exception)
{
}
}
@@ -158,18 +143,31 @@ namespace Rssdp.Infrastructure
private Task SearchAsync(string searchTarget, TimeSpan searchWaitTime, CancellationToken cancellationToken)
{
if (searchTarget == null) throw new ArgumentNullException(nameof(searchTarget));
if (searchTarget.Length == 0) throw new ArgumentException("searchTarget cannot be an empty string.", nameof(searchTarget));
if (searchWaitTime.TotalSeconds < 0) throw new ArgumentException("searchWaitTime must be a positive time.");
if (searchWaitTime.TotalSeconds > 0 && searchWaitTime.TotalSeconds <= 1) throw new ArgumentException("searchWaitTime must be zero (if you are not using the result and relying entirely in the events), or greater than one second.");
if (searchTarget == null)
{
throw new ArgumentNullException(nameof(searchTarget));
}
if (searchTarget.Length == 0)
{
throw new ArgumentException("searchTarget cannot be an empty string.", nameof(searchTarget));
}
if (searchWaitTime.TotalSeconds < 0)
{
throw new ArgumentException("searchWaitTime must be a positive time.");
}
if (searchWaitTime.TotalSeconds > 0 && searchWaitTime.TotalSeconds <= 1)
{
throw new ArgumentException("searchWaitTime must be zero (if you are not using the result and relying entirely in the events), or greater than one second.");
}
ThrowIfDisposed();
return BroadcastDiscoverMessage(searchTarget, SearchTimeToMXValue(searchWaitTime), cancellationToken);
}
#endregion
/// <summary>
/// Starts listening for broadcast notifications of service availability.
/// </summary>
@@ -212,14 +210,19 @@ namespace Rssdp.Infrastructure
/// <seealso cref="DeviceAvailable"/>
protected virtual void OnDeviceAvailable(DiscoveredSsdpDevice device, bool isNewDevice, IPAddress localIpAddress)
{
if (this.IsDisposed) return;
if (this.IsDisposed)
{
return;
}
var handlers = this.DeviceAvailable;
if (handlers != null)
{
handlers(this, new DeviceAvailableEventArgs(device, isNewDevice)
{
LocalIpAddress = localIpAddress
});
}
}
/// <summary>
@@ -230,17 +233,18 @@ namespace Rssdp.Infrastructure
/// <seealso cref="DeviceUnavailable"/>
protected virtual void OnDeviceUnavailable(DiscoveredSsdpDevice device, bool expired)
{
if (this.IsDisposed) return;
if (this.IsDisposed)
{
return;
}
var handlers = this.DeviceUnavailable;
if (handlers != null)
{
handlers(this, new DeviceUnavailableEventArgs(device, expired));
}
}
#endregion
#region Public Properties
/// <summary>
/// Sets or returns a string containing the filter for notifications. Notifications not matching the filter will not raise the <see cref="ISsdpDeviceLocator.DeviceAvailable"/> or <see cref="ISsdpDeviceLocator.DeviceUnavailable"/> events.
/// </summary>
@@ -262,10 +266,6 @@ namespace Rssdp.Infrastructure
set;
}
#endregion
#region Overrides
/// <summary>
/// Disposes this object and all internal resources. Stops listening for all network messages.
/// </summary>
@@ -286,12 +286,6 @@ namespace Rssdp.Infrastructure
}
}
#endregion
#region Private Methods
#region Discovery/Device Add
private void AddOrUpdateDiscoveredDevice(DiscoveredSsdpDevice device, IPAddress localIpAddress)
{
bool isNewDevice = false;
@@ -315,7 +309,10 @@ namespace Rssdp.Infrastructure
private void DeviceFound(DiscoveredSsdpDevice device, bool isNewDevice, IPAddress localIpAddress)
{
if (!NotificationTypeMatchesFilter(device)) return;
if (!NotificationTypeMatchesFilter(device))
{
return;
}
OnDeviceAvailable(device, isNewDevice, localIpAddress);
}
@@ -327,17 +324,13 @@ namespace Rssdp.Infrastructure
|| device.NotificationType == this.NotificationFilter;
}
#endregion
#region Network Message Processing
private Task BroadcastDiscoverMessage(string serviceType, TimeSpan mxValue, CancellationToken cancellationToken)
{
var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
values["HOST"] = "239.255.255.250:1900";
values["USER-AGENT"] = "UPnP/1.0 DLNADOC/1.50 Platinum/1.0.4.2";
//values["X-EMBY-SERVERID"] = _appHost.SystemId;
// values["X-EMBY-SERVERID"] = _appHost.SystemId;
values["MAN"] = "\"ssdp:discover\"";
@@ -356,7 +349,10 @@ namespace Rssdp.Infrastructure
private void ProcessSearchResponseMessage(HttpResponseMessage message, IPAddress localIpAddress)
{
if (!message.IsSuccessStatusCode) return;
if (!message.IsSuccessStatusCode)
{
return;
}
var location = GetFirstHeaderUriValue("Location", message);
if (location != null)
@@ -377,13 +373,20 @@ namespace Rssdp.Infrastructure
private void ProcessNotificationMessage(HttpRequestMessage message, IPAddress localIpAddress)
{
if (String.Compare(message.Method.Method, "Notify", StringComparison.OrdinalIgnoreCase) != 0) return;
if (String.Compare(message.Method.Method, "Notify", StringComparison.OrdinalIgnoreCase) != 0)
{
return;
}
var notificationType = GetFirstHeaderStringValue("NTS", message);
if (String.Compare(notificationType, SsdpConstants.SsdpKeepAliveNotification, StringComparison.OrdinalIgnoreCase) == 0)
{
ProcessAliveNotification(message, localIpAddress);
}
else if (String.Compare(notificationType, SsdpConstants.SsdpByeByeNotification, StringComparison.OrdinalIgnoreCase) == 0)
{
ProcessByeByeNotification(message);
}
}
private void ProcessAliveNotification(HttpRequestMessage message, IPAddress localIpAddress)
@@ -425,13 +428,13 @@ namespace Rssdp.Infrastructure
};
if (NotificationTypeMatchesFilter(deadDevice))
{
OnDeviceUnavailable(deadDevice, false);
}
}
}
}
#region Header/Message Processing Utilities
private string GetFirstHeaderStringValue(string headerName, HttpResponseMessage message)
{
string retVal = null;
@@ -440,7 +443,9 @@ namespace Rssdp.Infrastructure
{
message.Headers.TryGetValues(headerName, out values);
if (values != null)
{
retVal = values.FirstOrDefault();
}
}
return retVal;
@@ -454,7 +459,9 @@ namespace Rssdp.Infrastructure
{
message.Headers.TryGetValues(headerName, out values);
if (values != null)
{
retVal = values.FirstOrDefault();
}
}
return retVal;
@@ -468,7 +475,9 @@ namespace Rssdp.Infrastructure
{
request.Headers.TryGetValues(headerName, out values);
if (values != null)
{
value = values.FirstOrDefault();
}
}
Uri retVal;
@@ -484,7 +493,9 @@ namespace Rssdp.Infrastructure
{
response.Headers.TryGetValues(headerName, out values);
if (values != null)
{
value = values.FirstOrDefault();
}
}
Uri retVal;
@@ -494,20 +505,20 @@ namespace Rssdp.Infrastructure
private TimeSpan CacheAgeFromHeader(System.Net.Http.Headers.CacheControlHeaderValue headerValue)
{
if (headerValue == null) return TimeSpan.Zero;
if (headerValue == null)
{
return TimeSpan.Zero;
}
return (TimeSpan)(headerValue.MaxAge ?? headerValue.SharedMaxAge ?? TimeSpan.Zero);
}
#endregion
#endregion
#region Expiry and Device Removal
private void RemoveExpiredDevicesFromCache()
{
if (this.IsDisposed) return;
if (this.IsDisposed)
{
return;
}
DiscoveredSsdpDevice[] expiredDevices = null;
lock (_Devices)
@@ -516,7 +527,10 @@ namespace Rssdp.Infrastructure
foreach (var device in expiredDevices)
{
if (this.IsDisposed) return;
if (this.IsDisposed)
{
return;
}
_Devices.Remove(device);
}
@@ -527,7 +541,10 @@ namespace Rssdp.Infrastructure
// problems.
foreach (var expiredUsn in (from expiredDevice in expiredDevices select expiredDevice.Usn).Distinct())
{
if (this.IsDisposed) return;
if (this.IsDisposed)
{
return;
}
DeviceDied(expiredUsn, true);
}
@@ -541,7 +558,10 @@ namespace Rssdp.Infrastructure
existingDevices = FindExistingDeviceNotifications(_Devices, deviceUsn);
foreach (var existingDevice in existingDevices)
{
if (this.IsDisposed) return true;
if (this.IsDisposed)
{
return true;
}
_Devices.Remove(existingDevice);
}
@@ -552,7 +572,9 @@ namespace Rssdp.Infrastructure
foreach (var removedDevice in existingDevices)
{
if (NotificationTypeMatchesFilter(removedDevice))
{
OnDeviceUnavailable(removedDevice, expired);
}
}
return true;
@@ -561,14 +583,16 @@ namespace Rssdp.Infrastructure
return false;
}
#endregion
private TimeSpan SearchTimeToMXValue(TimeSpan searchWaitTime)
{
if (searchWaitTime.TotalSeconds < 2 || searchWaitTime == TimeSpan.Zero)
{
return OneSecond;
}
else
{
return searchWaitTime.Subtract(OneSecond);
}
}
private DiscoveredSsdpDevice FindExistingDeviceNotification(IEnumerable<DiscoveredSsdpDevice> devices, string notificationType, string usn)
@@ -580,6 +604,7 @@ namespace Rssdp.Infrastructure
return d;
}
}
return null;
}
@@ -598,10 +623,6 @@ namespace Rssdp.Infrastructure
return list;
}
#endregion
#region Event Handlers
private void CommsServer_ResponseReceived(object sender, ResponseReceivedEventArgs e)
{
ProcessSearchResponseMessage(e.Message, e.LocalIpAddress);
@@ -611,8 +632,5 @@ namespace Rssdp.Infrastructure
{
ProcessNotificationMessage(e.Message, e.LocalIpAddress);
}
#endregion
}
}