diff options
Diffstat (limited to 'Emby.Dlna/Main/DlnaEntryPoint.cs')
| -rw-r--r-- | Emby.Dlna/Main/DlnaEntryPoint.cs | 222 |
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; } } } |
