aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2016-11-14 15:18:01 -0500
committerLuke Pulverenti <luke.pulverenti@gmail.com>2016-11-14 15:18:01 -0500
commit6d40ab7e1c40fdb5c18defb7a5f5521bbd0cfb2e (patch)
tree19a2ca600c1c6a7df8eb9a649b94e0cc70086f4d
parent08f959faba73e6ef66970276a43c5a7c807a6720 (diff)
parent588c06fca037b6656d7b734b47f709a0e078ce41 (diff)
Merge branch 'beta' of https://github.com/MediaBrowser/Emby into beta
-rw-r--r--Emby.Common.Implementations/IO/ManagedFileSystem.cs2
-rw-r--r--Emby.Common.Implementations/Net/SocketFactory.cs1
-rw-r--r--Emby.Common.Implementations/Net/UdpSocket.cs11
-rw-r--r--Emby.Dlna/Main/DlnaEntryPoint.cs30
-rw-r--r--Emby.Dlna/Ssdp/DeviceDiscovery.cs20
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs7
-rw-r--r--MediaBrowser.Server.Mono/Program.cs2
-rw-r--r--RSSDP/ISsdpCommunicationsServer.cs3
-rw-r--r--RSSDP/RSSDP.csproj1
-rw-r--r--RSSDP/SsdpCommunicationsServer.cs17
-rw-r--r--RSSDP/SsdpDeviceLocator.cs2
-rw-r--r--RSSDP/SsdpDeviceLocatorBase.cs70
-rw-r--r--RSSDP/SsdpDevicePublisher.cs4
-rw-r--r--RSSDP/SsdpDevicePublisherBase.cs43
-rw-r--r--RSSDP/SsdpHelper.cs88
-rw-r--r--SocketHttpListener.Portable/Net/HttpListenerResponse.cs4
16 files changed, 179 insertions, 126 deletions
diff --git a/Emby.Common.Implementations/IO/ManagedFileSystem.cs b/Emby.Common.Implementations/IO/ManagedFileSystem.cs
index 83bb50f94..4fb70d4e2 100644
--- a/Emby.Common.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Common.Implementations/IO/ManagedFileSystem.cs
@@ -61,7 +61,7 @@ namespace Emby.Common.Implementations.IO
{
get
{
- return Path.DirectorySeparatorChar;
+ return Path.PathSeparator;
}
}
diff --git a/Emby.Common.Implementations/Net/SocketFactory.cs b/Emby.Common.Implementations/Net/SocketFactory.cs
index f26137683..c65593242 100644
--- a/Emby.Common.Implementations/Net/SocketFactory.cs
+++ b/Emby.Common.Implementations/Net/SocketFactory.cs
@@ -131,6 +131,7 @@ namespace Emby.Common.Implementations.Net
#else
retVal.ExclusiveAddressUse = false;
#endif
+ //retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse(ipAddress), _LocalIP));
diff --git a/Emby.Common.Implementations/Net/UdpSocket.cs b/Emby.Common.Implementations/Net/UdpSocket.cs
index eca82034b..b9b7d8a2d 100644
--- a/Emby.Common.Implementations/Net/UdpSocket.cs
+++ b/Emby.Common.Implementations/Net/UdpSocket.cs
@@ -63,7 +63,7 @@ namespace Emby.Common.Implementations.Net
}
}, state);
#else
- _Socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.EndPoint, new AsyncCallback(this.ProcessResponse), state);
+ _Socket.BeginReceiveFrom(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ref state.EndPoint, ProcessResponse, state);
#endif
return tcs.Task;
@@ -99,7 +99,7 @@ namespace Emby.Common.Implementations.Net
_Socket.EndSend(result);
taskSource.TrySetResult(true);
}
- catch (SocketException ex)
+ catch (Exception ex)
{
taskSource.TrySetException(ex);
}
@@ -200,13 +200,6 @@ namespace Emby.Common.Implementations.Net
{
state.TaskCompletionSource.SetCanceled();
}
- catch (SocketException se)
- {
- if (se.SocketErrorCode != SocketError.Interrupted && se.SocketErrorCode != SocketError.OperationAborted && se.SocketErrorCode != SocketError.Shutdown)
- state.TaskCompletionSource.SetException(se);
- else
- state.TaskCompletionSource.SetCanceled();
- }
catch (Exception ex)
{
state.TaskCompletionSource.SetException(ex);
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index ef27c029d..49bb9a74f 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -55,6 +55,8 @@ namespace Emby.Dlna.Main
private readonly ISocketFactory _socketFactory;
private readonly IEnvironmentInfo _environmentInfo;
+ private ISsdpCommunicationsServer _communicationsServer;
+
public DlnaEntryPoint(IServerConfigurationManager config,
ILogManager logManager,
IServerApplicationHost appHost,
@@ -152,10 +154,18 @@ namespace Emby.Dlna.Main
{
try
{
- StartPublishing();
+ if (_communicationsServer == null)
+ {
+ _communicationsServer = new SsdpCommunicationsServer(_socketFactory)
+ {
+ IsShared = true
+ };
+ }
+
+ StartPublishing(_communicationsServer);
_ssdpHandlerStarted = true;
- StartDeviceDiscovery();
+ StartDeviceDiscovery(_communicationsServer);
}
catch (Exception ex)
{
@@ -165,20 +175,20 @@ namespace Emby.Dlna.Main
private void LogMessage(string msg)
{
- //_logger.Debug(msg);
+ _logger.Debug(msg);
}
- private void StartPublishing()
+ private void StartPublishing(ISsdpCommunicationsServer communicationsServer)
{
SsdpDevicePublisherBase.LogFunction = LogMessage;
- _Publisher = new SsdpDevicePublisher(_socketFactory, _timerFactory, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion);
+ _Publisher = new SsdpDevicePublisher(communicationsServer, _timerFactory, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion);
}
- private void StartDeviceDiscovery()
+ private void StartDeviceDiscovery(ISsdpCommunicationsServer communicationsServer)
{
try
{
- ((DeviceDiscovery)_deviceDiscovery).Start();
+ ((DeviceDiscovery)_deviceDiscovery).Start(communicationsServer);
}
catch (Exception ex)
{
@@ -374,6 +384,12 @@ namespace Emby.Dlna.Main
DisposeDlnaServer();
DisposePlayToManager();
DisposeSsdpHandler();
+
+ if (_communicationsServer != null)
+ {
+ _communicationsServer.Dispose();
+ _communicationsServer = null;
+ }
}
public void DisposeDlnaServer()
diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
index 6f5842968..1cd19d010 100644
--- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs
+++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
@@ -15,6 +15,7 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Threading;
using Rssdp;
+using Rssdp.Infrastructure;
namespace Emby.Dlna.Ssdp
{
@@ -29,7 +30,7 @@ namespace Emby.Dlna.Ssdp
public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscovered;
public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceLeft;
- private SsdpDeviceLocator _DeviceLocator;
+ private SsdpDeviceLocator _deviceLocator;
private readonly ITimerFactory _timerFactory;
private readonly ISocketFactory _socketFactory;
@@ -45,9 +46,9 @@ namespace Emby.Dlna.Ssdp
}
// Call this method from somewhere in your code to start the search.
- public void BeginSearch()
+ public void Start(ISsdpCommunicationsServer communicationsServer)
{
- _DeviceLocator = new SsdpDeviceLocator(_socketFactory, _timerFactory);
+ _deviceLocator = new SsdpDeviceLocator(communicationsServer, _timerFactory);
// (Optional) Set the filter so we only see notifications for devices we care about
// (can be any search target value i.e device type, uuid value etc - any value that appears in the
@@ -55,8 +56,8 @@ namespace Emby.Dlna.Ssdp
//_DeviceLocator.NotificationFilter = "upnp:rootdevice";
// Connect our event handler so we process devices as they are found
- _DeviceLocator.DeviceAvailable += deviceLocator_DeviceAvailable;
- _DeviceLocator.DeviceUnavailable += _DeviceLocator_DeviceUnavailable;
+ _deviceLocator.DeviceAvailable += deviceLocator_DeviceAvailable;
+ _deviceLocator.DeviceUnavailable += _DeviceLocator_DeviceUnavailable;
// Perform a search so we don't have to wait for devices to broadcast notifications
// again to get any results right away (notifications are broadcast periodically).
@@ -72,9 +73,9 @@ namespace Emby.Dlna.Ssdp
try
{
// Enable listening for notifications (optional)
- _DeviceLocator.StartListeningForNotifications();
+ _deviceLocator.StartListeningForNotifications();
- await _DeviceLocator.SearchAsync().ConfigureAwait(false);
+ await _deviceLocator.SearchAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -130,11 +131,6 @@ namespace Emby.Dlna.Ssdp
EventHelper.FireEventIfNotNull(DeviceLeft, this, args, _logger);
}
- public void Start()
- {
- BeginSearch();
- }
-
public void Dispose()
{
if (!_disposed)
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
index 6bb06843a..6d527c1cf 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
@@ -31,13 +31,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public async Task Record(MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
- var httpRequestOptions = new HttpRequestOptions()
+ var httpRequestOptions = new HttpRequestOptions
{
- Url = mediaSource.Path
+ Url = mediaSource.Path,
+ BufferContent = false
};
- httpRequestOptions.BufferContent = false;
-
using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false))
{
_logger.Info("Opened recording stream from tuner provider");
diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs
index 7fc3ff22e..f490a829a 100644
--- a/MediaBrowser.Server.Mono/Program.cs
+++ b/MediaBrowser.Server.Mono/Program.cs
@@ -291,7 +291,7 @@ namespace MediaBrowser.Server.Mono
{
public bool IsBsd { get; set; }
- public virtual string GetUserId()
+ public override string GetUserId()
{
return Syscall.getuid().ToString(CultureInfo.InvariantCulture);
}
diff --git a/RSSDP/ISsdpCommunicationsServer.cs b/RSSDP/ISsdpCommunicationsServer.cs
index b1e84dc9f..462f33fe6 100644
--- a/RSSDP/ISsdpCommunicationsServer.cs
+++ b/RSSDP/ISsdpCommunicationsServer.cs
@@ -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
diff --git a/RSSDP/RSSDP.csproj b/RSSDP/RSSDP.csproj
index fb4d67e1a..d60f6ea44 100644
--- a/RSSDP/RSSDP.csproj
+++ b/RSSDP/RSSDP.csproj
@@ -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>
diff --git a/RSSDP/SsdpCommunicationsServer.cs b/RSSDP/SsdpCommunicationsServer.cs
index c0b9c6542..4de47f3d3 100644
--- a/RSSDP/SsdpCommunicationsServer.cs
+++ b/RSSDP/SsdpCommunicationsServer.cs
@@ -170,12 +170,11 @@ 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>
- /// <exception cref="System.ArgumentNullException">Thrown if the <paramref name="messageData"/> argument is null.</exception>
- /// <exception cref="System.ObjectDisposedException">Thrown if the <see cref="DisposableManagedObjectBase.IsDisposed"/> property is true (because <seealso cref="DisposableManagedObjectBase.Dispose()" /> has been called previously).</exception>
- public async Task SendMulticastMessage(byte[] messageData)
+ public async Task SendMulticastMessage(string message)
{
- if (messageData == null) throw new ArgumentNullException("messageData");
+ if (message == null) throw new ArgumentNullException("messageData");
+
+ byte[] messageData = Encoding.UTF8.GetBytes(message);
ThrowIfDisposed();
@@ -294,21 +293,19 @@ namespace Rssdp.Infrastructure
// Tasks are captured to local variables even if we don't use them just to avoid compiler warnings.
var t = Task.Run(async () =>
{
-
var cancelled = false;
while (!cancelled)
{
try
{
- var result = await socket.ReceiveAsync();
+ var result = await socket.ReceiveAsync().ConfigureAwait(false);
if (result.ReceivedBytes > 0)
{
// Strange cannot convert compiler error here if I don't explicitly
// assign or cast to Action first. Assignment is easier to read,
// so went with that.
- Action processWork = () => ProcessMessage(System.Text.UTF8Encoding.UTF8.GetString(result.Buffer, 0, result.ReceivedBytes), result.RemoteEndPoint);
- var processTask = Task.Run(processWork);
+ ProcessMessage(System.Text.UTF8Encoding.UTF8.GetString(result.Buffer, 0, result.ReceivedBytes), result.RemoteEndPoint);
}
}
catch (ObjectDisposedException)
@@ -330,7 +327,9 @@ namespace Rssdp.Infrastructure
lock (_SendSocketSynchroniser)
{
if (_SendSocket == null)
+ {
_SendSocket = CreateSocketAndListenForResponsesAsync();
+ }
}
}
}
diff --git a/RSSDP/SsdpDeviceLocator.cs b/RSSDP/SsdpDeviceLocator.cs
index 01c96463f..3ea17237d 100644
--- a/RSSDP/SsdpDeviceLocator.cs
+++ b/RSSDP/SsdpDeviceLocator.cs
@@ -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.
diff --git a/RSSDP/SsdpDeviceLocatorBase.cs b/RSSDP/SsdpDeviceLocatorBase.cs
index ed4c087cd..b6276e499 100644
--- a/RSSDP/SsdpDeviceLocatorBase.cs
+++ b/RSSDP/SsdpDeviceLocatorBase.cs
@@ -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)
{
- lock (_SearchResultsSynchroniser)
+ foreach (var device in GetUnexpiredDevices().Where(NotificationTypeMatchesFilter))
{
- foreach (var device in GetUnexpiredDevices().Where((d) => NotificationTypeMatchesFilter(d)))
- {
- if (this.IsDisposed) return;
-
- DeviceFound(device, false);
- }
+ 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();
diff --git a/RSSDP/SsdpDevicePublisher.cs b/RSSDP/SsdpDevicePublisher.cs
index 56f27b3a2..1c17c7837 100644
--- a/RSSDP/SsdpDevicePublisher.cs
+++ b/RSSDP/SsdpDevicePublisher.cs
@@ -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)
{
}
diff --git a/RSSDP/SsdpDevicePublisherBase.cs b/RSSDP/SsdpDevicePublisherBase.cs
index b3c28aab7..7737733f7 100644
--- a/RSSDP/SsdpDevicePublisherBase.cs
+++ b/RSSDP/SsdpDevicePublisherBase.cs
@@ -6,6 +6,7 @@ using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Threading;
+using RSSDP;
namespace Rssdp.Infrastructure
{
@@ -344,7 +345,7 @@ namespace Rssdp.Infrastructure
values["USN"] = uniqueServiceName;
values["LOCATION"] = rootDevice.Location.ToString();
- var message = BuildMessage(header, values);
+ var message = SsdpHelper.BuildMessage(header, values);
try
{
@@ -384,19 +385,15 @@ namespace Rssdp.Infrastructure
return isDuplicateRequest;
}
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "t", Justification = "Capturing task to local variable avoids compiler warning, but value is otherwise not required.")]
private void CleanUpRecentSearchRequestsAsync()
{
- var t = Task.Run(() =>
+ lock (_RecentSearchRequests)
{
- lock (_RecentSearchRequests)
+ foreach (var requestKey in (from r in _RecentSearchRequests where r.Value.IsOld() select r.Key).ToArray())
{
- foreach (var requestKey in (from r in _RecentSearchRequests where r.Value.IsOld() select r.Key).ToArray())
- {
- _RecentSearchRequests.Remove(requestKey);
- }
+ _RecentSearchRequests.Remove(requestKey);
}
- });
+ }
}
#endregion
@@ -481,31 +478,13 @@ namespace Rssdp.Infrastructure
values["NT"] = notificationType;
values["USN"] = uniqueServiceName;
- var message = BuildMessage(header, values);
+ var message = SsdpHelper.BuildMessage(header, values);
- _CommsServer.SendMulticastMessage(System.Text.UTF8Encoding.UTF8.GetBytes(message));
+ _CommsServer.SendMulticastMessage(message);
WriteTrace(String.Format("Sent alive notification"), device);
}
- private 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();
- }
-
#endregion
#region ByeBye
@@ -543,9 +522,9 @@ namespace Rssdp.Infrastructure
values["NT"] = notificationType;
values["USN"] = uniqueServiceName;
- var message = BuildMessage(header, values);
+ var message = SsdpHelper.BuildMessage(header, values);
- return _CommsServer.SendMulticastMessage(System.Text.UTF8Encoding.UTF8.GetBytes(message));
+ return _CommsServer.SendMulticastMessage(message);
//WriteTrace(String.Format("Sent byebye notification"), device);
}
@@ -686,7 +665,7 @@ namespace Rssdp.Infrastructure
{
if (this.IsDisposed) return;
- if (e.Message.Method.Method == SsdpConstants.MSearchMethod)
+ if (string.Equals(e.Message.Method.Method, SsdpConstants.MSearchMethod, StringComparison.OrdinalIgnoreCase))
{
//According to SSDP/UPnP spec, ignore message if missing these headers.
// Edit: But some devices do it anyway
diff --git a/RSSDP/SsdpHelper.cs b/RSSDP/SsdpHelper.cs
new file mode 100644
index 000000000..2eacf3c11
--- /dev/null
+++ b/RSSDP/SsdpHelper.cs
@@ -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);
+ }
+ }
+}
diff --git a/SocketHttpListener.Portable/Net/HttpListenerResponse.cs b/SocketHttpListener.Portable/Net/HttpListenerResponse.cs
index fb3bc2bdb..880473c0a 100644
--- a/SocketHttpListener.Portable/Net/HttpListenerResponse.cs
+++ b/SocketHttpListener.Portable/Net/HttpListenerResponse.cs
@@ -413,8 +413,8 @@ namespace SocketHttpListener.Net
* HttpStatusCode.InternalServerError 500
* HttpStatusCode.ServiceUnavailable 503
*/
- bool conn_close = (status_code == 400 || status_code == 408 || status_code == 411 ||
- status_code == 413 || status_code == 414 || status_code == 500 ||
+ bool conn_close = (status_code == 408 || status_code == 411 ||
+ status_code == 413 || status_code == 414 ||
status_code == 503);
if (conn_close == false)