update msearch
This commit is contained in:
parent
c2e9df41dc
commit
180ab02edc
|
@ -51,8 +51,7 @@ namespace Rssdp.Infrastructure
|
|||
/// <summary>
|
||||
/// Sends a message to the SSDP multicast address and port.
|
||||
/// </summary>
|
||||
/// <param name="messageData">A byte array containing the data to send.</param>
|
||||
Task SendMulticastMessage(byte[] messageData);
|
||||
Task SendMulticastMessage(string message);
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
<Compile Include="SsdpDevicePublisher.cs" />
|
||||
<Compile Include="SsdpDevicePublisherBase.cs" />
|
||||
<Compile Include="SsdpEmbeddedDevice.cs" />
|
||||
<Compile Include="SsdpHelper.cs" />
|
||||
<Compile Include="SsdpRootDevice.cs" />
|
||||
<Compile Include="UPnP10DeviceValidator.cs" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Rssdp
|
|||
/// Default constructor. Constructs a new instance using the default <see cref="ISsdpCommunicationsServer"/> and <see cref="ISocketFactory"/> implementations for this platform.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification="Can't expose along exception paths here (exceptions should be very rare anyway, and probably fatal too) and we shouldn't dipose the items we pass to base in any other case.")]
|
||||
public SsdpDeviceLocator(ISocketFactory socketFactory, ITimerFactory timerFacatory) : base(new SsdpCommunicationsServer(socketFactory), timerFacatory)
|
||||
public SsdpDeviceLocator(ISsdpCommunicationsServer communicationsServer, ITimerFactory timerFacatory) : base(communicationsServer, timerFacatory)
|
||||
{
|
||||
// This is not the problem you are looking for;
|
||||
// Yes, this is poor man's dependency injection which some call an anti-pattern.
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using RSSDP;
|
||||
|
||||
namespace Rssdp.Infrastructure
|
||||
{
|
||||
|
@ -28,14 +29,6 @@ namespace Rssdp.Infrastructure
|
|||
private ITimer _ExpireCachedDevicesTimer;
|
||||
private ITimerFactory _timerFactory;
|
||||
|
||||
private const string HttpURequestMessageFormat = @"{0} * HTTP/1.1
|
||||
HOST: {1}:{2}
|
||||
MAN: ""{3}""
|
||||
MX: {5}
|
||||
ST: {4}
|
||||
|
||||
";
|
||||
|
||||
private static readonly TimeSpan DefaultSearchWaitTime = TimeSpan.FromSeconds(4);
|
||||
private static readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1);
|
||||
|
||||
|
@ -166,21 +159,16 @@ ST: {4}
|
|||
if (searchWaitTime > TimeSpan.Zero)
|
||||
await BroadcastDiscoverMessage(searchTarget, SearchTimeToMXValue(searchWaitTime)).ConfigureAwait(false);
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
lock (_SearchResultsSynchroniser)
|
||||
{
|
||||
foreach (var device in GetUnexpiredDevices().Where((d) => NotificationTypeMatchesFilter(d)))
|
||||
foreach (var device in GetUnexpiredDevices().Where(NotificationTypeMatchesFilter))
|
||||
{
|
||||
if (this.IsDisposed) return;
|
||||
|
||||
DeviceFound(device, false);
|
||||
}
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
if (searchWaitTime != TimeSpan.Zero)
|
||||
await Task.Delay(searchWaitTime);
|
||||
await Task.Delay(searchWaitTime).ConfigureAwait(false);
|
||||
|
||||
IEnumerable<DiscoveredSsdpDevice> retVal = null;
|
||||
|
||||
|
@ -192,7 +180,7 @@ ST: {4}
|
|||
_SearchResults = null;
|
||||
}
|
||||
|
||||
var expireTask = RemoveExpiredDevicesFromCacheAsync();
|
||||
RemoveExpiredDevicesFromCache();
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -417,25 +405,27 @@ ST: {4}
|
|||
|
||||
#region Network Message Processing
|
||||
|
||||
private static byte[] BuildDiscoverMessage(string serviceType, TimeSpan mxValue)
|
||||
{
|
||||
return System.Text.UTF8Encoding.UTF8.GetBytes(
|
||||
String.Format(HttpURequestMessageFormat,
|
||||
SsdpConstants.MSearchMethod,
|
||||
SsdpConstants.MulticastLocalAdminAddress,
|
||||
SsdpConstants.MulticastPort,
|
||||
SsdpConstants.SsdpDiscoverMessage,
|
||||
serviceType,
|
||||
mxValue.TotalSeconds
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private Task BroadcastDiscoverMessage(string serviceType, TimeSpan mxValue)
|
||||
{
|
||||
var broadcastMessage = BuildDiscoverMessage(serviceType, mxValue);
|
||||
var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
return _CommunicationsServer.SendMulticastMessage(broadcastMessage);
|
||||
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["MAN"] = "\"ssdp:discover\"";
|
||||
|
||||
// Search target
|
||||
values["ST"] = "ssdp:all";
|
||||
|
||||
// Seconds to delay response
|
||||
values["MX"] = "3";
|
||||
|
||||
var header = "M-SEARCH * HTTP/1.1";
|
||||
|
||||
var message = SsdpHelper.BuildMessage(header, values);
|
||||
|
||||
return _CommunicationsServer.SendMulticastMessage(message);
|
||||
}
|
||||
|
||||
private void ProcessSearchResponseMessage(HttpResponseMessage message)
|
||||
|
@ -608,19 +598,11 @@ ST: {4}
|
|||
|
||||
#region Expiry and Device Removal
|
||||
|
||||
private Task RemoveExpiredDevicesFromCacheAsync()
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
RemoveExpiredDevicesFromCache();
|
||||
});
|
||||
}
|
||||
|
||||
private void RemoveExpiredDevicesFromCache()
|
||||
{
|
||||
if (this.IsDisposed) return;
|
||||
|
||||
IEnumerable<DiscoveredSsdpDevice> expiredDevices = null;
|
||||
DiscoveredSsdpDevice[] expiredDevices = null;
|
||||
lock (_Devices)
|
||||
{
|
||||
expiredDevices = (from device in _Devices where device.IsExpired() select device).ToArray();
|
||||
|
|
|
@ -26,8 +26,8 @@ namespace Rssdp
|
|||
/// <para>Uses the default <see cref="ISsdpCommunicationsServer"/> implementation and network settings for Windows and the SSDP specification.</para>
|
||||
/// </remarks>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "No way to do this here, and we don't want to dispose it except in the (rare) case of an exception anyway.")]
|
||||
public SsdpDevicePublisher(ISocketFactory socketFactory, ITimerFactory timerFactory, string osName, string osVersion)
|
||||
: base(new SsdpCommunicationsServer(socketFactory), timerFactory, osName, osVersion)
|
||||
public SsdpDevicePublisher(ISsdpCommunicationsServer communicationsServer, ITimerFactory timerFactory, string osName, string osVersion)
|
||||
: base(communicationsServer, timerFactory, osName, osVersion)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
88
RSSDP/SsdpHelper.cs
Normal file
88
RSSDP/SsdpHelper.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Text;
|
||||
|
||||
namespace RSSDP
|
||||
{
|
||||
public class SsdpHelper
|
||||
{
|
||||
private readonly ITextEncoding _encoding;
|
||||
|
||||
public SsdpHelper(ITextEncoding encoding)
|
||||
{
|
||||
_encoding = encoding;
|
||||
}
|
||||
|
||||
public SsdpMessageInfo ParseSsdpResponse(byte[] data)
|
||||
{
|
||||
using (var ms = new MemoryStream(data))
|
||||
{
|
||||
using (var reader = new StreamReader(ms, _encoding.GetASCIIEncoding()))
|
||||
{
|
||||
var proto = (reader.ReadLine() ?? string.Empty).Trim();
|
||||
var method = proto.Split(new[] { ' ' }, 2)[0];
|
||||
var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
for (var line = reader.ReadLine(); line != null; line = reader.ReadLine())
|
||||
{
|
||||
line = line.Trim();
|
||||
if (string.IsNullOrEmpty(line))
|
||||
{
|
||||
break;
|
||||
}
|
||||
var parts = line.Split(new[] { ':' }, 2);
|
||||
|
||||
if (parts.Length >= 2)
|
||||
{
|
||||
headers[parts[0]] = parts[1].Trim();
|
||||
}
|
||||
}
|
||||
|
||||
return new SsdpMessageInfo
|
||||
{
|
||||
Method = method,
|
||||
Headers = headers,
|
||||
Message = data
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string BuildMessage(string header, Dictionary<string, string> values)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
const string argFormat = "{0}: {1}\r\n";
|
||||
|
||||
builder.AppendFormat("{0}\r\n", header);
|
||||
|
||||
foreach (var pair in values)
|
||||
{
|
||||
builder.AppendFormat(argFormat, pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
builder.Append("\r\n");
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class SsdpMessageInfo
|
||||
{
|
||||
public string Method { get; set; }
|
||||
|
||||
public IpEndPointInfo EndPoint { get; set; }
|
||||
|
||||
public Dictionary<string, string> Headers { get; set; }
|
||||
|
||||
public IpEndPointInfo LocalEndPoint { get; set; }
|
||||
public byte[] Message { get; set; }
|
||||
|
||||
public SsdpMessageInfo()
|
||||
{
|
||||
Headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user