Beispiel #1
0
        internal UdpChannelFactory(UdpTransportBindingElement transportBindingElement, BindingContext context)
            : base(context.Binding)
        {
            Fx.Assert(transportBindingElement != null, "transportBindingElement can't be null");
            Fx.Assert(context != null, "binding context can't be null");
            Fx.Assert(typeof(TChannel) == typeof(IOutputChannel) || typeof(TChannel) == typeof(IDuplexChannel), "this channel factory only supports IOutputChannel and IDuplexChannel");

            this.udpTransportBindingElement = transportBindingElement;

            // We should only throw this exception if the user specified realistic MaxReceivedMessageSize less than or equal to max message size over UDP.
            // If the user specified something bigger like Long.MaxValue, we shouldn't stop them.
            if (this.udpTransportBindingElement.MaxReceivedMessageSize <= UdpConstants.MaxMessageSizeOverIPv4 &&
                this.udpTransportBindingElement.SocketReceiveBufferSize < this.udpTransportBindingElement.MaxReceivedMessageSize)
            {
                throw FxTrace.Exception.ArgumentOutOfRange("SocketReceiveBufferSize", this.udpTransportBindingElement.SocketReceiveBufferSize,
                                                           SR.Property1LessThanOrEqualToProperty2("MaxReceivedMessageSize", this.udpTransportBindingElement.MaxReceivedMessageSize,
                                                                                                  "SocketReceiveBufferSize", this.udpTransportBindingElement.SocketReceiveBufferSize));
            }

            this.messageEncoderFactory = UdpUtility.GetEncoder(context);

            bool retransmissionEnabled = this.udpTransportBindingElement.RetransmissionSettings.Enabled;
            //duplicated detection doesn't apply to IOutputChannel, so don't throw if we are only sending
            bool duplicateDetectionEnabled = this.udpTransportBindingElement.DuplicateMessageHistoryLength > 0 ? typeof(TChannel) != typeof(IOutputChannel) : false;

            UdpUtility.ValidateDuplicateDetectionAndRetransmittionSupport(this.messageEncoderFactory, retransmissionEnabled, duplicateDetectionEnabled);

            int maxBufferSize = (int)Math.Min(transportBindingElement.MaxReceivedMessageSize, UdpConstants.MaxMessageSizeOverIPv4);

            this.BufferManager = BufferManager.CreateBufferManager(transportBindingElement.MaxBufferPoolSize, maxBufferSize);
        }
        //must be called under a lock in receive loop
        public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, ref EndPoint remoteEndPoint, AsyncCallback callback, object state)
        {
            UdpUtility.ValidateBufferBounds(buffer, offset, size);

            ThrowIfNotOpen();

            bool         success     = false;
            IAsyncResult asyncResult = null;

            try
            {
                this.pendingReceiveCount++;

                asyncResult = new ReceiveFromAsyncResult(
                    this.socket,
                    new ArraySegment <byte>(buffer, offset, size),
                    remoteEndPoint,
                    size - offset,
                    this.timeToLive,
                    callback,
                    state);
                success = true;

                return(asyncResult);
            }
            finally
            {
                if (!success)
                {
                    this.pendingReceiveCount--;
                }
            }
        }
        public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, EndPoint remoteEndPoint, AsyncCallback callback, object state)
        {
            ThrowIfNotOpen();
            UdpUtility.ValidateBufferBounds(buffer, offset, size);

            return(new SendToAsyncResult(this.socket, buffer, offset, size, remoteEndPoint, this.timeToLive, callback, state));
        }
Beispiel #4
0
        protected override TChannel OnCreateChannel(EndpointAddress to, Uri via)
        {
            Fx.Assert(to != null, "To address should have been validated as non-null by ChannelFactoryBase");
            Fx.Assert(via != null, "Via address should have been validated as non-null by ChannelFactoryBase");

            if (!via.IsAbsoluteUri)
            {
                throw FxTrace.Exception.Argument("via", SR.RelativeUriNotAllowed(via));
            }

            if (!via.Scheme.Equals(UdpConstants.Scheme, StringComparison.OrdinalIgnoreCase))
            {
                throw FxTrace.Exception.Argument("via", SR.UriSchemeNotSupported(via.Scheme));
            }

            if (!UdpUtility.IsSupportedHostNameType(via.HostNameType))
            {
                throw FxTrace.Exception.Argument("via", SR.UnsupportedUriHostNameType(via.Host, via.HostNameType));
            }

            if (via.IsDefaultPort || via.Port == 0)
            {
                throw FxTrace.Exception.ArgumentOutOfRange("via", via, SR.PortNumberRequiredOnVia(via));
            }

            UdpSocket[] sockets        = null;
            IPEndPoint  remoteEndPoint = null;
            TChannel    channel;

            lock (this.ThisLock)
            {
                bool isMulticast;
                sockets = GetSockets(via, out remoteEndPoint, out isMulticast);

                EndpointAddress localAddress = new EndpointAddress(EndpointAddress.AnonymousUri);

                if (typeof(TChannel) == typeof(IDuplexChannel))
                {
                    UdpChannelFactory <IDuplexChannel> duplexChannelFactory = (UdpChannelFactory <IDuplexChannel>)(object) this;
                    channel = (TChannel)(object)new ClientUdpDuplexChannel(duplexChannelFactory, sockets, remoteEndPoint, localAddress, to, via, isMulticast);
                }
                else
                {
                    UdpChannelFactory <IOutputChannel> outputChannelFactory = (UdpChannelFactory <IOutputChannel>)(object) this;
                    channel = (TChannel)(object)new ClientUdpOutputChannel(
                        outputChannelFactory,
                        remoteEndPoint,
                        outputChannelFactory.messageEncoderFactory.Encoder,
                        this.BufferManager,
                        sockets,
                        outputChannelFactory.udpTransportBindingElement.RetransmissionSettings,
                        to,
                        via,
                        isMulticast);
                }
            }

            return(channel);
        }
        void InitUniqueUri(Uri listenUriBaseAddress, string relativeAddress)
        {
            Fx.Assert(listenUriBaseAddress != null, "listenUriBaseAddress parameter should have been verified before now");

            listenUriBaseAddress = UdpUtility.AppendRelativePath(listenUriBaseAddress, relativeAddress);

            this.listenUri = UdpUtility.AppendRelativePath(listenUriBaseAddress, Guid.NewGuid().ToString());
        }
        void InitExplicitUri(Uri listenUriBaseAddress, string relativeAddress)
        {
            if (listenUriBaseAddress.IsDefaultPort || listenUriBaseAddress.Port == 0)
            {
                throw FxTrace.Exception.ArgumentOutOfRange("context.ListenUriBaseAddress", listenUriBaseAddress, SR.ExplicitListenUriModeRequiresPort);
            }

            this.listenUri = UdpUtility.AppendRelativePath(listenUriBaseAddress, relativeAddress);
        }
        void InitUri(BindingContext context)
        {
            Uri listenUriBase = context.ListenUriBaseAddress;

            if (context.ListenUriMode == ListenUriMode.Unique && listenUriBase == null)
            {
                UriBuilder uriBuilder = new UriBuilder(this.Scheme, DnsCache.MachineName);
                uriBuilder.Path = Guid.NewGuid().ToString();
                listenUriBase   = uriBuilder.Uri;
                context.ListenUriBaseAddress = listenUriBase;
            }
            else
            {
                if (listenUriBase == null)
                {
                    throw FxTrace.Exception.ArgumentNull("context.ListenUriBaseAddress");
                }

                if (!listenUriBase.IsAbsoluteUri)
                {
                    throw FxTrace.Exception.Argument("context.ListenUriBaseAddress", SR.RelativeUriNotAllowed(listenUriBase));
                }

                if (context.ListenUriMode == ListenUriMode.Unique && !listenUriBase.IsDefaultPort)
                {
                    throw FxTrace.Exception.Argument("context.ListenUriBaseAddress", SR.DefaultPortRequiredForListenUriModeUnique(listenUriBase));
                }

                if (listenUriBase.Scheme.Equals(this.Scheme, StringComparison.OrdinalIgnoreCase) == false)
                {
                    throw FxTrace.Exception.Argument("context.ListenUriBaseAddress", SR.UriSchemeNotSupported(listenUriBase.Scheme));
                }

                if (!UdpUtility.IsSupportedHostNameType(listenUriBase.HostNameType))
                {
                    throw FxTrace.Exception.Argument("context.ListenUriBaseAddress", SR.UnsupportedUriHostNameType(listenUriBase.Host, listenUriBase.HostNameType));
                }
            }

            switch (context.ListenUriMode)
            {
            case ListenUriMode.Explicit:
                InitExplicitUri(context.ListenUriBaseAddress, context.ListenUriRelativeAddress);
                break;

            case ListenUriMode.Unique:
                InitUniqueUri(context.ListenUriBaseAddress, context.ListenUriRelativeAddress);
                break;

            default:
                Fx.AssertAndThrow("Unhandled ListenUriMode encountered: " + context.ListenUriMode);
                break;
            }
        }
 internal override void HandleReceiveException(Exception ex)
 {
     if (UdpUtility.CanIgnoreServerException(ex))
     {
         FxTrace.Exception.AsWarning(ex);
     }
     else
     {
         //base implementation will wrap the exception and enqueue it.
         base.HandleReceiveException(ex);
     }
 }
        internal UdpChannelListener(UdpTransportBindingElement udpTransportBindingElement, BindingContext context)
            : base(context.Binding)
        {
            Fx.Assert(udpTransportBindingElement != null, "udpTransportBindingElement can't be null");
            Fx.Assert(context != null, "BindingContext parameter can't be null");

            this.udpTransportBindingElement = udpTransportBindingElement;
            this.cleanedUp = 0;

            this.duplicateDetector = null;

            if (udpTransportBindingElement.DuplicateMessageHistoryLength > 0)
            {
                this.duplicateDetector = new DuplicateMessageDetector(udpTransportBindingElement.DuplicateMessageHistoryLength);
            }

            this.onChannelClosed = new EventHandler(OnChannelClosed);

            // We should only throw this exception if the user specified realistic MaxReceivedMessageSize less than or equal to max message size over UDP.
            // If the user specified something bigger like Long.MaxValue, we shouldn't stop them.
            if (this.udpTransportBindingElement.MaxReceivedMessageSize <= UdpConstants.MaxMessageSizeOverIPv4 &&
                this.udpTransportBindingElement.SocketReceiveBufferSize < this.udpTransportBindingElement.MaxReceivedMessageSize)
            {
                throw FxTrace.Exception.ArgumentOutOfRange("SocketReceiveBufferSize", this.udpTransportBindingElement.SocketReceiveBufferSize,
                                                           SR.Property1LessThanOrEqualToProperty2("MaxReceivedMessageSize", this.udpTransportBindingElement.MaxReceivedMessageSize,
                                                                                                  "SocketReceiveBufferSize", this.udpTransportBindingElement.SocketReceiveBufferSize));
            }


            int maxBufferSize = (int)Math.Min(udpTransportBindingElement.MaxReceivedMessageSize, UdpConstants.MaxMessageSizeOverIPv4);

            this.bufferManager = BufferManager.CreateBufferManager(udpTransportBindingElement.MaxBufferPoolSize, maxBufferSize);

            this.messageEncoderFactory = UdpUtility.GetEncoder(context);

            UdpUtility.ValidateDuplicateDetectionAndRetransmittionSupport(this.messageEncoderFactory, this.udpTransportBindingElement.RetransmissionSettings.Enabled, this.udpTransportBindingElement.DuplicateMessageHistoryLength > 0);

            InitUri(context);

            //Note: because we are binding the sockets in InitSockets, we can start receiving data immediately.
            //If there is a delay between the Building of the listener and the call to Open, stale data could build up
            //inside the Winsock buffer.  We have decided that making sure the port is updated correctly in the listen uri
            //(e.g. in the ListenUriMode.Unique case) before leaving the build step is more important than the
            //potential for stale data.
            InitSockets(context.ListenUriMode == ListenUriMode.Unique);

            Fx.Assert(!this.listenUri.IsDefaultPort, "Listen Uri's port should never be the default port: " + this.listenUri);
        }
Beispiel #10
0
        //there are some errors on the server side that we should just ignore because the server will not need
        //to change its behavior if it sees the exception.  These errors are not ignored on the client
        //because it may need to adjust settings (e.g. TTL, send smaller messages, double check server address for correctness)
        internal static bool CanIgnoreServerException(Exception ex)
        {
            SocketError error;

            if (UdpUtility.TryGetSocketError(ex, out error))
            {
                switch (error)
                {
                case SocketError.ConnectionReset: //"ICMP Destination Unreachable" error - client closed the socket
                case SocketError.NetworkReset:    //ICMP: Time Exceeded (TTL expired)
                case SocketError.MessageSize:     //client sent a message larger than the max message size allowed.
                    return(true);
                }
            }
            return(false);
        }
        public int SendTo(byte[] buffer, int offset, int size, EndPoint remoteEndPoint)
        {
            ThrowIfNotOpen();
            UdpUtility.ValidateBufferBounds(buffer, offset, size);

            try
            {
                int count = this.socket.SendTo(buffer, offset, size, SocketFlags.None, remoteEndPoint);
                Fx.Assert(count == size, "Bytes sent on the wire should be the same as the bytes specified");

                return(count);
            }
            catch (SocketException socketException)
            {
                throw FxTrace.Exception.AsError(ConvertNetworkError(socketException, size - offset, TransferDirection.Send, this.timeToLive));
            }
        }
        //Tries to enqueue this async exception onto the channel instance if possible,
        //puts it onto the local exception queue otherwise.
        void HandleReceiveException(Exception ex)
        {
            TChannel channel = this.channelInstance;

            if (channel != null)
            {
                channel.HandleReceiveException(ex);
            }
            else
            {
                if (UdpUtility.CanIgnoreServerException(ex))
                {
                    FxTrace.Exception.AsWarning(ex);
                }
                else
                {
                    this.channelQueue.EnqueueAndDispatch(UdpUtility.WrapAsyncException(ex), null, false);
                }
            }
        }
        internal UdpSocketReceiveManager(UdpSocket[] receiveSockets, int maxPendingReceivesPerSocket, BufferManager bufferManager, IUdpReceiveHandler receiveHandler)
        {
            Fx.Assert(receiveSockets != null, "receiveSockets parameter is null");
            Fx.Assert(receiveSockets.Length > 0, "receiveSockets parameter is empty");
            Fx.Assert(maxPendingReceivesPerSocket > 0, "maxPendingReceivesPerSocket can't be <= 0");
            Fx.Assert(receiveHandler.MaxReceivedMessageSize > 0, "maxReceivedMessageSize must be > 0");
            Fx.Assert(bufferManager != null, "bufferManager argument should not be null");
            Fx.Assert(receiveHandler != null, "receiveHandler should not be null");

            this.receiveHandler = receiveHandler;
            this.thisLock       = new object();
            this.bufferManager  = bufferManager;
            this.receiveSockets = receiveSockets;
            this.maxPendingReceivesPerSocket = maxPendingReceivesPerSocket;
            this.messageBufferSize           = UdpUtility.ComputeMessageBufferSize(receiveHandler.MaxReceivedMessageSize);

            int maxPendingReceives = maxPendingReceivesPerSocket * receiveSockets.Length;

            this.receiveBufferPool = new ConnectionBufferPool(this.messageBufferSize, maxPendingReceives);
        }
Beispiel #14
0
            private void Initialize(Message message)
            {
                Exception exceptionToThrow;

                this.sendSockets = this.channel.GetSendSockets(message, out this.remoteEndpoint, out exceptionToThrow);

                if (exceptionToThrow != null)
                {
                    throw FxTrace.Exception.AsError(exceptionToThrow);
                }

                this.IsMulticast = UdpUtility.IsMulticastAddress(this.remoteEndpoint.Address);

                if (this.channel.ShouldRetransmitMessage(this.IsMulticast))
                {
                    this.retransmissionEnabled = true;
                    this.channel.RetransmitStarting(this.message.Headers.MessageId, this);
                    this.retransmitTimer    = new IOThreadTimer(onRetransmitMessage, this, false);
                    this.retransmitIterator = this.channel.CreateRetransmitIterator(this.IsMulticast);
                }

                this.messageData = this.channel.EncodeMessage(message);
            }
Beispiel #15
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);
        }
        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();
            }
        }
Beispiel #17
0
        // returns false if the message was dropped because the max pending message count was hit.
        bool IUdpReceiveHandler.HandleDataReceived(ArraySegment <byte> data, EndPoint remoteEndpoint, int interfaceIndex, Action onMessageDequeuedCallback)
        {
            bool    returnBuffer      = true;
            string  messageHash       = null;
            Message message           = null;
            bool    continueReceiving = true;

            try
            {
                IPEndPoint remoteIPEndPoint = (IPEndPoint)remoteEndpoint;

                message = UdpUtility.DecodeMessage(
                    this.DuplicateDetector,
                    this.Encoder,
                    this.BufferManager,
                    data,
                    remoteIPEndPoint,
                    interfaceIndex,
                    this.IgnoreSerializationException,
                    out messageHash);

                if (message != null)
                {
                    // We pass in the length of the message buffer instead of the length of the message to keep track of the amount of memory that's been allocated
                    continueReceiving = this.EnqueueMessage(message, data.Array.Length, onMessageDequeuedCallback);
                    returnBuffer      = !continueReceiving;
                }
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    returnBuffer = false;
                    throw;
                }

                this.HandleReceiveException(e);
            }
            finally
            {
                if (returnBuffer)
                {
                    if (message != null)
                    {
                        if (this.DuplicateDetector != null)
                        {
                            Fx.Assert(messageHash != null, "message hash should always be available if duplicate detector is enabled");
                            this.DuplicateDetector.RemoveEntry(messageHash);
                        }

                        message.Close(); // implicitly returns the buffer
                    }
                    else
                    {
                        this.BufferManager.ReturnBuffer(data.Array);
                    }
                }
            }

            return(continueReceiving);
        }
Beispiel #18
0
 internal virtual void HandleReceiveException(Exception ex)
 {
     this.EnqueueAndDispatch(UdpUtility.WrapAsyncException(ex), null, false);
 }
        //returns false if the message was dropped because the max pending message count was hit.
        bool IUdpReceiveHandler.HandleDataReceived(ArraySegment <byte> data, EndPoint remoteEndpoint, int interfaceIndex, Action onMessageDequeuedCallback)
        {
            BufferManager localBufferManager = this.bufferManager;
            bool          returnBuffer       = true;
            string        messageHash        = null;
            Message       message            = null;
            bool          continueReceiving  = true;

            try
            {
                IPEndPoint remoteIPEndPoint = (IPEndPoint)remoteEndpoint;
                if (localBufferManager != null)
                {
                    message = UdpUtility.DecodeMessage(this.duplicateDetector, this.messageEncoderFactory.Encoder,
                                                       localBufferManager, data, remoteIPEndPoint, interfaceIndex, true, out messageHash);

                    if (message != null)
                    {
                        // We pass in the length of the message buffer instead of the length of the message to keep track of the amount of memory that's been allocated
                        continueReceiving = Dispatch(message, data.Array.Length, onMessageDequeuedCallback);
                        returnBuffer      = !continueReceiving;
                    }
                }
                else
                {
                    Fx.Assert(this.State != CommunicationState.Opened, "buffer manager should only be null when closing down and the channel instance has taken control of the receive manager.");

                    IUdpReceiveHandler receiveHandler = (IUdpReceiveHandler)this.channelInstance;

                    if (receiveHandler != null)
                    {
                        returnBuffer      = false; //let the channel instance take care of the buffer
                        continueReceiving = receiveHandler.HandleDataReceived(data, remoteEndpoint, interfaceIndex, onMessageDequeuedCallback);
                    }
                    else
                    {
                        //both channel and listener are shutting down, so drop the message and stop the receive loop
                        continueReceiving = false;
                    }
                }
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    returnBuffer = false;
                    throw;
                }

                HandleReceiveException(e);
            }
            finally
            {
                if (returnBuffer)
                {
                    if (message != null)
                    {
                        if (this.duplicateDetector != null)
                        {
                            Fx.Assert(messageHash != null, "message hash should always be available if duplicate detector is enabled");
                            this.duplicateDetector.RemoveEntry(messageHash);
                        }

                        message.Close(); // implicitly returns the buffer
                    }
                    else
                    {
                        // CSDMain 238600. Both channel and listener are shutting down. There's a race condition happening here
                        // and the bufferManager is not available at this moment. The data buffer ignored here might introduce
                        // an issue with buffer manager, but given that we are in the shutting down case here, it should not be a
                        // big problem.
                        if (localBufferManager != null)
                        {
                            localBufferManager.ReturnBuffer(data.Array);
                        }
                    }
                }
            }

            return(continueReceiving);
        }
Beispiel #20
0
        protected override void OnSend(Message message, TimeSpan timeout)
        {
            if (message is NullMessage)
            {
                return;
            }

            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);

            IPEndPoint remoteEndPoint;

            UdpSocket[] sendSockets;
            Exception   exceptionToBeThrown;

            sendSockets = this.GetSendSockets(message, out remoteEndPoint, out exceptionToBeThrown);

            if (exceptionToBeThrown != null)
            {
                throw FxTrace.Exception.AsError(exceptionToBeThrown);
            }

            if (timeoutHelper.RemainingTime() <= TimeSpan.Zero)
            {
                throw FxTrace.Exception.AsError(new TimeoutException(SR.SendTimedOut(remoteEndPoint, timeout)));
            }

            bool returnBuffer = false;
            ArraySegment <byte> messageData = default(ArraySegment <byte>);

            bool sendingMulticast = UdpUtility.IsMulticastAddress(remoteEndPoint.Address);
            SynchronousRetransmissionHelper retransmitHelper = null;
            RetransmitIterator retransmitIterator            = null;

            bool shouldRetransmit = this.ShouldRetransmitMessage(sendingMulticast);

            try
            {
                if (shouldRetransmit)
                {
                    retransmitIterator = this.CreateRetransmitIterator(sendingMulticast);
                    retransmitHelper   = new SynchronousRetransmissionHelper(sendingMulticast);
                    this.RetransmitStarting(message.Headers.MessageId, retransmitHelper);
                }

                messageData  = this.EncodeMessage(message);
                returnBuffer = true;

                this.TransmitMessage(messageData, sendSockets, remoteEndPoint, timeoutHelper);

                if (shouldRetransmit)
                {
                    while (retransmitIterator.MoveNext())
                    {
                        // wait for currentDelay time, then retransmit
                        if (retransmitIterator.CurrentDelay > 0)
                        {
                            retransmitHelper.Wait(retransmitIterator.CurrentDelay);
                        }

                        if (retransmitHelper.IsCanceled)
                        {
                            ThrowIfAborted();
                            return;
                        }

                        // since we only invoke the encoder once just before the initial send of the message
                        // we need to handle logging the message in the retransmission case
                        if (MessageLogger.LogMessagesAtTransportLevel)
                        {
                            UdpOutputChannel.LogMessage(ref message, messageData);
                        }

                        this.TransmitMessage(messageData, sendSockets, remoteEndPoint, timeoutHelper);
                    }
                }
            }
            finally
            {
                if (returnBuffer)
                {
                    this.BufferManager.ReturnBuffer(messageData.Array);
                }

                if (shouldRetransmit)
                {
                    this.RetransmitStopping(message.Headers.MessageId);

                    if (retransmitHelper != null)
                    {
                        retransmitHelper.Dispose();
                    }
                }
            }
        }
Beispiel #21
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);
        }