예제 #1
0
        // Must return non-null/non-empty array unless exceptionToBeThrown is has been set
        protected override UdpSocket[] GetSendSockets(Message message, out IPEndPoint remoteEndPoint, out Exception exceptionToBeThrown)
        {
            Fx.Assert(message != null, "message can't be null");

            UdpSocket[] socketList = null;
            exceptionToBeThrown = null;

            remoteEndPoint = null;
            Uri  destination;
            bool isVia = false;

            if (message.Properties.Via != null)
            {
                destination = message.Properties.Via;
                isVia       = true;
            }
            else if (message.Headers.To != null)
            {
                destination = message.Headers.To;
            }
            else
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ToOrViaRequired));
            }

            this.ValidateDestinationUri(destination, isVia);

            if (destination.HostNameType == UriHostNameType.IPv4 || destination.HostNameType == UriHostNameType.IPv6)
            {
                remoteEndPoint = new IPEndPoint(IPAddress.Parse(destination.DnsSafeHost), destination.Port);

                if (this.IsMulticast)
                {
                    UdpSocket socket = this.GetSendSocketUsingInterfaceIndex(message.Properties, out exceptionToBeThrown);

                    if (socket != null)
                    {
                        if (socket.AddressFamily == remoteEndPoint.AddressFamily)
                        {
                            socketList = new UdpSocket[] { socket };
                        }
                        else
                        {
                            exceptionToBeThrown = new InvalidOperationException(SR.RemoteAddressUnreachableDueToIPVersionMismatch(destination.DnsSafeHost));
                        }
                    }
                }
                else
                {
                    UdpSocket socket = this.GetSendSocket(remoteEndPoint.Address, destination, out exceptionToBeThrown);
                    if (socket != null)
                    {
                        socketList = new UdpSocket[] { socket };
                    }
                }
            }
            else
            {
                IPAddress[] remoteAddresses = DnsCache.Resolve(destination).AddressList;

                if (this.IsMulticast)
                {
                    UdpSocket socket = this.GetSendSocketUsingInterfaceIndex(message.Properties, out exceptionToBeThrown);

                    if (socket != null)
                    {
                        socketList = new UdpSocket[] { socket };

                        for (int i = 0; i < remoteAddresses.Length; i++)
                        {
                            if (remoteAddresses[i].AddressFamily == socket.AddressFamily)
                            {
                                remoteEndPoint = new IPEndPoint(remoteAddresses[i], destination.Port);
                                break;
                            }
                        }

                        if (remoteEndPoint == null)
                        {
                            // for multicast, we only listen on either IPv4 or IPv6 (not both).
                            // if we didn't find a matching remote endpoint, then it would indicate that
                            // the remote host didn't resolve to an address we can use...
                            exceptionToBeThrown = new InvalidOperationException(SR.RemoteAddressUnreachableDueToIPVersionMismatch(destination.DnsSafeHost));
                        }
                    }
                }
                else
                {
                    bool useIPv4 = true;
                    bool useIPv6 = true;

                    for (int i = 0; i < remoteAddresses.Length; i++)
                    {
                        IPAddress address = remoteAddresses[i];

                        if (address.AddressFamily == AddressFamily.InterNetwork && useIPv4)
                        {
                            UdpSocket socket = this.GetSendSocket(address, destination, out exceptionToBeThrown);
                            if (socket == null)
                            {
                                if (this.State != CommunicationState.Opened)
                                {
                                    // time to exit, the channel is closing down.
                                    break;
                                }
                                else
                                {
                                    // no matching socket on IPv4, so ignore future IPv4 addresses
                                    // in the remoteAddresses list
                                    useIPv4 = false;
                                }
                            }
                            else
                            {
                                remoteEndPoint = new IPEndPoint(address, destination.Port);
                                socketList     = new UdpSocket[] { socket };
                                break;
                            }
                        }
                        else if (address.AddressFamily == AddressFamily.InterNetworkV6 && useIPv6)
                        {
                            UdpSocket socket = this.GetSendSocket(address, destination, out exceptionToBeThrown);
                            if (socket == null)
                            {
                                if (this.State != CommunicationState.Opened)
                                {
                                    // time to exit, the channel is closing down.
                                    break;
                                }
                                else
                                {
                                    // no matching socket on IPv6, so ignore future IPv6 addresses
                                    // in the remoteAddresses list
                                    useIPv6 = false;
                                }
                            }
                            else
                            {
                                remoteEndPoint = new IPEndPoint(address, destination.Port);
                                socketList     = new UdpSocket[] { socket };
                                break;
                            }
                        }
                    }
                }
            }

            return(socketList);
        }