diff options
| author | Joshua M. Boniface <joshua@boniface.me> | 2023-07-03 13:16:21 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-07-03 13:16:21 -0400 |
| commit | 93b400343ebd2ef92e740d804ceaaedb01da30cf (patch) | |
| tree | 0190174ceb0df9c3bcd23647548d80be48425214 /Emby.Server.Implementations | |
| parent | 44cc3ee44286dd5b3a626df79a8a576ad4a0d34a (diff) | |
| parent | e233a3b074d7696e4c05846aaf04434dafaf4031 (diff) | |
Merge pull request #8147 from Shadowghost/network-rewrite
Diffstat (limited to 'Emby.Server.Implementations')
9 files changed, 106 insertions, 338 deletions
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 7969577bc..dd90a8950 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -475,8 +475,8 @@ namespace Emby.Server.Implementations } var networkConfiguration = ConfigurationManager.GetNetworkConfiguration(); - HttpPort = networkConfiguration.HttpServerPortNumber; - HttpsPort = networkConfiguration.HttpsPortNumber; + HttpPort = networkConfiguration.InternalHttpPort; + HttpsPort = networkConfiguration.InternalHttpsPort; // Safeguard against invalid configuration if (HttpPort == HttpsPort) @@ -785,8 +785,8 @@ namespace Emby.Server.Implementations if (HttpPort != 0 && HttpsPort != 0) { // Need to restart if ports have changed - if (networkConfiguration.HttpServerPortNumber != HttpPort - || networkConfiguration.HttpsPortNumber != HttpsPort) + if (networkConfiguration.InternalHttpPort != HttpPort + || networkConfiguration.InternalHttpsPort != HttpsPort) { if (ConfigurationManager.Configuration.IsPortAuthorized) { @@ -995,7 +995,7 @@ namespace Emby.Server.Implementations return PublishedServerUrl.Trim('/'); } - string smart = NetManager.GetBindInterface(remoteAddr, out var port); + string smart = NetManager.GetBindAddress(remoteAddr, out var port); return GetLocalApiUrl(smart.Trim('/'), null, port); } @@ -1006,7 +1006,9 @@ namespace Emby.Server.Implementations if (ConfigurationManager.GetNetworkConfiguration().EnablePublishedServerUriByRequest) { int? requestPort = request.Host.Port; - if ((requestPort == 80 && string.Equals(request.Scheme, "http", StringComparison.OrdinalIgnoreCase)) || (requestPort == 443 && string.Equals(request.Scheme, "https", StringComparison.OrdinalIgnoreCase))) + if (requestPort == null + || (requestPort == 80 && string.Equals(request.Scheme, "http", StringComparison.OrdinalIgnoreCase)) + || (requestPort == 443 && string.Equals(request.Scheme, "https", StringComparison.OrdinalIgnoreCase))) { requestPort = -1; } @@ -1027,15 +1029,15 @@ namespace Emby.Server.Implementations return PublishedServerUrl.Trim('/'); } - string smart = NetManager.GetBindInterface(hostname, out var port); + string smart = NetManager.GetBindAddress(hostname, out var port); return GetLocalApiUrl(smart.Trim('/'), null, port); } /// <inheritdoc/> - public string GetApiUrlForLocalAccess(IPObject hostname = null, bool allowHttps = true) + public string GetApiUrlForLocalAccess(IPAddress ipAddress = null, bool allowHttps = true) { // With an empty source, the port will be null - var smart = NetManager.GetBindInterface(hostname ?? IPHost.None, out _); + var smart = NetManager.GetBindAddress(ipAddress, out _, true); var scheme = !allowHttps ? Uri.UriSchemeHttp : null; int? port = !allowHttps ? HttpPort : null; return GetLocalApiUrl(smart, scheme, port); diff --git a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index 06e57ad12..d6da597b8 100644 --- a/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/Emby.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -57,7 +57,7 @@ namespace Emby.Server.Implementations.EntryPoints return new StringBuilder(32) .Append(config.EnableUPnP).Append(Separator) - .Append(config.PublicPort).Append(Separator) + .Append(config.PublicHttpPort).Append(Separator) .Append(config.PublicHttpsPort).Append(Separator) .Append(_appHost.HttpPort).Append(Separator) .Append(_appHost.HttpsPort).Append(Separator) @@ -146,7 +146,7 @@ namespace Emby.Server.Implementations.EntryPoints private IEnumerable<Task> CreatePortMaps(INatDevice device) { var config = _config.GetNetworkConfiguration(); - yield return CreatePortMap(device, _appHost.HttpPort, config.PublicPort); + yield return CreatePortMap(device, _appHost.HttpPort, config.PublicHttpPort); if (_appHost.ListenWithHttps) { diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs index e45baedd7..2839e163e 100644 --- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs +++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs @@ -1,10 +1,14 @@ 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 Jellyfin.Networking.Configuration; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Plugins; using Microsoft.Extensions.Configuration; @@ -29,11 +33,13 @@ namespace Emby.Server.Implementations.EntryPoints private readonly IServerApplicationHost _appHost; private readonly IConfiguration _config; private readonly IConfigurationManager _configurationManager; + private readonly INetworkManager _networkManager; + private readonly bool _enableMultiSocketBinding; /// <summary> /// The UDP server. /// </summary> - private UdpServer? _udpServer; + private List<UdpServer> _udpServers; private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private bool _disposed = false; @@ -44,16 +50,21 @@ namespace Emby.Server.Implementations.EntryPoints /// <param name="appHost">Instance of the <see cref="IServerApplicationHost"/> interface.</param> /// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param> /// <param name="configurationManager">Instance of the <see cref="IConfigurationManager"/> interface.</param> + /// <param name="networkManager">Instance of the <see cref="INetworkManager"/> interface.</param> public UdpServerEntryPoint( ILogger<UdpServerEntryPoint> logger, IServerApplicationHost appHost, IConfiguration configuration, - IConfigurationManager configurationManager) + IConfigurationManager configurationManager, + INetworkManager networkManager) { _logger = logger; _appHost = appHost; _config = configuration; _configurationManager = configurationManager; + _networkManager = networkManager; + _udpServers = new List<UdpServer>(); + _enableMultiSocketBinding = OperatingSystem.IsWindows() || OperatingSystem.IsLinux(); } /// <inheritdoc /> @@ -68,8 +79,32 @@ namespace Emby.Server.Implementations.EntryPoints try { - _udpServer = new UdpServer(_logger, _appHost, _config, PortNumber); - _udpServer.Start(_cancellationTokenSource.Token); + if (_enableMultiSocketBinding) + { + // Add global broadcast socket + var server = new UdpServer(_logger, _appHost, _config, IPAddress.Broadcast, PortNumber); + server.Start(_cancellationTokenSource.Token); + _udpServers.Add(server); + + // Add bind address specific broadcast sockets + // IPv6 is currently unsupported + var validInterfaces = _networkManager.GetInternalBindAddresses().Where(i => i.AddressFamily == AddressFamily.InterNetwork); + foreach (var intf in validInterfaces) + { + var broadcastAddress = NetworkExtensions.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 + { + var server = new UdpServer(_logger, _appHost, _config, IPAddress.Any, PortNumber); + server.Start(_cancellationTokenSource.Token); + _udpServers.Add(server); + } } catch (SocketException ex) { @@ -97,9 +132,12 @@ namespace Emby.Server.Implementations.EntryPoints _cancellationTokenSource.Cancel(); _cancellationTokenSource.Dispose(); - _udpServer?.Dispose(); - _udpServer = null; + foreach (var server in _udpServers) + { + server.Dispose(); + } + _udpServers.Clear(); _disposed = true; } } diff --git a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs index 4f7d1c40a..ecfb242f6 100644 --- a/Emby.Server.Implementations/HttpServer/WebSocketManager.cs +++ b/Emby.Server.Implementations/HttpServer/WebSocketManager.cs @@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.HttpServer using var connection = new WebSocketConnection( _loggerFactory.CreateLogger<WebSocketConnection>(), webSocket, - context.GetNormalizedRemoteIp()) + context.GetNormalizedRemoteIP()) { OnReceive = ProcessWebSocketMessageReceived }; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 98bbc1540..1795e85a3 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -661,18 +661,18 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun // Need a way to set the Receive timeout on the socket otherwise this might never timeout? try { - await udpClient.SendToAsync(discBytes, 0, discBytes.Length, new IPEndPoint(IPAddress.Parse("255.255.255.255"), 65001), cancellationToken).ConfigureAwait(false); + await udpClient.SendToAsync(discBytes, new IPEndPoint(IPAddress.Broadcast, 65001), cancellationToken).ConfigureAwait(false); var receiveBuffer = new byte[8192]; while (!cancellationToken.IsCancellationRequested) { - var response = await udpClient.ReceiveAsync(receiveBuffer, 0, receiveBuffer.Length, cancellationToken).ConfigureAwait(false); - var deviceIp = response.RemoteEndPoint.Address.ToString(); + var response = await udpClient.ReceiveMessageFromAsync(receiveBuffer, new IPEndPoint(IPAddress.Any, 0), cancellationToken).ConfigureAwait(false); + var deviceIP = ((IPEndPoint)response.RemoteEndPoint).Address.ToString(); - // check to make sure we have enough bytes received to be a valid message and make sure the 2nd byte is the discover reply byte - if (response.ReceivedBytes > 13 && response.Buffer[1] == 3) + // Check to make sure we have enough bytes received to be a valid message and make sure the 2nd byte is the discover reply byte + if (response.ReceivedBytes > 13 && receiveBuffer[1] == 3) { - var deviceAddress = "http://" + deviceIp; + var deviceAddress = "http://" + deviceIP; var info = await TryGetTunerHostInfo(deviceAddress, cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs index 7bc209d6b..a8b090635 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs @@ -48,10 +48,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun GC.SuppressFinalize(this); } - public async Task<bool> CheckTunerAvailability(IPAddress remoteIp, int tuner, CancellationToken cancellationToken) + public async Task<bool> CheckTunerAvailability(IPAddress remoteIP, int tuner, CancellationToken cancellationToken) { using var client = new TcpClient(); - await client.ConnectAsync(remoteIp, HdHomeRunPort, cancellationToken).ConfigureAwait(false); + await client.ConnectAsync(remoteIP, HdHomeRunPort, cancellationToken).ConfigureAwait(false); using var stream = client.GetStream(); return await CheckTunerAvailability(stream, tuner, cancellationToken).ConfigureAwait(false); @@ -75,9 +75,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - public async Task StartStreaming(IPAddress remoteIp, IPAddress localIp, int localPort, IHdHomerunChannelCommands commands, int numTuners, CancellationToken cancellationToken) + public async Task StartStreaming(IPAddress remoteIP, IPAddress localIP, int localPort, IHdHomerunChannelCommands commands, int numTuners, CancellationToken cancellationToken) { - _remoteEndPoint = new IPEndPoint(remoteIp, HdHomeRunPort); + _remoteEndPoint = new IPEndPoint(remoteIP, HdHomeRunPort); _tcpClient = new TcpClient(); await _tcpClient.ConnectAsync(_remoteEndPoint, cancellationToken).ConfigureAwait(false); @@ -125,7 +125,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - var targetValue = string.Format(CultureInfo.InvariantCulture, "rtp://{0}:{1}", localIp, localPort); + var targetValue = string.Format(CultureInfo.InvariantCulture, "rtp://{0}:{1}", localIP, localPort); var targetMsgLen = WriteSetMessage(buffer, i, "target", targetValue, lockKeyValue); await stream.WriteAsync(buffer.AsMemory(0, targetMsgLen), cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs index 303875df5..51e92953d 100644 --- a/Emby.Server.Implementations/Net/SocketFactory.cs +++ b/Emby.Server.Implementations/Net/SocketFactory.cs @@ -10,60 +10,63 @@ namespace Emby.Server.Implementations.Net public class SocketFactory : ISocketFactory { /// <inheritdoc /> - public ISocket CreateUdpBroadcastSocket(int localPort) + public Socket CreateUdpBroadcastSocket(int localPort) { if (localPort < 0) { throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); } - var retVal = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); try { - retVal.EnableBroadcast = true; - retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); + socket.EnableBroadcast = true; + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); + socket.Bind(new IPEndPoint(IPAddress.Any, localPort)); - return new UdpSocket(retVal, localPort, IPAddress.Any); + return socket; } catch { - retVal?.Dispose(); + socket?.Dispose(); throw; } } /// <inheritdoc /> - public ISocket CreateSsdpUdpSocket(IPAddress localIp, int localPort) + public Socket CreateSsdpUdpSocket(IPData bindInterface, int localPort) { + ArgumentNullException.ThrowIfNull(bindInterface.Address); + if (localPort < 0) { throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); } - var retVal = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); try { - retVal.EnableBroadcast = true; - retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + socket.Bind(new IPEndPoint(bindInterface.Address, localPort)); - retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddress.Parse("239.255.255.250"), localIp)); - return new UdpSocket(retVal, localPort, localIp); + return socket; } catch { - retVal?.Dispose(); + socket?.Dispose(); throw; } } /// <inheritdoc /> - public ISocket CreateUdpMulticastSocket(IPAddress ipAddress, int multicastTimeToLive, int localPort) + public Socket CreateUdpMulticastSocket(IPAddress multicastAddress, IPData bindInterface, int multicastTimeToLive, int localPort) { - ArgumentNullException.ThrowIfNull(ipAddress); + var bindIPAddress = bindInterface.Address; + ArgumentNullException.ThrowIfNull(multicastAddress); + ArgumentNullException.ThrowIfNull(bindIPAddress); if (multicastTimeToLive <= 0) { @@ -75,36 +78,26 @@ namespace Emby.Server.Implementations.Net throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); } - var retVal = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - - retVal.ExclusiveAddressUse = false; + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); try { - // seeing occasional exceptions thrown on qnap - // System.Net.Sockets.SocketException (0x80004005): Protocol not available - retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - } - catch (SocketException) - { - } - - try - { - retVal.EnableBroadcast = true; - // retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); - retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive); - - var localIp = IPAddress.Any; - - retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ipAddress, localIp)); - retVal.MulticastLoopback = true; - - return new UdpSocket(retVal, localPort, localIp); + var interfaceIndex = bindInterface.Index; + var interfaceIndexSwapped = (int)IPAddress.HostToNetworkOrder(interfaceIndex); + + socket.MulticastLoopback = false; + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true); + socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive); + socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, interfaceIndexSwapped); + socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastAddress, interfaceIndex)); + socket.Bind(new IPEndPoint(multicastAddress, localPort)); + + return socket; } catch { - retVal?.Dispose(); + socket?.Dispose(); throw; } diff --git a/Emby.Server.Implementations/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs deleted file mode 100644 index 577b79283..000000000 --- a/Emby.Server.Implementations/Net/UdpSocket.cs +++ /dev/null @@ -1,267 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Net; - -namespace Emby.Server.Implementations.Net -{ - // THIS IS A LINKED FILE - SHARED AMONGST MULTIPLE PLATFORMS - // Be careful to check any changes compile and work for all platform projects it is shared in. - - public sealed class UdpSocket : ISocket, IDisposable - { - private readonly int _localPort; - - private readonly SocketAsyncEventArgs _receiveSocketAsyncEventArgs = new SocketAsyncEventArgs() - { - SocketFlags = SocketFlags.None - }; - - private readonly SocketAsyncEventArgs _sendSocketAsyncEventArgs = new SocketAsyncEventArgs() - { - SocketFlags = SocketFlags.None - }; - - private Socket _socket; - private bool _disposed = false; - private TaskCompletionSource<SocketReceiveResult> _currentReceiveTaskCompletionSource; - private TaskCompletionSource<int> _currentSendTaskCompletionSource; - - public UdpSocket(Socket socket, int localPort, IPAddress ip) - { - ArgumentNullException.ThrowIfNull(socket); - - _socket = socket; - _localPort = localPort; - LocalIPAddress = ip; - - _socket.Bind(new IPEndPoint(ip, _localPort)); - - InitReceiveSocketAsyncEventArgs(); - } - - public UdpSocket(Socket socket, IPEndPoint endPoint) - { - ArgumentNullException.ThrowIfNull(socket); - - _socket = socket; - _socket.Connect(endPoint); - - InitReceiveSocketAsyncEventArgs(); - } - - public Socket Socket => _socket; - - public IPAddress LocalIPAddress { get; } - - private void InitReceiveSocketAsyncEventArgs() - { - var receiveBuffer = new byte[8192]; - _receiveSocketAsyncEventArgs.SetBuffer(receiveBuffer, 0, receiveBuffer.Length); - _receiveSocketAsyncEventArgs.Completed += OnReceiveSocketAsyncEventArgsCompleted; - - var sendBuffer = new byte[8192]; - _sendSocketAsyncEventArgs.SetBuffer(sendBuffer, 0, sendBuffer.Length); - _sendSocketAsyncEventArgs.Completed += OnSendSocketAsyncEventArgsCompleted; - } - - private void OnReceiveSocketAsyncEventArgsCompleted(object sender, SocketAsyncEventArgs e) - { - var tcs = _currentReceiveTaskCompletionSource; - if (tcs is not null) - { - _currentReceiveTaskCompletionSource = null; - - if (e.SocketError == SocketError.Success) - { - tcs.TrySetResult(new SocketReceiveResult - { - Buffer = e.Buffer, - ReceivedBytes = e.BytesTransferred, - RemoteEndPoint = e.RemoteEndPoint as IPEndPoint, - LocalIPAddress = LocalIPAddress - }); - } - else - { - tcs.TrySetException(new SocketException((int)e.SocketError)); - } - } - } - - private void OnSendSocketAsyncEventArgsCompleted(object sender, SocketAsyncEventArgs e) - { - var tcs = _currentSendTaskCompletionSource; - if (tcs is not null) - { - _currentSendTaskCompletionSource = null; - - if (e.SocketError == SocketError.Success) - { - tcs.TrySetResult(e.BytesTransferred); - } - else - { - tcs.TrySetException(new SocketException((int)e.SocketError)); - } - } - } - - public IAsyncResult BeginReceive(byte[] buffer, int offset, int count, AsyncCallback callback) - { - ThrowIfDisposed(); - - EndPoint receivedFromEndPoint = new IPEndPoint(IPAddress.Any, 0); - - return _socket.BeginReceiveFrom(buffer, offset, count, SocketFlags.None, ref receivedFromEndPoint, callback, buffer); - } - - public int Receive(byte[] buffer, int offset, int count) - { - ThrowIfDisposed(); - - return _socket.Receive(buffer, 0, buffer.Length, SocketFlags.None); - } - - public SocketReceiveResult EndReceive(IAsyncResult result) - { - ThrowIfDisposed(); - - var sender = new IPEndPoint(IPAddress.Any, 0); - var remoteEndPoint = (EndPoint)sender; - - var receivedBytes = _socket.EndReceiveFrom(result, ref remoteEndPoint); - - var buffer = (byte[])result.AsyncState; - - return new SocketReceiveResult - { - ReceivedBytes = receivedBytes, - RemoteEndPoint = (IPEndPoint)remoteEndPoint, - Buffer = buffer, - LocalIPAddress = LocalIPAddress - }; - } - - public Task<SocketReceiveResult> ReceiveAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - ThrowIfDisposed(); - - var taskCompletion = new TaskCompletionSource<SocketReceiveResult>(TaskCreationOptions.RunContinuationsAsynchronously); - bool isResultSet = false; - - Action<IAsyncResult> callback = callbackResult => - { - try - { - if (!isResultSet) - { - isResultSet = true; - taskCompletion.TrySetResult(EndReceive(callbackResult)); - } - } - catch (Exception ex) - { - taskCompletion.TrySetException(ex); - } - }; - - var result = BeginReceive(buffer, offset, count, new AsyncCallback(callback)); - - if (result.CompletedSynchronously) - { - callback(result); - return taskCompletion.Task; - } - - cancellationToken.Register(() => taskCompletion.TrySetCanceled()); - - return taskCompletion.Task; - } - - public Task SendToAsync(byte[] buffer, int offset, int bytes, IPEndPoint endPoint, CancellationToken cancellationToken) - { - ThrowIfDisposed(); - - var taskCompletion = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously); - bool isResultSet = false; - - Action<IAsyncResult> callback = callbackResult => - { - try - { - if (!isResultSet) - { - isResultSet = true; - taskCompletion.TrySetResult(EndSendTo(callbackResult)); - } - } - catch (Exception ex) - { - taskCompletion.TrySetException(ex); - } - }; - - var result = BeginSendTo(buffer, offset, bytes, endPoint, new AsyncCallback(callback), null); - - if (result.CompletedSynchronously) - { - callback(result); - return taskCompletion.Task; - } - - cancellationToken.Register(() => taskCompletion.TrySetCanceled()); - - return taskCompletion.Task; - } - - public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, IPEndPoint endPoint, AsyncCallback callback, object state) - { - ThrowIfDisposed(); - - return _socket.BeginSendTo(buffer, offset, size, SocketFlags.None, endPoint, callback, state); - } - - public int EndSendTo(IAsyncResult result) - { - ThrowIfDisposed(); - - return _socket.EndSendTo(result); - } - - private void ThrowIfDisposed() - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(UdpSocket)); - } - } - - /// <inheritdoc /> - public void Dispose() - { - if (_disposed) - { - return; - } - - _socket?.Dispose(); - _receiveSocketAsyncEventArgs.Dispose(); - _sendSocketAsyncEventArgs.Dispose(); - _currentReceiveTaskCompletionSource?.TrySetCanceled(); - _currentSendTaskCompletionSource?.TrySetCanceled(); - - _socket = null; - _currentReceiveTaskCompletionSource = null; - _currentSendTaskCompletionSource = null; - - _disposed = true; - } - } -} diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs index 937e792f5..a3bbd6df0 100644 --- a/Emby.Server.Implementations/Udp/UdpServer.cs +++ b/Emby.Server.Implementations/Udp/UdpServer.cs @@ -37,18 +37,20 @@ namespace Emby.Server.Implementations.Udp /// <param name="logger">The logger.</param> /// <param name="appHost">The application host.</param> /// <param name="configuration">The configuration manager.</param> + /// <param name="bindAddress"> The bind address.</param> /// <param name="port">The port.</param> public UdpServer( ILogger logger, IServerApplicationHost appHost, IConfiguration configuration, + IPAddress bindAddress, int port) { _logger = logger; _appHost = appHost; _config = configuration; - _endpoint = new IPEndPoint(IPAddress.Any, port); + _endpoint = new IPEndPoint(bindAddress, port); _udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); _udpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); |
