| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 | using System;using System.Net;using System.Net.Sockets;using System.Text;using System.Text.Json;using System.Threading;using System.Threading.Tasks;using MediaBrowser.Controller;using MediaBrowser.Model.ApiClient;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.Logging;namespace Emby.Server.Implementations.Udp{    /// <summary>    /// Provides a Udp Server.    /// </summary>    public sealed class UdpServer : IDisposable    {        /// <summary>        /// The _logger.        /// </summary>        private readonly ILogger _logger;        private readonly IServerApplicationHost _appHost;        private readonly IConfiguration _config;        /// <summary>        /// Address Override Configuration Key.        /// </summary>        public const string AddressOverrideConfigKey = "PublishedServerUrl";        private Socket _udpSocket;        private IPEndPoint _endpoint;        private readonly byte[] _receiveBuffer = new byte[8192];        private bool _disposed = false;        /// <summary>        /// Initializes a new instance of the <see cref="UdpServer" /> class.        /// </summary>        public UdpServer(ILogger logger, IServerApplicationHost appHost, IConfiguration configuration)        {            _logger = logger;            _appHost = appHost;            _config = configuration;        }        private async Task RespondToV2Message(string messageText, EndPoint endpoint, CancellationToken cancellationToken)        {            string localUrl = !string.IsNullOrEmpty(_config[AddressOverrideConfigKey])                ? _config[AddressOverrideConfigKey]                : await _appHost.GetLocalApiUrl(cancellationToken).ConfigureAwait(false);            if (!string.IsNullOrEmpty(localUrl))            {                var response = new ServerDiscoveryInfo                {                    Address = localUrl,                    Id = _appHost.SystemId,                    Name = _appHost.FriendlyName                };                try                {                    await _udpSocket.SendToAsync(JsonSerializer.SerializeToUtf8Bytes(response), SocketFlags.None, endpoint).ConfigureAwait(false);                }                catch (SocketException ex)                {                    _logger.LogError(ex, "Error sending response message");                }                var parts = messageText.Split('|');                if (parts.Length > 1)                {                    _appHost.EnableLoopback(parts[1]);                }            }            else            {                _logger.LogWarning("Unable to respond to udp request because the local ip address could not be determined.");            }        }        /// <summary>        /// Starts the specified port.        /// </summary>        /// <param name="port">The port.</param>        /// <param name="cancellationToken"></param>        public void Start(int port, CancellationToken cancellationToken)        {            _endpoint = new IPEndPoint(IPAddress.Any, port);            _udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);            _udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);            _udpSocket.Bind(_endpoint);            _ = Task.Run(async () => await BeginReceiveAsync(cancellationToken).ConfigureAwait(false), cancellationToken).ConfigureAwait(false);        }        private async Task BeginReceiveAsync(CancellationToken cancellationToken)        {            while (!cancellationToken.IsCancellationRequested)            {                var infiniteTask = Task.Delay(-1, cancellationToken);                try                {                    var task = _udpSocket.ReceiveFromAsync(_receiveBuffer, SocketFlags.None, _endpoint);                    await Task.WhenAny(task, infiniteTask).ConfigureAwait(false);                    if (!task.IsCompleted)                    {                        return;                    }                    var result = task.Result;                    var text = Encoding.UTF8.GetString(_receiveBuffer, 0, result.ReceivedBytes);                    if (text.Contains("who is JellyfinServer?", StringComparison.OrdinalIgnoreCase))                    {                        await RespondToV2Message(text, result.RemoteEndPoint, cancellationToken).ConfigureAwait(false);                    }                }                catch (SocketException ex)                {                    _logger.LogError(ex, "Failed to receive data from socket");                }                catch (OperationCanceledException)                {                    // Don't throw                }            }        }        /// <inheritdoc />        public void Dispose()        {            if (_disposed)            {                return;            }            _udpSocket?.Dispose();            GC.SuppressFinalize(this);        }    }}
 |