using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.Udp; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Plugins; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using IConfigurationManager = MediaBrowser.Common.Configuration.IConfigurationManager; namespace Emby.Server.Implementations.EntryPoints { /// /// Class responsible for registering all UDP broadcast endpoints and their handlers. /// public sealed class UdpServerEntryPoint : IServerEntryPoint { /// /// The port of the UDP server. /// public const int PortNumber = 7359; /// /// The logger. /// private readonly ILogger _logger; private readonly IServerApplicationHost _appHost; private readonly IConfiguration _config; private readonly IConfigurationManager _configurationManager; private readonly INetworkManager _networkManager; /// /// The UDP server. /// private readonly List _udpServers; private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private bool _disposed; /// /// Initializes a new instance of the class. /// /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. public UdpServerEntryPoint( ILogger logger, IServerApplicationHost appHost, IConfiguration configuration, IConfigurationManager configurationManager, INetworkManager networkManager) { _logger = logger; _appHost = appHost; _config = configuration; _configurationManager = configurationManager; _networkManager = networkManager; _udpServers = new List(); } /// public Task RunAsync() { CheckDisposed(); if (!_configurationManager.GetNetworkConfiguration().AutoDiscovery) { return Task.CompletedTask; } try { // Linux needs to bind to the broadcast addresses to get broadcast traffic // Windows receives broadcast fine when binding to just the interface, it is unable to bind to broadcast addresses if (OperatingSystem.IsLinux()) { // Add global broadcast listener var server = new UdpServer(_logger, _appHost, _config, IPAddress.Broadcast, PortNumber); server.Start(_cancellationTokenSource.Token); _udpServers.Add(server); // Add bind address specific broadcast listeners // IPv6 is currently unsupported var validInterfaces = _networkManager.GetInternalBindAddresses().Where(i => i.AddressFamily == AddressFamily.InterNetwork); foreach (var intf in validInterfaces) { var broadcastAddress = NetworkUtils.GetBroadcastAddress(intf.Subnet); _logger.LogDebug("Binding UDP server to {Address} on port {PortNumber}", broadcastAddress, PortNumber); server = new UdpServer(_logger, _appHost, _config, broadcastAddress, PortNumber); server.Start(_cancellationTokenSource.Token); _udpServers.Add(server); } } else { // Add bind address specific broadcast listeners // IPv6 is currently unsupported var validInterfaces = _networkManager.GetInternalBindAddresses().Where(i => i.AddressFamily == AddressFamily.InterNetwork); foreach (var intf in validInterfaces) { var intfAddress = intf.Address; _logger.LogDebug("Binding UDP server to {Address} on port {PortNumber}", intfAddress, PortNumber); var server = new UdpServer(_logger, _appHost, _config, intfAddress, PortNumber); server.Start(_cancellationTokenSource.Token); _udpServers.Add(server); } } } catch (SocketException ex) { _logger.LogWarning(ex, "Unable to start AutoDiscovery listener on UDP port {PortNumber}", PortNumber); } return Task.CompletedTask; } private void CheckDisposed() { if (_disposed) { throw new ObjectDisposedException(GetType().Name); } } /// public void Dispose() { if (_disposed) { return; } _cancellationTokenSource.Cancel(); _cancellationTokenSource.Dispose(); foreach (var server in _udpServers) { server.Dispose(); } _udpServers.Clear(); _disposed = true; } } }