UdpUtility.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.ServiceModel.Discovery / System / ServiceModel / Channels / UdpUtility.cs / 1484997 / UdpUtility.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------

namespace System.ServiceModel.Channels 
{
    using System; 
    using System.Collections.Generic; 
    using System.Net;
    using System.Net.NetworkInformation; 
    using System.Net.Sockets;
    using System.Runtime;
    using System.ServiceModel.Discovery;
    using System.Xml; 

    static class UdpUtility 
    { 
        public static Uri AppendRelativePath(Uri basepath, string relativePath)
        { 
            // Ensure that baseAddress Path does end with a slash if we have a relative address
            if (!string.IsNullOrEmpty(relativePath))
            {
                if (!basepath.AbsolutePath.EndsWith("/", StringComparison.Ordinal)) 
                {
                    UriBuilder uriBuilder = new UriBuilder(basepath); 
                    uriBuilder.Path = uriBuilder.Path + "/"; 
                    basepath = uriBuilder.Uri;
                } 

                basepath = new Uri(basepath, relativePath);
            }
 
            return basepath;
        } 
 
        public static MessageEncoderFactory GetEncoder(BindingContext context)
        { 
            MessageEncodingBindingElement messageEncoderBindingElement = context.BindingParameters.Remove();
            MessageEncoderFactory factory = null;
            if (messageEncoderBindingElement != null)
            { 
                factory = messageEncoderBindingElement.CreateMessageEncoderFactory();
            } 
            else 
            {
                factory = UdpConstants.Defaults.MessageEncoderFactory; 
            }

            if (factory.MessageVersion.Addressing == AddressingVersion.None)
            { 
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TransportRequiresAddressingOnEncoder(factory.MessageVersion.Addressing.ToString())));
            } 
 
            return factory;
        } 

        public static void CheckSocketSupport(out bool ipV4Supported, out bool ipV6Supported)
        {
            ipV4Supported = Socket.OSSupportsIPv4; 
            ipV6Supported = Socket.OSSupportsIPv6;
 
            ThrowIfNoSocketSupport(ipV4Supported, ipV6Supported); 
        }
 
        public static int GetLoopbackInterfaceIndex(NetworkInterface adapter, bool ipv4)
        {
            Fx.Assert(adapter != null, "adapter can't be null");
            Fx.Assert(adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback, "adapter type must be loopback adapter"); 

            if (ipv4) 
            { 
                return NetworkInterface.LoopbackInterfaceIndex;
            } 
            else
            {
                IPInterfaceProperties properties = adapter.GetIPProperties();
                IPv6InterfaceProperties ipv6Properties = properties.GetIPv6Properties(); 
                return ipv6Properties.Index;
            } 
        } 

        public static UdpSocket CreateUnicastListenSocket(IPAddress ipAddress, ref int port, int receiveBufferSize, int timeToLive) 
        {
            return CreateListenSocket(ipAddress, ref port, receiveBufferSize, timeToLive, UdpConstants.Defaults.InterfaceIndex, false, false);
        }
 
        public static UdpSocket CreateListenSocket(IPAddress ipAddress, ref int port, int receiveBufferSize, int timeToLive,
            int interfaceIndex, bool allowMulticastLoopback, bool isLoopbackAdapter) 
        { 
            bool isIPv6 = (ipAddress.AddressFamily == AddressFamily.InterNetworkV6);
            Socket socket = null; 

            bool listenMulticast = IsMulticastAddress(ipAddress);

            IPEndPoint localEndpoint; 

            if (listenMulticast) 
            { 
                IPAddress bindAddress = (isIPv6 ? IPAddress.IPv6Any : IPAddress.Any);
                localEndpoint = new IPEndPoint(bindAddress, port); 
            }
            else
            {
                localEndpoint = new IPEndPoint(ipAddress, port); 
            }
 
            socket = new Socket(localEndpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); 

            SetPreBindSocketOptions(socket, listenMulticast, receiveBufferSize, (short)timeToLive, interfaceIndex, allowMulticastLoopback, isLoopbackAdapter); 

            BindSocket(socket, localEndpoint);

            SetPostBindSocketOptions(socket, listenMulticast, ipAddress, interfaceIndex); 

            if (port == 0) 
            { 
                //update the port to be the actual one the socket is bound to...
                port = ((IPEndPoint)socket.LocalEndPoint).Port; 
            }


            return new UdpSocket(socket, interfaceIndex); 
        }
 
        //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;
        }
 
        public static void ThrowIfNoSocketSupport()
        { 
            ThrowIfNoSocketSupport(Socket.OSSupportsIPv4, Socket.OSSupportsIPv6); 
        }
 
        static void ThrowIfNoSocketSupport(bool ipv4Supported, bool ipv6Supported)
        {
            if (!ipv4Supported && !ipv6Supported)
            { 
                throw FxTrace.Exception.AsError(new NotSupportedException(SR.IPv4OrIPv6Required));
            } 
        } 

        public static NetworkInterface[] GetMulticastInterfaces(string multicastInterfaceIdentifier) 
        {
            NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();

            Fx.Assert(adapters != null, "NetworkInterface.GetAllNetworkInterfaces() should never return null"); 

            NetworkInterface[] results = null; 
 
            if (string.IsNullOrEmpty(multicastInterfaceIdentifier)) //find all supported NICs
            { 
                List supportedAdapters = new List ();

                for (int i = 0; i < adapters.Length; i++)
                { 
                    NetworkInterface adapter = adapters[i];
 
                    if (IsSuitableForMulticast(adapter)) 
                    {
                        supportedAdapters.Add(adapter); 
                    }
                }

                //OK to return an empty array in this case, the calling code will throw an exception 
                //with better context information that what we have here...
                results = supportedAdapters.ToArray(); 
            } 
            else  //Only looking for one interface...
            { 
                for (int i = 0; i < adapters.Length; i++)
                {
                    NetworkInterface adapter = adapters[i];
 
                    if (string.Equals(adapter.Id, multicastInterfaceIdentifier, StringComparison.OrdinalIgnoreCase))
                    { 
                        if (IsSuitableForMulticast(adapter)) 
                        {
                            OperationalStatus status = adapter.OperationalStatus; 
                            if (status != OperationalStatus.Up)
                            {
                                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.UdpAdapterSpecifiedNotConnected(multicastInterfaceIdentifier, status)));
                            } 

                            results = new NetworkInterface[] { adapter }; 
                            break; 
                        }
                        else 
                        {
                            throw FxTrace.Exception.AsError(new InvalidOperationException(SR.UdpAdapterSpecifiedNotSuitableForMulticast(multicastInterfaceIdentifier)));
                        }
                    } 
                }
 
                if (results == null || results.Length == 0) 
                {
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.UdpInterfaceIndexMatchNotFound(multicastInterfaceIdentifier))); 
                }
            }

            Fx.Assert(results != null, "A null list of network adapters should never be returned.  It should either be an empty list or an exception should have been thrown."); 
            return results;
        } 
 
        public static bool IsMulticastAddress(IPAddress address)
        { 
            if (address.AddressFamily == AddressFamily.InterNetwork)
            {
                // 224.0.0.0 through 239.255.255.255
                byte[] addressBytes = address.GetAddressBytes(); 
                return ((addressBytes[0] & 0xE0) == 0xE0);
            } 
            else 
            {
                return address.IsIPv6Multicast; 
            }
        }

        public static bool IsSuitableForMulticast(NetworkInterface networkInterface) 
        {
            bool result = false; 
 
            if (networkInterface.SupportsMulticast &&
                !networkInterface.IsReceiveOnly && 
                networkInterface.NetworkInterfaceType != NetworkInterfaceType.Tunnel &&
                networkInterface.NetworkInterfaceType != NetworkInterfaceType.Unknown)
            {
                result = true; 
            }
 
            return result; 
        }
 
        public static bool IsSupportedHostNameType(UriHostNameType hostNameType)
        {
            return hostNameType == UriHostNameType.Dns ||
                hostNameType == UriHostNameType.IPv4 || 
                hostNameType == UriHostNameType.IPv6;
        } 
 
        public static void ValidateBufferBounds(byte[] buffer, int offset, int size)
        { 
            if (buffer == null)
            {
                throw FxTrace.Exception.ArgumentNull("buffer");
            } 

            ValidateBufferBounds(buffer.Length, offset, size); 
        } 

        public static void ValidateBufferBounds(int bufferSize, int offset, int size) 
        {
            if (offset < 0)
            {
                throw FxTrace.Exception.ArgumentOutOfRange("offset", offset, SR.ValueMustBeNonNegative(offset)); 
            }
 
            if (offset > bufferSize) 
            {
                throw FxTrace.Exception.ArgumentOutOfRange("offset", offset, SR.OffsetExceedsBufferSize(bufferSize)); 
            }

            if (size <= 0)
            { 
                throw FxTrace.Exception.ArgumentOutOfRange("size", size, SR.ValueMustBePositive);
            } 
 
            int remainingBufferSpace = bufferSize - offset;
            if (size > remainingBufferSpace) 
            {
                throw FxTrace.Exception.ArgumentOutOfRange("size", size, SR.SizeExceedsRemainingBufferSpace(remainingBufferSpace));
            }
        } 

        public static Exception WrapAsyncException(Exception ex) 
        { 
            if (ex is TimeoutException)
            { 
                return new TimeoutException(SR.AsynchronousExceptionOccurred, ex);
            }
            else if (ex is AddressAlreadyInUseException)
            { 
                return new AddressAlreadyInUseException(SR.AsynchronousExceptionOccurred, ex);
            } 
            else if (ex is AddressAccessDeniedException) 
            {
                return new AddressAccessDeniedException(SR.AsynchronousExceptionOccurred, ex); 
            }
            else if (ex is EndpointNotFoundException)
            {
                return new EndpointNotFoundException(SR.AsynchronousExceptionOccurred, ex); 
            }
            else if (ex is XmlException) 
            { 
                return new XmlException(SR.AsynchronousExceptionOccurred, ex);
            } 
            else if (ex is CommunicationException)
            {
                return new CommunicationException(SR.AsynchronousExceptionOccurred, ex);
            } 
            else
            { 
                return ex; 
            }
        } 

        static void BindSocket(Socket socket, IPEndPoint localEndpoint)
        {
            try 
            {
                socket.Bind(localEndpoint); 
            } 
            catch (SocketException ex)
            { 
                if (ex.SocketErrorCode == SocketError.AddressAlreadyInUse)
                {
                    throw FxTrace.Exception.AsError(new AddressAlreadyInUseException(SR.SocketAddressInUse(localEndpoint.ToString()), ex));
                } 
                else if (ex.SocketErrorCode == SocketError.AccessDenied)
                { 
                    throw FxTrace.Exception.AsError(new AddressAccessDeniedException(SR.SocketAddressAccessDenied(localEndpoint.ToString()), ex)); 
                }
                else 
                {
                    throw;
                }
            } 
        }
 
        static void SetPreBindSocketOptions(Socket socket, bool listenMulticast, int receiveBufferSize, short timeToLive, int interfaceIndex, 
            bool allowMulticastLoopback, bool isLoopbackAdapter)
        { 
            bool isIPv4 = socket.AddressFamily == AddressFamily.InterNetwork;
            SocketOptionLevel ipOptionLevel = (isIPv4 ? ipOptionLevel = SocketOptionLevel.IP: ipOptionLevel = SocketOptionLevel.IPv6);

            //sets only the unicast TTL 
            socket.Ttl = timeToLive;
 
            //set send related multicast options even if not listening multicast, 
            //we might be sending multicast (e.g. client side or due to manual addressing on server).
            socket.SetSocketOption(ipOptionLevel, SocketOptionName.MulticastTimeToLive, timeToLive); 

            if (interfaceIndex != UdpConstants.Defaults.InterfaceIndex)
            {
                int index = (isIPv4 ? IPAddress.HostToNetworkOrder(interfaceIndex) : interfaceIndex); 

                //sets the outbound interface index 
                socket.SetSocketOption(ipOptionLevel, SocketOptionName.MulticastInterface, index); 
            }
 
            if (listenMulticast)
            {
                //don't set this socket option if the socket is bound to the
                //loopback adapter because it will throw an argument exception. 
                if (!isLoopbackAdapter)
                { 
                    socket.SetSocketOption(ipOptionLevel, SocketOptionName.MulticastLoopback, allowMulticastLoopback); 
                }
 
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
            }
            else
            { 
                socket.ExclusiveAddressUse = true;
            } 
 
            if (receiveBufferSize >= 0)
            { 
                socket.ReceiveBufferSize = receiveBufferSize;
            }
        }
 
        static void SetPostBindSocketOptions(Socket socket, bool listenMulticast, IPAddress ipAddress, int interfaceIndex)
        { 
            bool isIPv6 = socket.AddressFamily == AddressFamily.InterNetworkV6; 

            if (listenMulticast) 
            {
                //Win2k3 requires that the joining of the multicast group be after the socket is bound (not true on Vista).
                if (isIPv6)
                { 
                    IPv6MulticastOption multicastGroup = (interfaceIndex == UdpConstants.Defaults.InterfaceIndex ?
                        new IPv6MulticastOption(ipAddress) 
                        : new IPv6MulticastOption(ipAddress, interfaceIndex)); 

                    socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, 
                        multicastGroup);
                }
                else
                { 
                    MulticastOption multicastGroup = (interfaceIndex == UdpConstants.Defaults.InterfaceIndex ?
                        new MulticastOption(ipAddress) 
                        : new MulticastOption(ipAddress, interfaceIndex)); 

                    socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, 
                        multicastGroup);
                }
            }
        } 

        public static bool TryGetSocketError(Exception ex, out SocketError error) 
        { 
            error = SocketError.SocketError;
 
            while (ex != null)
            {
                SocketException socketException = ex as SocketException;
                if (socketException != null) 
                {
                    error = socketException.SocketErrorCode; 
                    return true; 
                }
 
                ex = ex.InnerException;
            }

            return false; 
        }
 
        public static Message DecodeMessage(DuplicateMessageDetector duplicateDetector, MessageEncoder encoder, BufferManager bufferManager, ArraySegment data, IPEndPoint remoteEndPoint, int interfaceIndex, bool ignoreSerializationException, out string messageHash) 
        {
            Fx.Assert(data != null, "data can't be null"); 
            Fx.Assert(remoteEndPoint != null, "remoteEndPoint can't be null");
            Fx.Assert(encoder != null, "encoder can't be null");
            Fx.Assert(bufferManager != null, "bufferManager can't be null");
 
            Message message = null;
 
            messageHash = null; 

            if (duplicateDetector == null  || !duplicateDetector.IsDuplicate(data, out messageHash)) 
            {
                try
                {
                    message = encoder.ReadMessage(data, bufferManager); 
                }
                catch (XmlException error) 
                { 
                    // Don't throw serialization exceptions when the channel supports Multicast
                    if (!ignoreSerializationException) 
                    {
                        throw;
                    }
 
                    FxTrace.Exception.AsWarning(error);
                } 
 
                if (message != null)
                { 
                    message.Properties.Add(RemoteEndpointMessageProperty.Name,
                        new RemoteEndpointMessageProperty(remoteEndPoint.Address.ToString(), remoteEndPoint.Port));

                    UdpMessageProperty udpMessageProperty = new UdpMessageProperty(interfaceIndex); 
                    udpMessageProperty.AddTo(message);
                } 
            } 

            return message; 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK