示例#1
0
        //returns the port number used...
        public static int CreateListenSocketsOnUniquePort(IPAddress ipv4Address, IPAddress ipv6Address, int receiveBufferSize, int timeToLive, out UdpSocket ipv4Socket, out UdpSocket ipv6Socket)
        {
            // We need both IPv4 and IPv6 on the same port. We can't atomicly bind for IPv4 and IPv6,
            // so we try 10 times, which even with a 50% failure rate will statistically succeed 99.9% of the time.
            //
            // We look in the range of 49152-65534 for Vista default behavior parity.
            // http://www.iana.org/assignments/port-numbers
            //
            // We also grab the 10 random numbers in a row to reduce collisions between multiple people somehow
            // colliding on the same seed.
            const int retries       = 10;
            const int lowWatermark  = 49152;
            const int highWatermark = 65535;

            ipv4Socket = null;
            ipv6Socket = null;

            int[] portNumbers = new int[retries];

            Random randomNumberGenerator = new Random(AppDomain.CurrentDomain.GetHashCode() | Environment.TickCount);

            for (int i = 0; i < retries; i++)
            {
                portNumbers[i] = randomNumberGenerator.Next(lowWatermark, highWatermark);
            }


            int port = -1;

            for (int i = 0; i < retries; i++)
            {
                port = portNumbers[i];
                try
                {
                    ipv4Socket = UdpUtility.CreateUnicastListenSocket(ipv4Address, ref port, receiveBufferSize, timeToLive);
                    ipv6Socket = UdpUtility.CreateUnicastListenSocket(ipv6Address, ref port, receiveBufferSize, timeToLive);
                    break;
                }
                catch (AddressAlreadyInUseException)
                {
                    if (ipv4Socket != null)
                    {
                        ipv4Socket.Close();
                        ipv4Socket = null;
                    }
                    ipv6Socket = null;
                }
                catch (AddressAccessDeniedException)
                {
                    if (ipv4Socket != null)
                    {
                        ipv4Socket.Close();
                        ipv4Socket = null;
                    }
                    ipv6Socket = null;
                }
            }

            if (ipv4Socket == null)
            {
                throw FxTrace.Exception.AsError(new AddressAlreadyInUseException(SR.UniquePortNotAvailable));
            }

            Fx.Assert(ipv4Socket != null, "An exception should have been thrown if the ipv4Socket socket is null");
            Fx.Assert(ipv6Socket != null, "An exception should have been thrown if the ipv6Socket socket is null");
            Fx.Assert(port > 0, "The port number should have been greater than 0. Actual value was " + port);

            return(port);
        }
        void InitSockets(bool updateListenPort)
        {
            bool ipV4;
            bool ipV6;

            UdpUtility.CheckSocketSupport(out ipV4, out ipV6);

            Fx.Assert(this.listenSockets == null, "listen sockets should only be initialized once");

            this.listenSockets = new List <UdpSocket>();

            int port = (this.listenUri.IsDefaultPort ? 0 : this.listenUri.Port);

            if (this.listenUri.HostNameType == UriHostNameType.IPv6 ||
                this.listenUri.HostNameType == UriHostNameType.IPv4)
            {
                UdpUtility.ThrowOnUnsupportedHostNameType(this.listenUri);

                IPAddress address = IPAddress.Parse(this.listenUri.DnsSafeHost);

                if (UdpUtility.IsMulticastAddress(address))
                {
                    this.isMulticast = true;

                    NetworkInterface[] adapters = UdpUtility.GetMulticastInterfaces(udpTransportBindingElement.MulticastInterfaceId);

                    //if listening on a specific adapter, don't disable multicast loopback on that adapter.
                    bool allowMulticastLoopback = !string.IsNullOrEmpty(this.udpTransportBindingElement.MulticastInterfaceId);

                    for (int i = 0; i < adapters.Length; i++)
                    {
                        if (adapters[i].OperationalStatus == OperationalStatus.Up)
                        {
                            IPInterfaceProperties properties = adapters[i].GetIPProperties();
                            bool isLoopbackAdapter           = adapters[i].NetworkInterfaceType == NetworkInterfaceType.Loopback;

                            if (isLoopbackAdapter)
                            {
                                int interfaceIndex;
                                if (UdpUtility.TryGetLoopbackInterfaceIndex(adapters[i], address.AddressFamily == AddressFamily.InterNetwork, out interfaceIndex))
                                {
                                    listenSockets.Add(UdpUtility.CreateListenSocket(address, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize, this.udpTransportBindingElement.TimeToLive,
                                                                                    interfaceIndex, allowMulticastLoopback, isLoopbackAdapter));
                                }
                            }
                            else if (this.listenUri.HostNameType == UriHostNameType.IPv6)
                            {
                                if (adapters[i].Supports(NetworkInterfaceComponent.IPv6))
                                {
                                    IPv6InterfaceProperties v6Properties = properties.GetIPv6Properties();

                                    if (v6Properties != null)
                                    {
                                        listenSockets.Add(UdpUtility.CreateListenSocket(address, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize,
                                                                                        this.udpTransportBindingElement.TimeToLive, v6Properties.Index, allowMulticastLoopback, isLoopbackAdapter));
                                    }
                                }
                            }
                            else
                            {
                                if (adapters[i].Supports(NetworkInterfaceComponent.IPv4))
                                {
                                    IPv4InterfaceProperties v4Properties = properties.GetIPv4Properties();
                                    if (v4Properties != null)
                                    {
                                        listenSockets.Add(UdpUtility.CreateListenSocket(address, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize,
                                                                                        this.udpTransportBindingElement.TimeToLive, v4Properties.Index, allowMulticastLoopback, isLoopbackAdapter));
                                    }
                                }
                            }
                        }
                    }

                    if (listenSockets.Count == 0)
                    {
                        throw FxTrace.Exception.AsError(new ArgumentException(SR.UdpFailedToFindMulticastAdapter(this.listenUri)));
                    }
                }
                else
                {
                    //unicast - only sends on the default adapter...
                    this.listenSockets.Add(UdpUtility.CreateUnicastListenSocket(address, ref port,
                                                                                this.udpTransportBindingElement.SocketReceiveBufferSize, this.udpTransportBindingElement.TimeToLive));
                }
            }
            else
            {
                IPAddress v4Address = IPAddress.Any;
                IPAddress v6Address = IPAddress.IPv6Any;

                if (ipV4 && ipV6)
                {
                    if (port == 0)
                    {
                        //port 0 is only allowed when ListenUriMode == ListenUriMode.Unique
                        UdpSocket ipv4Socket, ipv6Socket;
                        port = UdpUtility.CreateListenSocketsOnUniquePort(v4Address, v6Address, this.udpTransportBindingElement.SocketReceiveBufferSize, this.udpTransportBindingElement.TimeToLive, out ipv4Socket, out ipv6Socket);

                        this.listenSockets.Add(ipv4Socket);
                        this.listenSockets.Add(ipv6Socket);
                    }
                    else
                    {
                        this.listenSockets.Add(UdpUtility.CreateUnicastListenSocket(v4Address, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize, this.udpTransportBindingElement.TimeToLive));
                        this.listenSockets.Add(UdpUtility.CreateUnicastListenSocket(v6Address, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize, this.udpTransportBindingElement.TimeToLive));
                    }
                }
                else if (ipV4)
                {
                    this.listenSockets.Add(UdpUtility.CreateUnicastListenSocket(v4Address, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize, this.udpTransportBindingElement.TimeToLive));
                }
                else if (ipV6)
                {
                    this.listenSockets.Add(UdpUtility.CreateUnicastListenSocket(v6Address, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize, this.udpTransportBindingElement.TimeToLive));
                }
            }

            if (updateListenPort && port != this.listenUri.Port)
            {
                UriBuilder uriBuilder = new UriBuilder(this.listenUri);
                uriBuilder.Port = port;
                this.listenUri  = uriBuilder.Uri;
            }

            // Open all the sockets to keep ref counts consistent
            foreach (UdpSocket udpSocket in this.ListenSockets)
            {
                udpSocket.Open();
            }
        }
示例#3
0
        //will only return > 1 socket when both of the following are true:
        // 1) multicast
        // 2) sending on all interfaces
        UdpSocket[] GetSockets(Uri via, out IPEndPoint remoteEndPoint, out bool isMulticast)
        {
            UdpSocket[] results = null;

            remoteEndPoint = null;
            IPAddress[] remoteAddressList;
            isMulticast = false;

            UdpUtility.ThrowIfNoSocketSupport();

            if (via.HostNameType == UriHostNameType.IPv6 || via.HostNameType == UriHostNameType.IPv4)
            {
                UdpUtility.ThrowOnUnsupportedHostNameType(via);

                IPAddress address = IPAddress.Parse(via.DnsSafeHost);
                isMulticast = UdpUtility.IsMulticastAddress(address);

                remoteAddressList = new IPAddress[] { address };
            }
            else
            {
                remoteAddressList = DnsCache.Resolve(via).AddressList;
            }

            if (remoteAddressList.Length < 1)
            {
                // System.Net.Dns shouldn't ever allow this to happen, but...
                Fx.Assert("DnsCache returned a HostEntry with zero length address list");
                throw FxTrace.Exception.AsError(new EndpointNotFoundException(SR.DnsResolveFailed(via.DnsSafeHost)));
            }

            remoteEndPoint = new IPEndPoint(remoteAddressList[0], via.Port);

            IPAddress localAddress;

            if (via.IsLoopback)
            {
                localAddress = (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Loopback : IPAddress.IPv6Loopback);
            }
            else
            {
                localAddress = (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any);
            }

            int port = 0;

            if (isMulticast)
            {
                List <UdpSocket>   socketList = new List <UdpSocket>();
                NetworkInterface[] adapters   = UdpUtility.GetMulticastInterfaces(this.udpTransportBindingElement.MulticastInterfaceId);

                //if listening on a specific adapter, don't disable multicast loopback on that adapter.
                bool allowMulticastLoopback = !string.IsNullOrEmpty(this.udpTransportBindingElement.MulticastInterfaceId);

                for (int i = 0; i < adapters.Length; i++)
                {
                    if (adapters[i].OperationalStatus == OperationalStatus.Up)
                    {
                        IPInterfaceProperties properties = adapters[i].GetIPProperties();
                        bool isLoopbackAdapter           = adapters[i].NetworkInterfaceType == NetworkInterfaceType.Loopback;

                        if (isLoopbackAdapter)
                        {
                            int interfaceIndex;
                            if (UdpUtility.TryGetLoopbackInterfaceIndex(adapters[i], localAddress.AddressFamily == AddressFamily.InterNetwork, out interfaceIndex))
                            {
                                socketList.Add(UdpUtility.CreateListenSocket(localAddress, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize, this.udpTransportBindingElement.TimeToLive,
                                                                             interfaceIndex, allowMulticastLoopback, isLoopbackAdapter));
                            }
                        }
                        else if (localAddress.AddressFamily == AddressFamily.InterNetworkV6)
                        {
                            if (adapters[i].Supports(NetworkInterfaceComponent.IPv6))
                            {
                                IPv6InterfaceProperties v6Properties = properties.GetIPv6Properties();

                                if (v6Properties != null)
                                {
                                    socketList.Add(UdpUtility.CreateListenSocket(localAddress, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize,
                                                                                 this.udpTransportBindingElement.TimeToLive, v6Properties.Index, allowMulticastLoopback, isLoopbackAdapter));
                                }
                            }
                        }
                        else
                        {
                            if (adapters[i].Supports(NetworkInterfaceComponent.IPv4))
                            {
                                IPv4InterfaceProperties v4Properties = properties.GetIPv4Properties();
                                if (v4Properties != null)
                                {
                                    socketList.Add(UdpUtility.CreateListenSocket(localAddress, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize,
                                                                                 this.udpTransportBindingElement.TimeToLive, v4Properties.Index, allowMulticastLoopback, isLoopbackAdapter));
                                }
                            }
                        }
                    }

                    //CreateListenSocket sets the port, but since we aren't listening
                    //on multicast, each socket can't share the same port.
                    port = 0;
                }

                if (socketList.Count == 0)
                {
                    throw FxTrace.Exception.AsError(new ArgumentException(SR.UdpFailedToFindMulticastAdapter(via)));
                }

                results = socketList.ToArray();
            }
            else
            {
                UdpSocket socket = UdpUtility.CreateUnicastListenSocket(localAddress, ref port, this.udpTransportBindingElement.SocketReceiveBufferSize,
                                                                        this.udpTransportBindingElement.TimeToLive);

                results = new UdpSocket[] { socket };
            }


            Fx.Assert(results != null, "GetSockets(...) return results should never be null. An exception should have been thrown but wasn't.");
            return(results);
        }