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)); }
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); }
//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); }
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); }
//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(); } }
// 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); }
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); }
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(); } } } }
//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); }