< Summary - Jellyfin

Information
Class: Jellyfin.Networking.AutoDiscoveryHost
Assembly: Jellyfin.Networking
File(s): /srv/git/jellyfin/src/Jellyfin.Networking/AutoDiscoveryHost.cs
Line coverage
100%
Covered lines: 10
Uncovered lines: 0
Coverable lines: 10
Total lines: 120
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%

File(s)

/srv/git/jellyfin/src/Jellyfin.Networking/AutoDiscoveryHost.cs

#LineLine coverage
 1using System;
 2using System.Net;
 3using System.Net.Sockets;
 4using System.Text;
 5using System.Text.Json;
 6using System.Threading;
 7using System.Threading.Tasks;
 8using MediaBrowser.Common.Configuration;
 9using MediaBrowser.Common.Net;
 10using MediaBrowser.Controller;
 11using MediaBrowser.Model.ApiClient;
 12using Microsoft.Extensions.Hosting;
 13using Microsoft.Extensions.Logging;
 14
 15namespace Jellyfin.Networking;
 16
 17/// <summary>
 18/// <see cref="BackgroundService"/> responsible for responding to auto-discovery messages.
 19/// </summary>
 20public sealed class AutoDiscoveryHost : BackgroundService
 21{
 22    /// <summary>
 23    /// The port to listen on for auto-discovery messages.
 24    /// </summary>
 25    private const int PortNumber = 7359;
 26
 27    private readonly ILogger<AutoDiscoveryHost> _logger;
 28    private readonly IServerApplicationHost _appHost;
 29    private readonly IConfigurationManager _configurationManager;
 30    private readonly INetworkManager _networkManager;
 31
 32    /// <summary>
 33    /// Initializes a new instance of the <see cref="AutoDiscoveryHost" /> class.
 34    /// </summary>
 35    /// <param name="logger">The <see cref="ILogger{AutoDiscoveryHost}"/>.</param>
 36    /// <param name="appHost">The <see cref="IServerApplicationHost"/>.</param>
 37    /// <param name="configurationManager">The <see cref="IConfigurationManager"/>.</param>
 38    /// <param name="networkManager">The <see cref="INetworkManager"/>.</param>
 2239    public AutoDiscoveryHost(
 2240        ILogger<AutoDiscoveryHost> logger,
 2241        IServerApplicationHost appHost,
 2242        IConfigurationManager configurationManager,
 2243        INetworkManager networkManager)
 44    {
 2245        _logger = logger;
 2246        _appHost = appHost;
 2247        _configurationManager = configurationManager;
 2248        _networkManager = networkManager;
 2249    }
 50
 51    /// <inheritdoc />
 52    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
 53    {
 54        var networkConfig = _configurationManager.GetNetworkConfiguration();
 55        if (!networkConfig.AutoDiscovery)
 56        {
 57            return;
 58        }
 59
 60        await ListenForAutoDiscoveryMessage(IPAddress.Any, stoppingToken).ConfigureAwait(false);
 61    }
 62
 63    private async Task ListenForAutoDiscoveryMessage(IPAddress listenAddress, CancellationToken cancellationToken)
 64    {
 65        try
 66        {
 67            using var udpClient = new UdpClient(new IPEndPoint(listenAddress, PortNumber));
 68            udpClient.MulticastLoopback = false;
 69
 70            while (!cancellationToken.IsCancellationRequested)
 71            {
 72                try
 73                {
 74                    var result = await udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
 75                    var text = Encoding.UTF8.GetString(result.Buffer);
 76                    if (text.Contains("who is JellyfinServer?", StringComparison.OrdinalIgnoreCase))
 77                    {
 78                        await RespondToV2Message(result.RemoteEndPoint, udpClient, cancellationToken).ConfigureAwait(fal
 79                    }
 80                }
 81                catch (SocketException ex)
 82                {
 83                    _logger.LogError(ex, "Failed to receive data from socket");
 84                }
 85            }
 86        }
 87        catch (OperationCanceledException)
 88        {
 89            _logger.LogDebug("Broadcast socket operation cancelled");
 90        }
 91        catch (Exception ex)
 92        {
 93            // Exception in this function will prevent the background service from restarting in-process.
 94            _logger.LogError(ex, "Unable to bind to {Address}:{Port}", listenAddress, PortNumber);
 95        }
 96    }
 97
 98    private async Task RespondToV2Message(IPEndPoint endpoint, UdpClient broadCastUdpClient, CancellationToken cancellat
 99    {
 100        var localUrl = _appHost.GetSmartApiUrl(endpoint.Address);
 101        if (string.IsNullOrEmpty(localUrl))
 102        {
 103            _logger.LogWarning("Unable to respond to server discovery request because the local ip address could not be 
 104            return;
 105        }
 106
 107        var response = new ServerDiscoveryInfo(localUrl, _appHost.SystemId, _appHost.FriendlyName);
 108        try
 109        {
 110            _logger.LogDebug("Sending AutoDiscovery response");
 111            await broadCastUdpClient
 112                .SendAsync(JsonSerializer.SerializeToUtf8Bytes(response).AsMemory(), endpoint, cancellationToken)
 113                .ConfigureAwait(false);
 114        }
 115        catch (SocketException ex)
 116        {
 117            _logger.LogError(ex, "Error sending response message");
 118        }
 119    }
 120}