aboutsummaryrefslogtreecommitdiff
path: root/Emby.Dlna/Main/DlnaEntryPoint.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Dlna/Main/DlnaEntryPoint.cs')
-rw-r--r--Emby.Dlna/Main/DlnaEntryPoint.cs222
1 files changed, 149 insertions, 73 deletions
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index a20006578..5d252d8dc 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -1,9 +1,17 @@
+#nullable disable
+
+#pragma warning disable CS1591
+
using System;
+using System.Globalization;
using System.Linq;
-using System.Threading;
+using System.Net.Http;
+using System.Net.Sockets;
using System.Threading.Tasks;
using Emby.Dlna.PlayTo;
using Emby.Dlna.Ssdp;
+using Jellyfin.Networking.Configuration;
+using Jellyfin.Networking.Manager;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
@@ -19,23 +27,19 @@ using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Net;
-using MediaBrowser.Model.System;
-using MediaBrowser.Model.Xml;
using Microsoft.Extensions.Logging;
using Rssdp;
using Rssdp.Infrastructure;
namespace Emby.Dlna.Main
{
- public class DlnaEntryPoint : IServerEntryPoint, IRunBeforeStartup
+ public sealed class DlnaEntryPoint : IServerEntryPoint, IRunBeforeStartup
{
private readonly IServerConfigurationManager _config;
- private readonly ILogger _logger;
+ private readonly ILogger<DlnaEntryPoint> _logger;
private readonly IServerApplicationHost _appHost;
-
- private PlayToManager _manager;
private readonly ISessionManager _sessionManager;
- private readonly IHttpClient _httpClient;
+ private readonly IHttpClientFactory _httpClientFactory;
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
private readonly IDlnaManager _dlnaManager;
@@ -44,28 +48,25 @@ namespace Emby.Dlna.Main
private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder;
-
private readonly IDeviceDiscovery _deviceDiscovery;
-
- private SsdpDevicePublisher _Publisher;
-
private readonly ISocketFactory _socketFactory;
- private readonly IEnvironmentInfo _environmentInfo;
private readonly INetworkManager _networkManager;
+ private readonly object _syncLock = new object();
+ private readonly NetworkConfiguration _netConfig;
+ private readonly bool _disabled;
+ private PlayToManager _manager;
+ private SsdpDevicePublisher _publisher;
private ISsdpCommunicationsServer _communicationsServer;
- internal IContentDirectory ContentDirectory { get; private set; }
- internal IConnectionManager ConnectionManager { get; private set; }
- internal IMediaReceiverRegistrar MediaReceiverRegistrar { get; private set; }
+ private bool _disposed;
- public static DlnaEntryPoint Current;
-
- public DlnaEntryPoint(IServerConfigurationManager config,
+ public DlnaEntryPoint(
+ IServerConfigurationManager config,
ILoggerFactory loggerFactory,
IServerApplicationHost appHost,
ISessionManager sessionManager,
- IHttpClient httpClient,
+ IHttpClientFactory httpClientFactory,
ILibraryManager libraryManager,
IUserManager userManager,
IDlnaManager dlnaManager,
@@ -76,16 +77,14 @@ namespace Emby.Dlna.Main
IDeviceDiscovery deviceDiscovery,
IMediaEncoder mediaEncoder,
ISocketFactory socketFactory,
- IEnvironmentInfo environmentInfo,
INetworkManager networkManager,
IUserViewManager userViewManager,
- IXmlReaderSettingsFactory xmlReaderSettingsFactory,
ITVSeriesManager tvSeriesManager)
{
_config = config;
_appHost = appHost;
_sessionManager = sessionManager;
- _httpClient = httpClient;
+ _httpClientFactory = httpClientFactory;
_libraryManager = libraryManager;
_userManager = userManager;
_dlnaManager = dlnaManager;
@@ -96,41 +95,74 @@ namespace Emby.Dlna.Main
_deviceDiscovery = deviceDiscovery;
_mediaEncoder = mediaEncoder;
_socketFactory = socketFactory;
- _environmentInfo = environmentInfo;
_networkManager = networkManager;
- _logger = loggerFactory.CreateLogger("Dlna");
+ _logger = loggerFactory.CreateLogger<DlnaEntryPoint>();
- ContentDirectory = new ContentDirectory.ContentDirectory(dlnaManager,
+ ContentDirectory = new ContentDirectory.ContentDirectoryService(
+ dlnaManager,
userDataManager,
imageProcessor,
libraryManager,
config,
userManager,
- _logger,
- httpClient,
+ loggerFactory.CreateLogger<ContentDirectory.ContentDirectoryService>(),
+ httpClientFactory,
localizationManager,
mediaSourceManager,
userViewManager,
mediaEncoder,
- xmlReaderSettingsFactory,
tvSeriesManager);
- ConnectionManager = new ConnectionManager.ConnectionManager(dlnaManager, config, _logger, httpClient, xmlReaderSettingsFactory);
+ ConnectionManager = new ConnectionManager.ConnectionManagerService(
+ dlnaManager,
+ config,
+ loggerFactory.CreateLogger<ConnectionManager.ConnectionManagerService>(),
+ httpClientFactory);
- MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrar(_logger, httpClient, config, xmlReaderSettingsFactory);
+ MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrarService(
+ loggerFactory.CreateLogger<MediaReceiverRegistrar.MediaReceiverRegistrarService>(),
+ httpClientFactory,
+ config);
Current = this;
+
+ _netConfig = config.GetConfiguration<NetworkConfiguration>("network");
+ _disabled = appHost.ListenWithHttps && _netConfig.RequireHttps;
+
+ if (_disabled && _config.GetDlnaConfiguration().EnableServer)
+ {
+ _logger.LogError("The DLNA specification does not support HTTPS.");
+ }
}
+ public static DlnaEntryPoint Current { get; private set; }
+
+ /// <summary>
+ /// Gets a value indicating whether the dlna server is enabled.
+ /// </summary>
+ public static bool Enabled { get; private set; }
+
+ public IContentDirectory ContentDirectory { get; private set; }
+
+ public IConnectionManager ConnectionManager { get; private set; }
+
+ public IMediaReceiverRegistrar MediaReceiverRegistrar { get; private set; }
+
public async Task RunAsync()
{
await ((DlnaManager)_dlnaManager).InitProfilesAsync().ConfigureAwait(false);
+ if (_disabled)
+ {
+ // No use starting as dlna won't work, as we're running purely on HTTPS.
+ return;
+ }
+
ReloadComponents();
- _config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated;
+ _config.NamedConfigurationUpdated += OnNamedConfigurationUpdated;
}
- void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
+ private void OnNamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
{
if (string.Equals(e.Key, "dlna", StringComparison.OrdinalIgnoreCase))
{
@@ -138,15 +170,16 @@ namespace Emby.Dlna.Main
}
}
- private async void ReloadComponents()
+ private void ReloadComponents()
{
var options = _config.GetDlnaConfiguration();
+ Enabled = options.EnableServer;
StartSsdpHandler();
if (options.EnableServer)
{
- await StartDevicePublisher(options).ConfigureAwait(false);
+ StartDevicePublisher(options);
}
else
{
@@ -169,7 +202,8 @@ namespace Emby.Dlna.Main
{
if (_communicationsServer == null)
{
- var enableMultiSocketBinding = _environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows;
+ var enableMultiSocketBinding = OperatingSystem.IsWindows() ||
+ OperatingSystem.IsLinux();
_communicationsServer = new SsdpCommunicationsServer(_socketFactory, _networkManager, _logger, enableMultiSocketBinding)
{
@@ -194,7 +228,10 @@ namespace Emby.Dlna.Main
{
try
{
- ((DeviceDiscovery)_deviceDiscovery).Start(communicationsServer);
+ if (communicationsServer != null)
+ {
+ ((DeviceDiscovery)_deviceDiscovery).Start(communicationsServer);
+ }
}
catch (Exception ex)
{
@@ -215,27 +252,34 @@ namespace Emby.Dlna.Main
}
}
- public async Task StartDevicePublisher(Configuration.DlnaOptions options)
+ public void StartDevicePublisher(Configuration.DlnaOptions options)
{
if (!options.BlastAliveMessages)
{
return;
}
- if (_Publisher != null)
+ if (_publisher != null)
{
return;
}
try
{
- _Publisher = new SsdpDevicePublisher(_communicationsServer, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion);
- _Publisher.LogFunction = LogMessage;
- _Publisher.SupportPnpRootDevice = false;
+ _publisher = new SsdpDevicePublisher(
+ _communicationsServer,
+ _networkManager,
+ MediaBrowser.Common.System.OperatingSystem.Name,
+ Environment.OSVersion.VersionString,
+ _config.GetDlnaConfiguration().SendOnlyMatchedHost)
+ {
+ LogFunction = LogMessage,
+ SupportPnpRootDevice = false
+ };
- await RegisterServerEndpoints().ConfigureAwait(false);
+ RegisterServerEndpoints();
- _Publisher.StartBroadcastingAliveMessages(TimeSpan.FromSeconds(options.BlastAliveMessageIntervalSeconds));
+ _publisher.StartBroadcastingAliveMessages(TimeSpan.FromSeconds(options.BlastAliveMessageIntervalSeconds));
}
catch (Exception ex)
{
@@ -243,31 +287,53 @@ namespace Emby.Dlna.Main
}
}
- private async Task RegisterServerEndpoints()
+ private void RegisterServerEndpoints()
{
- var addresses = (await _appHost.GetLocalIpAddresses(CancellationToken.None).ConfigureAwait(false)).ToList();
-
var udn = CreateUuid(_appHost.SystemId);
+ var descriptorUri = "/dlna/" + udn + "/description.xml";
+
+ var bindAddresses = NetworkManager.CreateCollection(
+ _networkManager.GetInternalBindAddresses()
+ .Where(i => i.AddressFamily == AddressFamily.InterNetwork || (i.AddressFamily == AddressFamily.InterNetworkV6 && i.Address.ScopeId != 0)));
- foreach (var address in addresses)
+ if (bindAddresses.Count == 0)
{
- // TODO: Remove this condition on platforms that support it
- //if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
- //{
- // continue;
- //}
+ // No interfaces returned, so use loopback.
+ bindAddresses = _networkManager.GetLoopbacks();
+ }
+
+ foreach (IPNetAddress address in bindAddresses)
+ {
+ if (address.AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ // Not supporting IPv6 right now
+ continue;
+ }
+
+ // Limit to LAN addresses only
+ if (!_networkManager.IsInLocalNetwork(address))
+ {
+ continue;
+ }
var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
_logger.LogInformation("Registering publisher for {0} on {1}", fullService, address);
- var descriptorUri = "/dlna/" + udn + "/description.xml";
- var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri);
+ var uri = new UriBuilder(_appHost.GetSmartApiUrl(address.Address) + descriptorUri);
+ if (!string.IsNullOrEmpty(_appHost.PublishedServerUrl))
+ {
+ // DLNA will only work over http, so we must reset to http:// : {port}.
+ uri.Scheme = "http";
+ uri.Port = _netConfig.HttpServerPortNumber;
+ }
var device = new SsdpRootDevice
{
- CacheLifetime = TimeSpan.FromSeconds(1800), //How long SSDP clients can cache this info.
- Location = uri, // Must point to the URL that serves your devices UPnP description document.
+ CacheLifetime = TimeSpan.FromSeconds(1800), // How long SSDP clients can cache this info.
+ Location = uri.Uri, // Must point to the URL that serves your devices UPnP description document.
+ Address = address.Address,
+ PrefixLength = address.PrefixLength,
FriendlyName = "Jellyfin",
Manufacturer = "Jellyfin",
ModelName = "Jellyfin Server",
@@ -276,13 +342,13 @@ namespace Emby.Dlna.Main
};
SetProperies(device, fullService);
- _Publisher.AddDevice(device);
+ _publisher.AddDevice(device);
var embeddedDevices = new[]
{
"urn:schemas-upnp-org:service:ContentDirectory:1",
"urn:schemas-upnp-org:service:ConnectionManager:1",
- //"urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"
+ // "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"
};
foreach (var subDevice in embeddedDevices)
@@ -308,12 +374,13 @@ namespace Emby.Dlna.Main
{
guid = text.GetMD5();
}
- return guid.ToString("N");
+
+ return guid.ToString("N", CultureInfo.InvariantCulture);
}
private void SetProperies(SsdpDevice device, string fullDeviceType)
{
- var service = fullDeviceType.Replace("urn:", string.Empty).Replace(":1", string.Empty);
+ var service = fullDeviceType.Replace("urn:", string.Empty, StringComparison.OrdinalIgnoreCase).Replace(":1", string.Empty, StringComparison.OrdinalIgnoreCase);
var serviceParts = service.Split(':');
@@ -324,7 +391,6 @@ namespace Emby.Dlna.Main
device.DeviceType = serviceParts[2];
}
- private readonly object _syncLock = new object();
private void StartPlayToManager()
{
lock (_syncLock)
@@ -336,7 +402,8 @@ namespace Emby.Dlna.Main
try
{
- _manager = new PlayToManager(_logger,
+ _manager = new PlayToManager(
+ _logger,
_sessionManager,
_libraryManager,
_userManager,
@@ -344,7 +411,7 @@ namespace Emby.Dlna.Main
_appHost,
_imageProcessor,
_deviceDiscovery,
- _httpClient,
+ _httpClientFactory,
_config,
_userDataManager,
_localization,
@@ -375,13 +442,30 @@ namespace Emby.Dlna.Main
{
_logger.LogError(ex, "Error disposing PlayTo manager");
}
+
_manager = null;
}
}
}
+ public void DisposeDevicePublisher()
+ {
+ if (_publisher != null)
+ {
+ _logger.LogInformation("Disposing SsdpDevicePublisher");
+ _publisher.Dispose();
+ _publisher = null;
+ }
+ }
+
+ /// <inheritdoc />
public void Dispose()
{
+ if (_disposed)
+ {
+ return;
+ }
+
DisposeDevicePublisher();
DisposePlayToManager();
DisposeDeviceDiscovery();
@@ -397,16 +481,8 @@ namespace Emby.Dlna.Main
ConnectionManager = null;
MediaReceiverRegistrar = null;
Current = null;
- }
- public void DisposeDevicePublisher()
- {
- if (_Publisher != null)
- {
- _logger.LogInformation("Disposing SsdpDevicePublisher");
- _Publisher.Dispose();
- _Publisher = null;
- }
+ _disposed = true;
}
}
}