@ -1,5 +1,3 @@
#nullable disable
using System ;
using System ;
using System.Net ;
using System.Net ;
using System.Net.Sockets ;
using System.Net.Sockets ;
@ -19,6 +17,11 @@ namespace Emby.Server.Implementations.Udp
/// </summary>
/// </summary>
public sealed class UdpServer : IDisposable
public sealed class UdpServer : IDisposable
{
{
/// <summary>
/// Address Override Configuration Key.
/// </summary>
public const string AddressOverrideConfigKey = "PublishedServerUrl" ;
/// <summary>
/// <summary>
/// The _logger.
/// The _logger.
/// </summary>
/// </summary>
@ -26,11 +29,6 @@ namespace Emby.Server.Implementations.Udp
private readonly IServerApplicationHost _appHost ;
private readonly IServerApplicationHost _appHost ;
private readonly IConfiguration _config ;
private readonly IConfiguration _config ;
/// <summary>
/// Address Override Configuration Key.
/// </summary>
public const string AddressOverrideConfigKey = "PublishedServerUrl" ;
private Socket _udpSocket ;
private Socket _udpSocket ;
private IPEndPoint _endpoint ;
private IPEndPoint _endpoint ;
private readonly byte [ ] _receiveBuffer = new byte [ 8192 ] ;
private readonly byte [ ] _receiveBuffer = new byte [ 8192 ] ;
@ -40,49 +38,58 @@ namespace Emby.Server.Implementations.Udp
/// <summary>
/// <summary>
/// Initializes a new instance of the <see cref="UdpServer" /> class.
/// Initializes a new instance of the <see cref="UdpServer" /> class.
/// </summary>
/// </summary>
public UdpServer ( ILogger logger , IServerApplicationHost appHost , IConfiguration configuration )
/// <param name="logger">The logger.</param>
/// <param name="appHost">The application host.</param>
/// <param name="configuration">The configuration manager.</param>
/// <param name="port">The port.</param>
public UdpServer (
ILogger logger ,
IServerApplicationHost appHost ,
IConfiguration configuration ,
int port )
{
{
_logger = logger ;
_logger = logger ;
_appHost = appHost ;
_appHost = appHost ;
_config = configuration ;
_config = configuration ;
_endpoint = new IPEndPoint ( IPAddress . Any , port ) ;
_udpSocket = new Socket ( AddressFamily . InterNetwork , SocketType . Dgram , ProtocolType . Udp ) ;
_udpSocket . SetSocketOption ( SocketOptionLevel . Socket , SocketOptionName . ReuseAddress , true ) ;
}
}
private async Task RespondToV2Message ( string messageText , EndPoint endpoint , CancellationToken cancellationToken )
private async Task RespondToV2Message ( string messageText , EndPoint endpoint , CancellationToken cancellationToken )
{
{
string localUrl = ! string . IsNullOrEmpty ( _config [ AddressOverrideConfigKey ] )
string? localUrl = _config [ AddressOverrideConfigKey ] ;
? _config [ AddressOverrideConfigKey ]
if ( string . IsNullOrEmpty ( localUrl ) )
: _appHost . GetSmartApiUrl ( ( ( IPEndPoint ) endpoint ) . Address ) ;
{
localUrl = _appHost . GetSmartApiUrl ( ( ( IPEndPoint ) endpoint ) . Address ) ;
}
if ( ! string . IsNullOrEmpty ( localUrl ) )
if ( string . IsNullOrEmpty ( localUrl ) )
{
{
var response = new ServerDiscoveryInfo ( localUrl , _appHost . SystemId , _appHost . FriendlyName ) ;
_logger . LogWarning ( "Unable to respond to udp request because the local ip address could not be determined." ) ;
return ;
}
try
var response = new ServerDiscoveryInfo ( localUrl , _appHost . SystemId , _appHost . FriendlyName ) ;
{
await _udpSocket . SendToAsync ( JsonSerializer . SerializeToUtf8Bytes ( response ) , SocketFlags . None , endpoint ) . ConfigureAwait ( false ) ;
try
}
{
catch ( SocketException ex )
await _udpSocket . SendToAsync ( JsonSerializer . SerializeToUtf8Bytes ( response ) , SocketFlags . None , endpoint ) . ConfigureAwait ( false ) ;
{
_logger . LogError ( ex , "Error sending response message" ) ;
}
}
}
else
catch ( SocketException ex )
{
{
_logger . Log Warning( "Unable to respond to udp request because the local ip address could not be determined. ") ;
_logger . Log Error( ex , "Error sending response message ") ;
}
}
}
}
/// <summary>
/// <summary>
/// Starts the specified port.
/// Starts the specified port.
/// </summary>
/// </summary>
/// <param name="port">The port.</param>
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
public void Start ( int port , CancellationToken cancellationToken )
public void Start ( 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 ) ;
_udpSocket . Bind ( _endpoint ) ;
_ = Task . Run ( async ( ) = > await BeginReceiveAsync ( cancellationToken ) . ConfigureAwait ( false ) , cancellationToken ) . ConfigureAwait ( false ) ;
_ = Task . Run ( async ( ) = > await BeginReceiveAsync ( cancellationToken ) . ConfigureAwait ( false ) , cancellationToken ) . ConfigureAwait ( false ) ;
@ -90,9 +97,9 @@ namespace Emby.Server.Implementations.Udp
private async Task BeginReceiveAsync ( CancellationToken cancellationToken )
private async Task BeginReceiveAsync ( CancellationToken cancellationToken )
{
{
var infiniteTask = Task . Delay ( - 1 , cancellationToken ) ;
while ( ! cancellationToken . IsCancellationRequested )
while ( ! cancellationToken . IsCancellationRequested )
{
{
var infiniteTask = Task . Delay ( - 1 , cancellationToken ) ;
try
try
{
{
var task = _udpSocket . ReceiveFromAsync ( _receiveBuffer , SocketFlags . None , _endpoint ) ;
var task = _udpSocket . ReceiveFromAsync ( _receiveBuffer , SocketFlags . None , _endpoint ) ;