582 lines
23 KiB
C#
582 lines
23 KiB
C#
|
//----------------------------------------------------------------
|
||
|
// 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.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<MessageEncodingBindingElement>();
|
||
|
MessageEncoderFactory factory = null;
|
||
|
if (messageEncoderBindingElement != null)
|
||
|
{
|
||
|
factory = messageEncoderBindingElement.CreateMessageEncoderFactory();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
factory = UdpConstants.Defaults.MessageEncoderFactory;
|
||
|
}
|
||
|
|
||
|
return factory;
|
||
|
}
|
||
|
|
||
|
//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 static void CheckSocketSupport(out bool ipV4Supported, out bool ipV6Supported)
|
||
|
{
|
||
|
ipV4Supported = Socket.OSSupportsIPv4;
|
||
|
ipV6Supported = Socket.OSSupportsIPv6;
|
||
|
|
||
|
ThrowIfNoSocketSupport(ipV4Supported, ipV6Supported);
|
||
|
}
|
||
|
|
||
|
public static bool TryGetLoopbackInterfaceIndex(NetworkInterface adapter, bool ipv4, out int interfaceIndex)
|
||
|
{
|
||
|
Fx.Assert(adapter != null, "adapter can't be null");
|
||
|
Fx.Assert(adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback, "adapter type must be loopback adapter");
|
||
|
|
||
|
interfaceIndex = -1;
|
||
|
bool result = false;
|
||
|
|
||
|
if (ipv4 && adapter.Supports(NetworkInterfaceComponent.IPv4))
|
||
|
{
|
||
|
interfaceIndex = NetworkInterface.LoopbackInterfaceIndex;
|
||
|
result = true;
|
||
|
}
|
||
|
else if (!ipv4 && adapter.Supports(NetworkInterfaceComponent.IPv6))
|
||
|
{
|
||
|
IPInterfaceProperties properties = adapter.GetIPProperties();
|
||
|
IPv6InterfaceProperties ipv6Properties = properties.GetIPv6Properties();
|
||
|
interfaceIndex = ipv6Properties.Index;
|
||
|
result = true;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
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 ValidateDuplicateDetectionAndRetransmittionSupport(MessageEncoderFactory messageEncoderFactory, bool retransmissionEnabled, bool duplicateDetectionEnabled)
|
||
|
{
|
||
|
Fx.Assert(messageEncoderFactory != null, "messageEncoderFactory shouldn't be null");
|
||
|
|
||
|
MessageVersion encoderMessageVersion = messageEncoderFactory.MessageVersion;
|
||
|
|
||
|
if (encoderMessageVersion.Addressing == AddressingVersion.None)
|
||
|
{
|
||
|
if (retransmissionEnabled)
|
||
|
{
|
||
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TransportRequiresAddressingOnEncoderForRetransmission(encoderMessageVersion, "RetransmissionSettings", typeof(UdpTransportBindingElement).Name)));
|
||
|
}
|
||
|
|
||
|
if (duplicateDetectionEnabled)
|
||
|
{
|
||
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TransportRequiresAddressingOnEncoderForDuplicateDetection(encoderMessageVersion, "DuplicateMessageHistoryLength", typeof(UdpTransportBindingElement).Name)));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void ThrowIfNoSocketSupport()
|
||
|
{
|
||
|
ThrowIfNoSocketSupport(Socket.OSSupportsIPv4, Socket.OSSupportsIPv6);
|
||
|
}
|
||
|
|
||
|
public static void ThrowOnUnsupportedHostNameType(Uri uri)
|
||
|
{
|
||
|
bool ipV4, ipV6;
|
||
|
CheckSocketSupport(out ipV4, out ipV6);
|
||
|
if (!ipV4 && uri.HostNameType == UriHostNameType.IPv4 || !ipV6 && uri.HostNameType == UriHostNameType.IPv6)
|
||
|
{
|
||
|
throw FxTrace.Exception.AsError(new ArgumentException(SR.UriHostNameTypeNotSupportedByOS(uri.Host, uri.HostNameType.ToString())));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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<NetworkInterface> supportedAdapters = new List<NetworkInterface>();
|
||
|
|
||
|
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
|
||
|
int firstAddressByte = (int)address.GetAddressBytes()[0];
|
||
|
return (firstAddressByte >= 224 && firstAddressByte <= 239);
|
||
|
}
|
||
|
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<byte> 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));
|
||
|
|
||
|
NetworkInterfaceMessageProperty networkInterfaceMessageProperty = new NetworkInterfaceMessageProperty(interfaceIndex);
|
||
|
networkInterfaceMessageProperty.AddTo(message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return message;
|
||
|
}
|
||
|
|
||
|
public static int ComputeMessageBufferSize(int maxReceivedMessageSize)
|
||
|
{
|
||
|
return Math.Min(UdpConstants.MaxMessageSizeOverIPv4, maxReceivedMessageSize);
|
||
|
}
|
||
|
}
|
||
|
}
|