< Summary - Jellyfin

Information
Class: Jellyfin.Networking.AutoDiscoveryHost
Assembly: Jellyfin.Networking
File(s): /srv/git/jellyfin/src/Jellyfin.Networking/AutoDiscoveryHost.cs
Line coverage
45%
Covered lines: 22
Uncovered lines: 26
Coverable lines: 48
Total lines: 120
Line coverage: 45.8%
Branch coverage
25%
Covered branches: 2
Total branches: 8
Branch coverage: 25%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 1/23/2026 - 12:11:06 AM Line coverage: 100% (10/10) Total lines: 1204/19/2026 - 12:14:27 AM Line coverage: 45.8% (22/48) Branch coverage: 25% (2/8) Total lines: 120 4/19/2026 - 12:14:27 AM Line coverage: 45.8% (22/48) Branch coverage: 25% (2/8) Total lines: 120

Coverage delta

Coverage delta 55 -55

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
ExecuteAsync()50%2280%
ListenForAutoDiscoveryMessage()25%7442.1%
RespondToV2Message()0%620%

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>
 2139    public AutoDiscoveryHost(
 2140        ILogger<AutoDiscoveryHost> logger,
 2141        IServerApplicationHost appHost,
 2142        IConfigurationManager configurationManager,
 2143        INetworkManager networkManager)
 44    {
 2145        _logger = logger;
 2146        _appHost = appHost;
 2147        _configurationManager = configurationManager;
 2148        _networkManager = networkManager;
 2149    }
 50
 51    /// <inheritdoc />
 52    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
 53    {
 2154        var networkConfig = _configurationManager.GetNetworkConfiguration();
 2155        if (!networkConfig.AutoDiscovery)
 56        {
 057            return;
 58        }
 59
 2160        await ListenForAutoDiscoveryMessage(IPAddress.Any, stoppingToken).ConfigureAwait(false);
 2161    }
 62
 63    private async Task ListenForAutoDiscoveryMessage(IPAddress listenAddress, CancellationToken cancellationToken)
 64    {
 65        try
 66        {
 2167            using var udpClient = new UdpClient(new IPEndPoint(listenAddress, PortNumber));
 2168            udpClient.MulticastLoopback = false;
 69
 2170            while (!cancellationToken.IsCancellationRequested)
 71            {
 72                try
 73                {
 2174                    var result = await udpClient.ReceiveAsync(cancellationToken).ConfigureAwait(false);
 075                    var text = Encoding.UTF8.GetString(result.Buffer);
 076                    if (text.Contains("who is JellyfinServer?", StringComparison.OrdinalIgnoreCase))
 77                    {
 078                        await RespondToV2Message(result.RemoteEndPoint, udpClient, cancellationToken).ConfigureAwait(fal
 79                    }
 080                }
 081                catch (SocketException ex)
 82                {
 083                    _logger.LogError(ex, "Failed to receive data from socket");
 084                }
 85            }
 086        }
 2187        catch (OperationCanceledException)
 88        {
 2189            _logger.LogDebug("Broadcast socket operation cancelled");
 2190        }
 091        catch (Exception ex)
 92        {
 93            // Exception in this function will prevent the background service from restarting in-process.
 094            _logger.LogError(ex, "Unable to bind to {Address}:{Port}", listenAddress, PortNumber);
 095        }
 2196    }
 97
 98    private async Task RespondToV2Message(IPEndPoint endpoint, UdpClient broadCastUdpClient, CancellationToken cancellat
 99    {
 0100        var localUrl = _appHost.GetSmartApiUrl(endpoint.Address);
 0101        if (string.IsNullOrEmpty(localUrl))
 102        {
 0103            _logger.LogWarning("Unable to respond to server discovery request because the local ip address could not be 
 0104            return;
 105        }
 106
 0107        var response = new ServerDiscoveryInfo(localUrl, _appHost.SystemId, _appHost.FriendlyName);
 108        try
 109        {
 0110            _logger.LogDebug("Sending AutoDiscovery response");
 0111            await broadCastUdpClient
 0112                .SendAsync(JsonSerializer.SerializeToUtf8Bytes(response).AsMemory(), endpoint, cancellationToken)
 0113                .ConfigureAwait(false);
 0114        }
 0115        catch (SocketException ex)
 116        {
 0117            _logger.LogError(ex, "Error sending response message");
 0118        }
 0119    }
 120}