aboutsummaryrefslogtreecommitdiff
path: root/RSSDP/SsdpDeviceLocatorBase.cs
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2017-02-07 02:33:24 -0500
committerLuke Pulverenti <luke.pulverenti@gmail.com>2017-02-07 02:33:24 -0500
commite0d5f7d158cbf8683452474e3afb4d808978b8a2 (patch)
tree620984f012d7715b329d3d793a26102d8176c041 /RSSDP/SsdpDeviceLocatorBase.cs
parent4704d22944f24fd1ab5a312e3d7b1b02be838a10 (diff)
reduce device discovery traffic
Diffstat (limited to 'RSSDP/SsdpDeviceLocatorBase.cs')
-rw-r--r--RSSDP/SsdpDeviceLocatorBase.cs173
1 files changed, 51 insertions, 122 deletions
diff --git a/RSSDP/SsdpDeviceLocatorBase.cs b/RSSDP/SsdpDeviceLocatorBase.cs
index 4f5eae616..1adb95cdf 100644
--- a/RSSDP/SsdpDeviceLocatorBase.cs
+++ b/RSSDP/SsdpDeviceLocatorBase.cs
@@ -24,11 +24,9 @@ namespace Rssdp.Infrastructure
private List<DiscoveredSsdpDevice> _Devices;
private ISsdpCommunicationsServer _CommunicationsServer;
- private IList<DiscoveredSsdpDevice> _SearchResults;
- private object _SearchResultsSynchroniser;
-
- private ITimer _ExpireCachedDevicesTimer;
+ private ITimer _BroadcastTimer;
private ITimerFactory _timerFactory;
+ private object _timerLock = new object();
private static readonly TimeSpan DefaultSearchWaitTime = TimeSpan.FromSeconds(4);
private static readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1);
@@ -48,7 +46,6 @@ namespace Rssdp.Infrastructure
_timerFactory = timerFactory;
_CommunicationsServer.ResponseReceived += CommsServer_ResponseReceived;
- _SearchResultsSynchroniser = new object();
_Devices = new List<DiscoveredSsdpDevice>();
}
@@ -92,11 +89,52 @@ namespace Rssdp.Infrastructure
#region Search Overloads
+ public void RestartBroadcastTimer(TimeSpan dueTime, TimeSpan period)
+ {
+ lock (_timerLock)
+ {
+ if (_BroadcastTimer == null)
+ {
+ _BroadcastTimer = _timerFactory.Create(OnBroadcastTimerCallback, null, dueTime, period);
+ }
+ else
+ {
+ _BroadcastTimer.Change(dueTime, period);
+ }
+ }
+ }
+
+ public void DisposeBroadcastTimer()
+ {
+ lock (_timerLock)
+ {
+ if (_BroadcastTimer != null)
+ {
+ _BroadcastTimer.Dispose();
+ _BroadcastTimer = null;
+ }
+ }
+ }
+
+ private async void OnBroadcastTimerCallback(object state)
+ {
+ StartListeningForNotifications();
+ RemoveExpiredDevicesFromCache();
+
+ try
+ {
+ await SearchAsync(CancellationToken.None).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+
+ }
+ }
+
/// <summary>
/// Performs a search for all devices using the default search timeout.
/// </summary>
- /// <returns>A task whose result is an <see cref="IEnumerable{T}"/> of <see cref="DiscoveredSsdpDevice" /> instances, representing all found devices.</returns>
- public Task<IEnumerable<DiscoveredSsdpDevice>> SearchAsync(CancellationToken cancellationToken)
+ private Task SearchAsync(CancellationToken cancellationToken)
{
return SearchAsync(SsdpConstants.SsdpDiscoverAllSTHeader, DefaultSearchWaitTime, cancellationToken);
}
@@ -111,8 +149,7 @@ namespace Rssdp.Infrastructure
/// <item><term>Device type</term><description>Fully qualified device type starting with urn: i.e urn:schemas-upnp-org:Basic:1</description></item>
/// </list>
/// </param>
- /// <returns>A task whose result is an <see cref="IEnumerable{T}"/> of <see cref="DiscoveredSsdpDevice" /> instances, representing all found devices.</returns>
- public Task<IEnumerable<DiscoveredSsdpDevice>> SearchAsync(string searchTarget)
+ private Task SearchAsync(string searchTarget)
{
return SearchAsync(searchTarget, DefaultSearchWaitTime, CancellationToken.None);
}
@@ -121,13 +158,12 @@ namespace Rssdp.Infrastructure
/// Performs a search for all devices using the specified search timeout.
/// </summary>
/// <param name="searchWaitTime">The amount of time to wait for network responses to the search request. Longer values will likely return more devices, but increase search time. A value between 1 and 5 seconds is recommended by the UPnP 1.1 specification, this method requires the value be greater 1 second if it is not zero. Specify TimeSpan.Zero to return only devices already in the cache.</param>
- /// <returns>A task whose result is an <see cref="IEnumerable{T}"/> of <see cref="DiscoveredSsdpDevice" /> instances, representing all found devices.</returns>
- public Task<IEnumerable<DiscoveredSsdpDevice>> SearchAsync(TimeSpan searchWaitTime)
+ private Task SearchAsync(TimeSpan searchWaitTime)
{
return SearchAsync(SsdpConstants.SsdpDiscoverAllSTHeader, searchWaitTime, CancellationToken.None);
}
- public async Task<IEnumerable<DiscoveredSsdpDevice>> SearchAsync(string searchTarget, TimeSpan searchWaitTime, CancellationToken cancellationToken)
+ private Task SearchAsync(string searchTarget, TimeSpan searchWaitTime, CancellationToken cancellationToken)
{
if (searchTarget == null) throw new ArgumentNullException("searchTarget");
if (searchTarget.Length == 0) throw new ArgumentException("searchTarget cannot be an empty string.", "searchTarget");
@@ -136,48 +172,7 @@ namespace Rssdp.Infrastructure
ThrowIfDisposed();
- if (_SearchResults != null) throw new InvalidOperationException("Search already in progress. Only one search at a time is allowed.");
- _SearchResults = new List<DiscoveredSsdpDevice>();
-
- // If searchWaitTime == 0 then we are only going to report unexpired cached items, not actually do a search.
- if (searchWaitTime > TimeSpan.Zero)
- await BroadcastDiscoverMessage(searchTarget, SearchTimeToMXValue(searchWaitTime), cancellationToken).ConfigureAwait(false);
-
- lock (_SearchResultsSynchroniser)
- {
- foreach (var device in GetUnexpiredDevices().Where(NotificationTypeMatchesFilter))
- {
- DeviceFound(device, false, null);
- }
- }
-
- if (searchWaitTime != TimeSpan.Zero)
- await Task.Delay(searchWaitTime, cancellationToken).ConfigureAwait(false);
-
- IEnumerable<DiscoveredSsdpDevice> retVal = null;
-
- try
- {
- lock (_SearchResultsSynchroniser)
- {
- retVal = _SearchResults;
- _SearchResults = null;
- }
-
- RemoveExpiredDevicesFromCache();
- }
- finally
- {
- var server = _CommunicationsServer;
- try
- {
- if (server != null) // In case we were disposed while searching.
- server.StopListeningForResponses();
- }
- catch (ObjectDisposedException) { }
- }
-
- return retVal;
+ return BroadcastDiscoverMessage(searchTarget, SearchTimeToMXValue(searchWaitTime), cancellationToken);
}
#endregion
@@ -287,9 +282,7 @@ namespace Rssdp.Infrastructure
if (disposing)
{
- var timer = _ExpireCachedDevicesTimer;
- if (timer != null)
- timer.Dispose();
+ DisposeBroadcastTimer();
var commsServer = _CommunicationsServer;
_CommunicationsServer = null;
@@ -332,40 +325,9 @@ namespace Rssdp.Infrastructure
private void DeviceFound(DiscoveredSsdpDevice device, bool isNewDevice, IpAddressInfo localIpAddress)
{
- // Don't raise the event if we've already done it for a cached
- // version of this device, and the cached version isn't
- // "significantly" different, i.e location and cachelifetime
- // haven't changed.
- var raiseEvent = false;
-
if (!NotificationTypeMatchesFilter(device)) return;
- lock (_SearchResultsSynchroniser)
- {
- if (_SearchResults != null)
- {
- var existingDevice = FindExistingDeviceNotification(_SearchResults, device.NotificationType, device.Usn);
- if (existingDevice == null)
- {
- _SearchResults.Add(device);
- raiseEvent = true;
- }
- else
- {
- if (existingDevice.DescriptionLocation != device.DescriptionLocation || existingDevice.CacheLifetime != device.CacheLifetime)
- {
- _SearchResults.Remove(existingDevice);
- _SearchResults.Add(device);
- raiseEvent = true;
- }
- }
- }
- else
- raiseEvent = true;
- }
-
- if (raiseEvent)
- OnDeviceAvailable(device, isNewDevice, localIpAddress);
+ OnDeviceAvailable(device, isNewDevice, localIpAddress);
}
private bool NotificationTypeMatchesFilter(DiscoveredSsdpDevice device)
@@ -450,8 +412,6 @@ namespace Rssdp.Infrastructure
};
AddOrUpdateDiscoveredDevice(device, localIpAddress);
-
- ResetExpireCachedDevicesTimer();
}
}
@@ -477,26 +437,9 @@ namespace Rssdp.Infrastructure
if (NotificationTypeMatchesFilter(deadDevice))
OnDeviceUnavailable(deadDevice, false);
}
-
- ResetExpireCachedDevicesTimer();
}
}
- private void ResetExpireCachedDevicesTimer()
- {
- if (IsDisposed) return;
-
- if (_ExpireCachedDevicesTimer == null)
- _ExpireCachedDevicesTimer = _timerFactory.Create(this.ExpireCachedDevices, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
-
- _ExpireCachedDevicesTimer.Change(60000, System.Threading.Timeout.Infinite);
- }
-
- private void ExpireCachedDevices(object state)
- {
- RemoveExpiredDevicesFromCache();
- }
-
#region Header/Message Processing Utilities
private static string GetFirstHeaderStringValue(string headerName, HttpResponseMessage message)
@@ -624,20 +567,6 @@ namespace Rssdp.Infrastructure
if (existingDevices != null && existingDevices.Any())
{
- lock (_SearchResultsSynchroniser)
- {
- if (_SearchResults != null)
- {
- var resultsToRemove = (from result in _SearchResults where result.Usn == deviceUsn select result).ToArray();
- foreach (var result in resultsToRemove)
- {
- if (this.IsDisposed) return true;
-
- _SearchResults.Remove(result);
- }
- }
- }
-
foreach (var removedDevice in existingDevices)
{
if (NotificationTypeMatchesFilter(removedDevice))