diff options
Diffstat (limited to 'Emby.Server.Implementations/Net/SocketFactory.cs')
| -rw-r--r-- | Emby.Server.Implementations/Net/SocketFactory.cs | 92 |
1 files changed, 49 insertions, 43 deletions
diff --git a/Emby.Server.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs index 303875df5..2bcd5eab2 100644 --- a/Emby.Server.Implementations/Net/SocketFactory.cs +++ b/Emby.Server.Implementations/Net/SocketFactory.cs @@ -1,69 +1,76 @@ -#pragma warning disable CS1591 - using System; +using System.Linq; using System.Net; +using System.Net.NetworkInformation; using System.Net.Sockets; using MediaBrowser.Model.Net; namespace Emby.Server.Implementations.Net { + /// <summary> + /// Factory class to create different kinds of sockets. + /// </summary> 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) { + var interfaceAddress = bindInterface.Address; + ArgumentNullException.ThrowIfNull(interfaceAddress); + 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(interfaceAddress, 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 +82,35 @@ 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; - - try - { - // seeing occasional exceptions thrown on qnap - // System.Net.Sockets.SocketException (0x80004005): Protocol not available - retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - } - catch (SocketException) - { - } + var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 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); + socket.MulticastLoopback = false; + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true); + socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive); + + if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + { + socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastAddress)); + socket.Bind(new IPEndPoint(multicastAddress, localPort)); + } + else + { + // Only create socket if interface supports multicast + var interfaceIndex = bindInterface.Index; + var interfaceIndexSwapped = IPAddress.HostToNetworkOrder(interfaceIndex); + + socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(multicastAddress, interfaceIndex)); + socket.Bind(new IPEndPoint(bindIPAddress, localPort)); + } + + return socket; } catch { - retVal?.Dispose(); + socket.Dispose(); throw; } |
