Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@ -0,0 +1,105 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System;
using System.IO;
using System.Runtime;
class ByteStreamBufferedMessageData
{
ArraySegment<byte> buffer;
BufferManager bufferManager;
int refCount;
public ByteStreamBufferedMessageData(ArraySegment<byte> buffer)
: this(buffer, null)
{
}
public ByteStreamBufferedMessageData(ArraySegment<byte> buffer, BufferManager bufferManager)
{
if (buffer.Array == null)
{
throw FxTrace.Exception.ArgumentNull(SR.ArgumentPropertyShouldNotBeNullError("buffer.Array"));
}
this.buffer = buffer;
this.bufferManager = bufferManager;
this.refCount = 0;
}
bool IsClosed
{
get
{
return this.refCount < 0;
}
}
public ArraySegment<byte> Buffer
{
get
{
ThrowIfClosed();
return this.buffer;
}
}
public void Open()
{
ThrowIfClosed();
this.refCount++;
}
public void Close()
{
if (!this.IsClosed)
{
if (--this.refCount <= 0)
{
if (this.bufferManager != null && this.buffer.Array != null)
{
this.bufferManager.ReturnBuffer(this.buffer.Array);
}
this.bufferManager = null;
this.buffer = default(ArraySegment<byte>);
this.refCount = int.MinValue;
}
}
}
public Stream ToStream()
{
return new ByteStreamBufferedMessageDataStream(this);
}
void ThrowIfClosed()
{
if (this.IsClosed)
{
throw FxTrace.Exception.ObjectDisposed(SR.ObjectDisposed(this));
}
}
class ByteStreamBufferedMessageDataStream : MemoryStream
{
ByteStreamBufferedMessageData byteStreamBufferedMessageData;
public ByteStreamBufferedMessageDataStream(ByteStreamBufferedMessageData byteStreamBufferedMessageData)
: base(byteStreamBufferedMessageData.Buffer.Array, byteStreamBufferedMessageData.Buffer.Offset, byteStreamBufferedMessageData.Buffer.Count, false)
{
this.byteStreamBufferedMessageData = byteStreamBufferedMessageData;
this.byteStreamBufferedMessageData.Open(); //increment the refCount
}
public override void Close()
{
this.byteStreamBufferedMessageData.Close();
base.Close();
}
}
}
}

View File

@ -0,0 +1,389 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System;
using System.Runtime;
using System.ServiceModel.Diagnostics;
using System.Xml;
using System.IO;
using System.Runtime.Diagnostics;
using SMTD = System.ServiceModel.Diagnostics.Application.TD;
using System.Diagnostics;
class ByteStreamMessageEncoder : MessageEncoder, IStreamedMessageEncoder, IWebMessageEncoderHelper, ITraceSourceStringProvider
{
string traceSourceString;
string maxReceivedMessageSizeExceededResourceString;
string maxSentMessageSizeExceededResourceString;
XmlDictionaryReaderQuotas quotas;
XmlDictionaryReaderQuotas bufferedReadReaderQuotas;
/// <summary>
/// Specifies if this encoder produces Messages that provide a body reader (with the Message.GetReaderAtBodyContents() method) positioned on content.
/// See the comments on 'IWebMessageEncoderHelper' for more info.
/// </summary>
bool moveBodyReaderToContent = false; // false because we want the ByteStreamMessageEncoder to be compatible with previous releases
public ByteStreamMessageEncoder(XmlDictionaryReaderQuotas quotas)
{
this.quotas = new XmlDictionaryReaderQuotas();
quotas.CopyTo(this.quotas);
this.bufferedReadReaderQuotas = EncoderHelpers.GetBufferedReadQuotas(this.quotas);
this.maxSentMessageSizeExceededResourceString = SR.MaxSentMessageSizeExceeded("{0}");
this.maxReceivedMessageSizeExceededResourceString = SR.MaxReceivedMessageSizeExceeded("{0}");
}
void IWebMessageEncoderHelper.EnableBodyReaderMoveToContent()
{
this.moveBodyReaderToContent = true;
}
public override string ContentType
{
get { return null; }
}
public override string MediaType
{
get { return null; }
}
public override MessageVersion MessageVersion
{
get { return MessageVersion.None; }
}
public override bool IsContentTypeSupported(string contentType)
{
return true;
}
public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
{
if (stream == null)
{
throw FxTrace.Exception.ArgumentNull("stream");
}
if (TD.ByteStreamMessageDecodingStartIsEnabled())
{
TD.ByteStreamMessageDecodingStart();
}
Message message = ByteStreamMessage.CreateMessage(stream, this.quotas, this.moveBodyReaderToContent);
message.Properties.Encoder = this;
if (SMTD.StreamedMessageReadByEncoderIsEnabled())
{
SMTD.StreamedMessageReadByEncoder(EventTraceActivityHelper.TryExtractActivity(message, true));
}
if (MessageLogger.LogMessagesAtTransportLevel)
{
MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
}
return message;
}
public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
{
if (buffer.Array == null)
{
throw FxTrace.Exception.ArgumentNull("buffer.Array");
}
if (bufferManager == null)
{
throw FxTrace.Exception.ArgumentNull("bufferManager");
}
if (TD.ByteStreamMessageDecodingStartIsEnabled())
{
TD.ByteStreamMessageDecodingStart();
}
ByteStreamBufferedMessageData messageData = new ByteStreamBufferedMessageData(buffer, bufferManager);
Message message = ByteStreamMessage.CreateMessage(messageData, this.bufferedReadReaderQuotas, this.moveBodyReaderToContent);
message.Properties.Encoder = this;
if (SMTD.MessageReadByEncoderIsEnabled())
{
SMTD.MessageReadByEncoder(
EventTraceActivityHelper.TryExtractActivity(message, true),
buffer.Count,
this);
}
if (MessageLogger.LogMessagesAtTransportLevel)
{
MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
}
return message;
}
public override void WriteMessage(Message message, Stream stream)
{
if (message == null)
{
throw FxTrace.Exception.ArgumentNull("message");
}
if (stream == null)
{
throw FxTrace.Exception.ArgumentNull("stream");
}
ThrowIfMismatchedMessageVersion(message);
EventTraceActivity eventTraceActivity = null;
if (TD.ByteStreamMessageEncodingStartIsEnabled())
{
eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
TD.ByteStreamMessageEncodingStart(eventTraceActivity);
}
message.Properties.Encoder = this;
if (MessageLogger.LogMessagesAtTransportLevel)
{
MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportSend);
}
using (XmlWriter writer = new XmlByteStreamWriter(stream, false))
{
message.WriteMessage(writer);
writer.Flush();
}
if (SMTD.StreamedMessageWrittenByEncoderIsEnabled())
{
SMTD.StreamedMessageWrittenByEncoder(eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message));
}
}
public override IAsyncResult BeginWriteMessage(Message message, Stream stream, AsyncCallback callback, object state)
{
if (message == null)
{
throw FxTrace.Exception.ArgumentNull("message");
}
if (stream == null)
{
throw FxTrace.Exception.ArgumentNull("stream");
}
ThrowIfMismatchedMessageVersion(message);
message.Properties.Encoder = this;
if (MessageLogger.LogMessagesAtTransportLevel)
{
MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportSend);
}
return new WriteMessageAsyncResult(message, stream, callback, state);
}
public override void EndWriteMessage(IAsyncResult result)
{
WriteMessageAsyncResult.End(result);
}
public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
{
if (message == null)
{
throw FxTrace.Exception.ArgumentNull("message");
}
if (bufferManager == null)
{
throw FxTrace.Exception.ArgumentNull("bufferManager");
}
if (maxMessageSize < 0)
{
throw FxTrace.Exception.ArgumentOutOfRange("maxMessageSize", maxMessageSize, SR.ArgumentOutOfMinRange(0));
}
if (messageOffset < 0)
{
throw FxTrace.Exception.ArgumentOutOfRange("messageOffset", messageOffset, SR.ArgumentOutOfMinRange(0));
}
EventTraceActivity eventTraceActivity = null;
if (TD.ByteStreamMessageEncodingStartIsEnabled())
{
eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
TD.ByteStreamMessageEncodingStart(eventTraceActivity);
}
ThrowIfMismatchedMessageVersion(message);
message.Properties.Encoder = this;
ArraySegment<byte> messageBuffer;
int size;
using (BufferManagerOutputStream stream = new BufferManagerOutputStream(maxSentMessageSizeExceededResourceString, 0, maxMessageSize, bufferManager))
{
stream.Skip(messageOffset);
using (XmlWriter writer = new XmlByteStreamWriter(stream, true))
{
message.WriteMessage(writer);
writer.Flush();
byte[] bytes = stream.ToArray(out size);
messageBuffer = new ArraySegment<byte>(bytes, messageOffset, size - messageOffset);
}
}
if (SMTD.MessageWrittenByEncoderIsEnabled())
{
SMTD.MessageWrittenByEncoder(
eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message),
messageBuffer.Count,
this);
}
if (MessageLogger.LogMessagesAtTransportLevel)
{
// DevDiv#486728
// Don't pass in a buffer manager to avoid returning 'messageBuffer" to the bufferManager twice.
ByteStreamBufferedMessageData messageData = new ByteStreamBufferedMessageData(messageBuffer, null);
using (XmlReader reader = new XmlBufferedByteStreamReader(messageData, this.quotas))
{
MessageLogger.LogMessage(ref message, reader, MessageLoggingSource.TransportSend);
}
}
return messageBuffer;
}
public override string ToString()
{
return ByteStreamMessageUtility.EncoderName;
}
public Stream GetResponseMessageStream(Message message)
{
if (message == null)
{
throw FxTrace.Exception.ArgumentNull("message");
}
ThrowIfMismatchedMessageVersion(message);
if (!ByteStreamMessage.IsInternalByteStreamMessage(message))
{
return null;
}
return message.GetBody<Stream>();
}
string ITraceSourceStringProvider.GetSourceString()
{
// Other MessageEncoders use base.GetTraceSourceString but that would require a public api change in MessageEncoder
// as ByteStreamMessageEncoder is in a different assemly. The same logic is reimplemented here.
if (this.traceSourceString == null)
{
this.traceSourceString = DiagnosticTraceBase.CreateDefaultSourceString(this);
}
return this.traceSourceString;
}
class WriteMessageAsyncResult : AsyncResult
{
Message message;
Stream stream;
static Action<IAsyncResult, Exception> onCleanup;
XmlByteStreamWriter writer;
EventTraceActivity eventTraceActivity;
public WriteMessageAsyncResult(Message message, Stream stream, AsyncCallback callback, object state)
: base(callback, state)
{
this.message = message;
this.stream = stream;
this.writer = new XmlByteStreamWriter(stream, false);
if (onCleanup == null)
{
onCleanup = new Action<IAsyncResult, Exception>(Cleanup);
}
this.OnCompleting += onCleanup;
Exception completionException = null;
bool completeSelf = false;
this.eventTraceActivity = null;
if (TD.ByteStreamMessageEncodingStartIsEnabled())
{
this.eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
TD.ByteStreamMessageEncodingStart(this.eventTraceActivity);
}
try
{
IAsyncResult result = message.BeginWriteMessage(writer, PrepareAsyncCompletion(HandleWriteMessage), this);
completeSelf = SyncContinue(result);
}
catch (Exception ex)
{
if (Fx.IsFatal(ex))
{
throw;
}
completeSelf = true;
completionException = ex;
}
if (completeSelf)
{
this.Complete(true, completionException);
}
}
static bool HandleWriteMessage(IAsyncResult result)
{
WriteMessageAsyncResult thisPtr = (WriteMessageAsyncResult)result.AsyncState;
thisPtr.message.EndWriteMessage(result);
thisPtr.writer.Flush();
if (SMTD.MessageWrittenAsynchronouslyByEncoderIsEnabled())
{
SMTD.MessageWrittenAsynchronouslyByEncoder(
thisPtr.eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(thisPtr.message));
}
return true;
}
static void Cleanup(IAsyncResult result, Exception ex)
{
WriteMessageAsyncResult thisPtr = (WriteMessageAsyncResult)result;
bool success = false;
try
{
thisPtr.writer.Close();
success = true;
}
finally
{
if (!success)
{
FxTrace.Exception.TraceHandledException(ex, TraceEventType.Information);
}
}
}
public static void End(IAsyncResult result)
{
AsyncResult.End<WriteMessageAsyncResult>(result);
}
}
}
}

View File

@ -0,0 +1,29 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System.Runtime;
using System.Xml;
class ByteStreamMessageEncoderFactory : MessageEncoderFactory
{
ByteStreamMessageEncoder encoder;
public ByteStreamMessageEncoderFactory(XmlDictionaryReaderQuotas quotas)
{
this.encoder = new ByteStreamMessageEncoder(quotas);
}
public override MessageEncoder Encoder
{
get { return this.encoder; }
}
public override MessageVersion MessageVersion
{
get { return encoder.MessageVersion; }
}
}
}

View File

@ -0,0 +1,109 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime;
using System.Xml;
[Fx.Tag.XamlVisible(false)]
public sealed class ByteStreamMessageEncodingBindingElement : MessageEncodingBindingElement
{
XmlDictionaryReaderQuotas readerQuotas;
public ByteStreamMessageEncodingBindingElement() : this((XmlDictionaryReaderQuotas)null)
{
}
public ByteStreamMessageEncodingBindingElement(XmlDictionaryReaderQuotas quota)
{
this.readerQuotas = new XmlDictionaryReaderQuotas();
if (quota != null)
{
quota.CopyTo(this.readerQuotas);
}
}
ByteStreamMessageEncodingBindingElement(ByteStreamMessageEncodingBindingElement byteStreamEncoderBindingElement)
: this(byteStreamEncoderBindingElement.readerQuotas)
{
}
public override MessageVersion MessageVersion
{
get
{
return MessageVersion.None;
}
set
{
if (value != MessageVersion.None)
{
throw FxTrace.Exception.Argument("MessageVersion", SR.ByteStreamMessageEncoderMessageVersionNotSupported(value));
}
}
}
public XmlDictionaryReaderQuotas ReaderQuotas
{
get
{
return this.readerQuotas;
}
set
{
if (value == null)
throw FxTrace.Exception.ArgumentNull("ReaderQuotas");
value.CopyTo(this.ReaderQuotas);
}
}
public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
{
return InternalCanBuildChannelFactory<TChannel>(context);
}
public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
return InternalBuildChannelFactory<TChannel>(context);
}
public override bool CanBuildChannelListener<TChannel>(BindingContext context)
{
return InternalCanBuildChannelListener<TChannel>(context);
}
public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
return InternalBuildChannelListener<TChannel>(context);
}
public override MessageEncoderFactory CreateMessageEncoderFactory()
{
return new ByteStreamMessageEncoderFactory(this.readerQuotas);
}
public override BindingElement Clone()
{
return new ByteStreamMessageEncodingBindingElement(this);
}
[EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeMessageVersion()
{
// Always MessageVersion.None in ByteStreamMessageEncoder
return false;
}
[EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeReaderQuotas()
{
return (!EncoderDefaults.IsDefaultReaderQuotas(this.ReaderQuotas));
}
}
}

View File

@ -0,0 +1,49 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System.Xml;
static class ByteStreamMessageUtility
{
public const string StreamElementName = "Binary";
public const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
public const string XmlNamespaceNamespace = "http://www.w3.org/2000/xmlns/";
// used when doing message tracing
internal const string EncoderName = "ByteStreamMessageEncoder";
internal static void EnsureByteBoundaries(byte[] buffer, int index, int count, bool isRead)
{
if (buffer == null)
{
throw FxTrace.Exception.ArgumentNull("buffer");
}
if (index < 0)
{
throw FxTrace.Exception.ArgumentOutOfRange("index", index, SR.ArgumentOutOfMinRange(0));
}
// we explicitly allow the case for index = 0, buffer.Length = 0 and count = 0 when it is write
// Note that we rely on the last check of count > buffer.Length - index to cover count > 0 && index == buffer.Length case
if (index > buffer.Length || (isRead && index == buffer.Length))
{
throw FxTrace.Exception.ArgumentOutOfRange("index", index, SR.OffsetExceedsBufferSize(buffer.Length));
}
if (count < 0)
{
throw FxTrace.Exception.ArgumentOutOfRange("count", count, SR.ArgumentOutOfMinRange(0));
}
if (count > buffer.Length - index)
{
throw FxTrace.Exception.ArgumentOutOfRange("count", count, SR.SizeExceedsRemainingBufferSpace(buffer.Length - index));
}
}
internal static XmlDictionaryReaderQuotas EnsureQuotas(XmlDictionaryReaderQuotas quotas)
{
return quotas ?? EncoderDefaults.ReaderQuotas;
}
}
}

View File

@ -0,0 +1,73 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.ServiceModel.Channels
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Runtime;
using System.Runtime.Diagnostics;
using System.ServiceModel.Diagnostics;
using System.Threading;
using System.Xml;
internal class ClientUdpOutputChannel : UdpOutputChannel
{
private EndpointAddress to;
public ClientUdpOutputChannel(ChannelManagerBase factory, IPEndPoint remoteEndPoint, MessageEncoder encoder, BufferManager bufferManager, UdpSocket[] sendSockets, UdpRetransmissionSettings retransmissionSettings, EndpointAddress to, Uri via, bool isMulticast)
: base(factory, encoder, bufferManager, sendSockets, retransmissionSettings, via, isMulticast)
{
Fx.Assert(to != null, "to address can't be null for this constructor...");
Fx.Assert(remoteEndPoint != null, "remoteEndPoint can't be null");
this.RemoteEndPoint = remoteEndPoint;
this.to = to;
}
public IPEndPoint RemoteEndPoint
{
get;
private set;
}
protected override UdpSocket[] GetSendSockets(Message message, out IPEndPoint remoteEndPoint, out Exception exceptionToBeThrown)
{
UdpSocket[] socketList = null;
remoteEndPoint = this.RemoteEndPoint;
exceptionToBeThrown = null;
if (this.IsMulticast)
{
// always send on all sockets...
socketList = this.SendSockets;
}
else
{
Fx.Assert(this.SendSockets.Length == 1, "Unicast Send socket list on client should always be 1 item long");
socketList = this.SendSockets;
}
return socketList;
}
protected override void AddHeadersTo(Message message)
{
Fx.Assert(message != null, "Message can't be null");
if (message.Version.Addressing != AddressingVersion.None)
{
this.to.ApplyTo(message);
}
message.Properties.Via = this.Via;
base.AddHeadersTo(message);
}
}
}

View File

@ -0,0 +1,102 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System;
using System.Runtime;
using System.Security.Cryptography;
sealed class DuplicateMessageDetector : IDisposable
{
HashAlgorithm hashAlgorithm;
[Fx.Tag.Cache(typeof(string), Fx.Tag.CacheAttrition.PartialPurgeOnEachAccess, SizeLimit = "maxListLength parameter to constructor")]
DuplicateDetector<string> duplicateDetector;
[Fx.Tag.SynchronizationObject()]
object thisLock;
bool disposed;
public DuplicateMessageDetector(int maxListLength)
{
Fx.Assert(maxListLength > 0, "maxListLength must be > 0");
this.disposed = false;
this.hashAlgorithm = HashAlgorithm.Create();
this.thisLock = new object();
this.duplicateDetector = new DuplicateDetector<string>(maxListLength);
}
public bool IsDuplicate(ArraySegment<byte> msgBytes, out string hashString)
{
Fx.Assert(msgBytes != null, "messageBytes can't be null");
Fx.Assert(msgBytes.Count > 0, "messageBytes.Count must be > 0");
byte[] hash;
bool notDuplicate = true;
lock (this.thisLock)
{
if (disposed)
{
throw FxTrace.Exception.AsError(new ObjectDisposedException(this.GetType().ToString()));
}
hash = this.hashAlgorithm.ComputeHash(msgBytes.Array, msgBytes.Offset, msgBytes.Count);
}
hashString = Convert.ToBase64String(hash);
Fx.Assert(string.IsNullOrEmpty(hashString) == false, "computed hashstring is null or empty");
lock (this.thisLock)
{
//the act of retreiving an existing item pushes it to the front of the MRU list, ensuring
//that the oldest hashes are trimmed first when we hit the max length.
notDuplicate = this.duplicateDetector.AddIfNotDuplicate(hashString);
}
return !notDuplicate;
}
public void RemoveEntry(string msgHash)
{
Fx.Assert(!string.IsNullOrEmpty(msgHash), "Message hash should never be null or empty");
lock (this.thisLock)
{
if (this.disposed)
{
throw FxTrace.Exception.AsError(new ObjectDisposedException(this.GetType().ToString()));
}
this.duplicateDetector.Remove(msgHash);
}
}
public void Dispose()
{
if (this.disposed)
{
return;
}
lock (this.thisLock)
{
if (!this.disposed)
{
this.disposed = true;
if (this.duplicateDetector != null)
{
this.duplicateDetector.Clear();
}
this.hashAlgorithm.Clear();
this.hashAlgorithm = null;
}
}
}
}
}

View File

@ -0,0 +1,45 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.ServiceModel.Channels
{
using System;
using System.Net.Http;
using System.Runtime;
/// <summary>
/// A static extension methods class for getting a <see cref="Message"/> instance
/// from an <see cref="HttpRequestMessage"/> instance.
/// </summary>
public static class HttpRequestMessageExtensionMethods
{
/// <summary>
/// An extension method for getting a <see cref="Message"/> instance
/// from an <see cref="HttpRequestMessage"/> instance.
/// </summary>
/// <remarks>
/// The <see cref="Message"/> instance can be read, written and copied
/// just as a traditional <see cref="ByteStreamMessage"/> instance. The
/// <see cref="Message"/> instance can also "read" to retrieve the original
/// <see cref="HttpRequestMessage"/> instance by calling the
/// <see cref="MessageExtensionMethods.ToHttpRequestMessage">
/// Message.ToHttpRequestMessage()</see> extension method.
/// </remarks>
/// <param name="httpRequestMessage">The <see cref="HttpRequestMessage"/>
/// from which to create the <see cref="Message"/> instance.</param>
/// <returns>The new <see cref="Message"/> instance.</returns>
public static Message ToMessage(this HttpRequestMessage httpRequestMessage)
{
if (httpRequestMessage == null)
{
throw FxTrace.Exception.ArgumentNull("httpRequestMessage");
}
Message message = ByteStreamMessage.CreateMessage(httpRequestMessage, null);
message.ConfigureAsHttpMessage(httpRequestMessage);
return message;
}
}
}

View File

@ -0,0 +1,45 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.ServiceModel.Channels
{
using System;
using System.Net.Http;
using System.Runtime;
/// <summary>
/// A static extension methods class for getting a <see cref="Message"/> instance
/// from an <see cref="HttpResponseMessage"/> instance.
/// </summary>
public static class HttpResponseMessageExtensionMethods
{
/// <summary>
/// An extension method for getting a <see cref="Message"/> instance
/// from an <see cref="HttpResponseMessage"/> instance.
/// </summary>
/// <remarks>
/// The <see cref="Message"/> instance can be read, written and copied
/// just as a traditional <see cref="ByteStreamMessage"/> instance. The
/// <see cref="Message"/> instance can also "read" to retrieve the original
/// <see cref="HttpResponseMessage"/> instance by calling the
/// <see cref="MessageExtensionMethods.ToHttpResponseMessage">
/// Message.ToHttpResponseMessage()</see> extension method.
/// </remarks>
/// <param name="httpResponseMessage">The <see cref="HttpResponseMessage"/>
/// from which to create the <see cref="Message"/> instance.</param>
/// <returns>The new <see cref="Message"/> instance.</returns>
public static Message ToMessage(this HttpResponseMessage httpResponseMessage)
{
if (httpResponseMessage == null)
{
throw FxTrace.Exception.ArgumentNull("httpResponseMessage");
}
Message message = ByteStreamMessage.CreateMessage(httpResponseMessage, null);
message.ConfigureAsHttpMessage(httpResponseMessage);
return message;
}
}
}

View File

@ -0,0 +1,21 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
interface IUdpReceiveHandler
{
int MaxReceivedMessageSize { get; }
void HandleAsyncException(Exception exception);
//returns false if the message was dropped because the max pending message count was hit.
bool HandleDataReceived(ArraySegment<byte> data, EndPoint remoteEndpoint, int interfaceIndex, Action onMessageDequeuedCallback);
}
}

View File

@ -0,0 +1,201 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.ServiceModel.Channels
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Runtime;
/// <summary>
/// A static extension methods class for getting either an <see cref="HttpRequestMessage"/>
/// or <see cref="HttpResponseMessage"/> instance from a <see cref="Message"/> instance.
/// </summary>
public static class MessageExtensionMethods
{
private const string MessageHeadersPropertyKey = "System.ServiceModel.Channels.MessageHeaders";
private const string ToHttpRequestMessageMethodName = "ToHttpRequestMessage()";
private const string ToHttpResponseMessageMethodName = "ToHttpResponseMessage()";
private static readonly string HttpRequestMessagePropertyTypeName = typeof(HttpRequestMessageProperty).Name;
private static readonly string HttpResponseMessagePropertyTypeName = typeof(HttpResponseMessageProperty).Name;
/// <summary>
/// An extension method for getting a <see cref="HttpRequestMessage"/> instance
/// from an <see cref="Message"/> instance.
/// </summary>
/// <param name="message">The <see cref="Message"/> instance from which to
/// get the <see cref="HttpRequestMessage"/> instance.</param>
/// <returns>The <see cref="HttpRequestMessage"/> instance.</returns>
public static HttpRequestMessage ToHttpRequestMessage(this Message message)
{
if (message == null)
{
throw FxTrace.Exception.ArgumentNull("message");
}
HttpRequestMessage httpRequestMessage = HttpRequestMessageProperty.GetHttpRequestMessageFromMessage(message);
if (httpRequestMessage == null)
{
HttpRequestMessageProperty requestMessageProperty = message.Properties.GetValue<HttpRequestMessageProperty>(HttpRequestMessageProperty.Name);
if (requestMessageProperty == null)
{
throw FxTrace.Exception.AsError(
new InvalidOperationException(
SR.MissingHttpMessageProperty(
ToHttpRequestMessageMethodName,
HttpRequestMessagePropertyTypeName)));
}
httpRequestMessage = CreateRequestMessage(message, requestMessageProperty);
}
return httpRequestMessage;
}
/// <summary>
/// An extension method for getting a <see cref="HttpResponseMessage"/> instance
/// from an <see cref="Message"/> instance.
/// </summary>
/// <param name="message">The <see cref="Message"/> instance from which to
/// get the <see cref="HttpResponseMessage"/> instance.</param>
/// <returns>The <see cref="HttpResponseMessage"/> instance.</returns>
public static HttpResponseMessage ToHttpResponseMessage(this Message message)
{
if (message == null)
{
throw FxTrace.Exception.ArgumentNull("message");
}
HttpResponseMessage httpResponseMessage = HttpResponseMessageProperty.GetHttpResponseMessageFromMessage(message);
if (httpResponseMessage == null)
{
HttpResponseMessageProperty responseMessageProperty = message.Properties.GetValue<HttpResponseMessageProperty>(HttpResponseMessageProperty.Name);
if (responseMessageProperty == null)
{
throw FxTrace.Exception.AsError(
new InvalidOperationException(
SR.MissingHttpMessageProperty(
ToHttpResponseMessageMethodName,
HttpResponseMessagePropertyTypeName)));
}
httpResponseMessage = CreateResponseMessage(message, responseMessageProperty);
}
return httpResponseMessage;
}
internal static void ConfigureAsHttpMessage(this Message message, HttpRequestMessage httpRequestMessage)
{
Fx.Assert(message != null, "The 'message' parameter should never be null.");
Fx.Assert(httpRequestMessage != null, "The 'httpRequestMessage' parameter should never be null.");
message.Properties.Add(HttpRequestMessageProperty.Name, new HttpRequestMessageProperty(httpRequestMessage));
CopyPropertiesToMessage(message, httpRequestMessage.Properties);
}
internal static void ConfigureAsHttpMessage(this Message message, HttpResponseMessage httpResponseMessage)
{
Fx.Assert(message != null, "The 'message' parameter should never be null.");
Fx.Assert(httpResponseMessage != null, "The 'httpResponseMessage' parameter should never be null.");
message.Properties.Add(HttpResponseMessageProperty.Name, new HttpResponseMessageProperty(httpResponseMessage));
HttpRequestMessage httpRequestMessage = httpResponseMessage.RequestMessage;
if (httpRequestMessage != null)
{
CopyPropertiesToMessage(message, httpRequestMessage.Properties);
}
}
private static void CopyPropertiesToMessage(Message message, IDictionary<string, object> properties)
{
Fx.Assert(message != null, "The 'message' parameter should not be null.");
Fx.Assert(properties != null, "The 'properties' parameter should not be null.");
foreach (KeyValuePair<string, object> property in properties)
{
MessageHeaders messageHeaders = property.Value as MessageHeaders;
if (messageHeaders != null &&
messageHeaders.MessageVersion == MessageVersion.None &&
string.Equals(property.Key, MessageHeadersPropertyKey, StringComparison.Ordinal))
{
foreach (MessageHeader header in messageHeaders)
{
message.Headers.Add(header);
}
}
else
{
message.Properties.Add(property.Key, property.Value);
}
}
}
private static HttpRequestMessage CreateRequestMessage(Message message, HttpRequestMessageProperty requestMessageProperty)
{
Fx.Assert(message != null, "The 'message' parameter should not be null.");
Fx.Assert(requestMessageProperty != null, "The 'requestMessageProperty' parameter should not be null.");
HttpRequestMessage request = new HttpRequestMessage();
request.RequestUri = message.Properties.Via;
Fx.Assert(requestMessageProperty.Method != null, "The HttpRequestMessageProperty class ensures the 'Method' property will never be null.");
request.Method = new HttpMethod(requestMessageProperty.Method);
request.Content = CreateMessageContent(message, requestMessageProperty.SuppressEntityBody);
WebHeaderCollection headers = requestMessageProperty.Headers;
foreach (string headerKey in headers.AllKeys)
{
request.AddHeader(headerKey, headers[headerKey]);
}
request.CopyPropertiesFromMessage(message);
return request;
}
private static HttpResponseMessage CreateResponseMessage(Message message, HttpResponseMessageProperty responseMessageProperty)
{
Fx.Assert(message != null, "The 'message' parameter should not be null.");
Fx.Assert(responseMessageProperty != null, "The 'responseMessageProperty' parameter should not be null.");
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = responseMessageProperty.HasStatusCodeBeenSet ?
responseMessageProperty.StatusCode :
message.IsFault ? HttpStatusCode.InternalServerError : HttpStatusCode.OK;
string reasonPhrase = responseMessageProperty.StatusDescription;
if (!string.IsNullOrEmpty(reasonPhrase))
{
response.ReasonPhrase = reasonPhrase;
}
response.Content = CreateMessageContent(message, responseMessageProperty.SuppressEntityBody);
WebHeaderCollection headers = responseMessageProperty.Headers;
foreach (string headerKey in headers.AllKeys)
{
response.AddHeader(headerKey, headers[headerKey]);
}
return response;
}
private static HttpContent CreateMessageContent(Message message, bool suppressEntityBody)
{
Fx.Assert(message != null, "The 'message' parameter should not be null.");
if (suppressEntityBody || message.IsEmpty)
{
return new ByteArrayContent(EmptyArray<byte>.Instance);
}
return new StreamContent(message.GetBody<Stream>());
}
}
}

View File

@ -0,0 +1,83 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System.Runtime;
public class NetworkInterfaceMessageProperty
{
const string PropertyName = "NetworkInterfaceMessageProperty";
public NetworkInterfaceMessageProperty(int interfaceIndex)
{
this.InterfaceIndex = interfaceIndex;
}
NetworkInterfaceMessageProperty(NetworkInterfaceMessageProperty other)
{
this.InterfaceIndex = other.InterfaceIndex;
}
public static string Name
{
get { return PropertyName; }
}
public int InterfaceIndex
{
get;
private set;
}
public static bool TryGet(Message message, out NetworkInterfaceMessageProperty property)
{
if (message == null)
{
throw FxTrace.Exception.ArgumentNull("message");
}
return TryGet(message.Properties, out property);
}
public static bool TryGet(MessageProperties properties, out NetworkInterfaceMessageProperty property)
{
if (properties == null)
{
throw FxTrace.Exception.ArgumentNull("properties");
}
object value = null;
if (properties.TryGetValue(PropertyName, out value))
{
property = value as NetworkInterfaceMessageProperty;
}
else
{
property = null;
}
return property != null;
}
public void AddTo(Message message)
{
if (message == null)
{
throw FxTrace.Exception.ArgumentNull("message");
}
AddTo(message.Properties);
}
public void AddTo(MessageProperties properties)
{
if (properties == null)
{
throw FxTrace.Exception.ArgumentNull("properties");
}
properties.Add(NetworkInterfaceMessageProperty.Name, this);
}
}
}

View File

@ -0,0 +1,304 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.ServiceModel.Channels
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Runtime;
using System.Runtime.Diagnostics;
using System.ServiceModel.Diagnostics;
using System.Threading;
using System.Xml;
internal class ServerUdpOutputChannel : UdpOutputChannel
{
public ServerUdpOutputChannel(ChannelManagerBase factory, MessageEncoder encoder, BufferManager bufferManager, UdpSocket[] sendSockets, UdpRetransmissionSettings retransmissionSettings, Uri via, bool isMulticast)
: base(factory, encoder, bufferManager, sendSockets, retransmissionSettings, via, isMulticast)
{
}
// will either return a valid socket or will set exceptionToBeThrown
protected UdpSocket GetSendSocket(IPAddress address, Uri destination, out Exception exceptionToBeThrown)
{
Fx.Assert(this.IsMulticast == false, "This overload should only be used for unicast.");
UdpSocket result = null;
exceptionToBeThrown = null;
AddressFamily family = address.AddressFamily;
lock (ThisLock)
{
if (this.State == CommunicationState.Opened)
{
for (int i = 0; i < this.SendSockets.Length; i++)
{
if (family == this.SendSockets[i].AddressFamily)
{
result = this.SendSockets[i];
break;
}
}
if (result == null)
{
exceptionToBeThrown = new InvalidOperationException(SR.RemoteAddressUnreachableDueToIPVersionMismatch(destination));
}
}
else
{
exceptionToBeThrown = CreateObjectDisposedException();
}
}
return result;
}
// will either return a valid socket or will set exceptionToBeThrown
protected UdpSocket GetSendSocket(int interfaceIndex, out Exception exceptionToBeThrown)
{
Fx.Assert(this.IsMulticast == true, "This overload should only be used for multicast.");
UdpSocket result = null;
exceptionToBeThrown = null;
lock (ThisLock)
{
if (this.State == CommunicationState.Opened)
{
for (int i = 0; i < this.SendSockets.Length; i++)
{
if (interfaceIndex == this.SendSockets[i].InterfaceIndex)
{
result = this.SendSockets[i];
break;
}
}
if (result == null)
{
exceptionToBeThrown = new InvalidOperationException(SR.UdpSendFailedInterfaceIndexMatchNotFound(interfaceIndex));
}
}
else
{
exceptionToBeThrown = CreateObjectDisposedException();
}
}
return result;
}
// 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;
}
private UdpSocket GetSendSocketUsingInterfaceIndex(MessageProperties properties, out Exception exceptionToBeThrown)
{
NetworkInterfaceMessageProperty property;
UdpSocket socket = null;
exceptionToBeThrown = null;
if (!NetworkInterfaceMessageProperty.TryGet(properties, out property))
{
if (this.SendSockets.Length > 1)
{
// this property is required on all messages sent from the channel listener.
// the client channel does not use this method to get the send SendSockets or the
// remote endpoint, so it is safe to throw...
exceptionToBeThrown = new InvalidOperationException(SR.NetworkInterfaceMessagePropertyMissing(typeof(NetworkInterfaceMessageProperty)));
}
else
{
// there is only one socket, so just send it on that one.
socket = this.SendSockets[0];
}
}
else
{
socket = this.GetSendSocket(property.InterfaceIndex, out exceptionToBeThrown);
}
return socket;
}
private void ValidateDestinationUri(Uri destination, bool isVia)
{
if (!destination.Scheme.Equals(UdpConstants.Scheme, StringComparison.OrdinalIgnoreCase))
{
if (isVia)
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ViaUriIsNotValid(destination, SR.UriSchemeNotSupported(destination.Scheme))));
}
else
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ToAddressIsNotValid(destination, SR.UriSchemeNotSupported(destination.Scheme))));
}
}
if (destination.Port < 1 || destination.Port > IPEndPoint.MaxPort)
{
if (isVia)
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ViaUriIsNotValid(destination, SR.PortNumberInvalid(1, IPEndPoint.MaxPort))));
}
else
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ToAddressIsNotValid(destination, SR.PortNumberInvalid(1, IPEndPoint.MaxPort))));
}
}
}
}
}

View File

@ -0,0 +1,78 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System;
class SynchronizedRandom : Random
{
public SynchronizedRandom()
: base()
{
this.ThisLock = new object();
}
public SynchronizedRandom(int seed)
: base(seed)
{
this.ThisLock = new object();
}
protected object ThisLock
{
get;
private set;
}
public override int Next(int minValue, int maxValue)
{
lock (this.ThisLock)
{
return base.Next(minValue, maxValue);
}
}
public override int Next()
{
lock (this.ThisLock)
{
return base.Next();
}
}
public override int Next(int maxValue)
{
lock (this.ThisLock)
{
return base.Next(maxValue);
}
}
public override void NextBytes(byte[] buffer)
{
lock (this.ThisLock)
{
base.NextBytes(buffer);
}
}
public override double NextDouble()
{
lock (this.ThisLock)
{
return base.NextDouble();
}
}
protected override double Sample()
{
lock (this.ThisLock)
{
return base.Sample();
}
}
}
}

View File

@ -0,0 +1,498 @@
// <copyright>
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
namespace System.ServiceModel.Channels
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Runtime;
using System.Runtime.Diagnostics;
using System.ServiceModel.Diagnostics;
using System.Threading;
using System.Xml;
internal abstract class UdpChannelBase<QueueItemType> : InputQueueChannel<QueueItemType>, IUdpReceiveHandler
where QueueItemType : class, IDisposable
{
private bool cleanedUp;
private long pendingMessagesTotalSize;
private long maxPendingMessagesTotalSize;
private int maxReceivedMessageSize;
private UdpRetransmissionSettings retransmitSettings;
private Uri via;
protected UdpChannelBase(
ChannelManagerBase channelManager,
MessageEncoder encoder,
BufferManager bufferManager,
UdpSocket[] sockets,
UdpRetransmissionSettings retransmissionSettings,
long maxPendingMessagesTotalSize,
EndpointAddress localAddress,
Uri via,
bool isMulticast,
int maxReceivedMessageSize)
: base(channelManager)
{
Fx.Assert(encoder != null, "encoder shouldn't be null");
Fx.Assert(bufferManager != null, "buffer manager shouldn't be null");
Fx.Assert(sockets != null, "sendSockets can't be null");
Fx.Assert(sockets.Length > 0, "sendSockets can't be empty");
Fx.Assert(retransmissionSettings != null, "retransmissionSettings can't be null");
Fx.Assert(maxPendingMessagesTotalSize >= 0, "maxPendingMessagesTotalSize must be >= 0");
Fx.Assert(maxReceivedMessageSize > 0, "maxReceivedMessageSize must be > 0");
Fx.Assert(localAddress != null, "localAddress can't be null");
Fx.Assert(via != null, "via can't be null");
this.maxPendingMessagesTotalSize = maxPendingMessagesTotalSize == UdpConstants.Defaults.DefaultMaxPendingMessagesTotalSize ? UdpConstants.Defaults.MaxPendingMessagesTotalSize : maxPendingMessagesTotalSize;
this.Encoder = encoder;
this.Sockets = sockets;
this.BufferManager = bufferManager;
this.retransmitSettings = retransmissionSettings;
this.IsMulticast = isMulticast;
this.DuplicateDetector = null;
this.ReceiveManager = null;
this.OwnsBufferManager = false;
this.maxReceivedMessageSize = maxReceivedMessageSize;
this.LocalAddress = localAddress;
this.via = via;
}
public EndpointAddress LocalAddress
{
get;
private set;
}
public Uri Via
{
get { return this.via; }
}
int IUdpReceiveHandler.MaxReceivedMessageSize
{
get { return this.maxReceivedMessageSize; }
}
protected abstract bool IgnoreSerializationException { get; }
protected bool OwnsBufferManager { get; set; }
protected DuplicateMessageDetector DuplicateDetector { get; set; }
protected UdpSocketReceiveManager ReceiveManager { get; set; }
protected BufferManager BufferManager
{
get;
private set;
}
protected MessageEncoder Encoder
{
get;
private set;
}
protected bool IsMulticast
{
get;
private set;
}
protected UdpOutputChannel UdpOutputChannel { get; private set; }
protected UdpSocket[] Sockets
{
get;
private set;
}
[SuppressMessage("Microsoft.StyleCop.CSharp.ReadabilityRules", "SA1100:DoNotPrefixCallsWithBaseUnlessLocalImplementationExists", Justification = "StyleCop 4.5 does not validate this rule properly.")]
public override T GetProperty<T>()
{
if (typeof(T) == typeof(IDuplexChannel))
{
return (T)(object)this;
}
T outputChannelProperty = this.UdpOutputChannel.GetProperty<T>();
if (outputChannelProperty != null)
{
return outputChannelProperty;
}
T messageEncoderProperty = this.Encoder.GetProperty<T>();
if (messageEncoderProperty != null)
{
return messageEncoderProperty;
}
return base.GetProperty<T>();
}
// 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;
}
void IUdpReceiveHandler.HandleAsyncException(Exception ex)
{
this.HandleReceiveException(ex);
}
internal virtual void HandleReceiveException(Exception ex)
{
this.EnqueueAndDispatch(UdpUtility.WrapAsyncException(ex), null, false);
}
// Since ChannelListener and channel lifetimes can be different, we need a
// way to transfer the socketReceiveManager and DuplicateMessageDetection
// objects to the channel if the listener gets closed. If this method succeeds, then
// this also indicates that the bufferManager is no longer owned by the channel listener,
// so we have to clean that up also.
internal bool TransferReceiveManagerOwnership(UdpSocketReceiveManager socketReceiveManager, DuplicateMessageDetector duplicateDetector)
{
bool success = false;
if (this.State == CommunicationState.Opened)
{
lock (ThisLock)
{
if (this.State == CommunicationState.Opened)
{
Fx.Assert(this.ReceiveManager == null, "ReceiveManager is already set to a non-null value");
Fx.Assert(this.DuplicateDetector == null, "DuplicateDetector is already set to a non-null value");
this.ReceiveManager = socketReceiveManager;
this.OwnsBufferManager = true;
this.ReceiveManager.SetReceiveHandler(this);
this.DuplicateDetector = duplicateDetector;
success = true;
}
}
}
return success;
}
// returns false if the max pending messages total size was hit.
internal bool EnqueueMessage(Message message, int messageBufferSize, Action messageDequeuedCallback)
{
Action onMessageDequeuedCallback = () =>
{
lock (this.ThisLock)
{
this.pendingMessagesTotalSize -= messageBufferSize;
Fx.Assert(this.pendingMessagesTotalSize >= 0, "pendingMessagesTotalSize should not be negative.");
}
messageDequeuedCallback();
};
bool success = false;
lock (this.ThisLock)
{
if (this.pendingMessagesTotalSize + messageBufferSize <= this.maxPendingMessagesTotalSize)
{
message.Properties.Via = this.Via;
this.pendingMessagesTotalSize += messageBufferSize;
try
{
this.FinishEnqueueMessage(message, onMessageDequeuedCallback, false);
success = true;
}
finally
{
if (!success)
{
this.pendingMessagesTotalSize -= messageBufferSize;
}
}
}
else
{
if (TD.MaxPendingMessagesTotalSizeReachedIsEnabled())
{
string messageIdString = string.Empty;
if (message.Headers.MessageId != null)
{
messageIdString = string.Format(CultureInfo.CurrentCulture, "'{0}' ", message.Headers.MessageId.ToString());
}
EventTraceActivity eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
TD.MaxPendingMessagesTotalSizeReached(eventTraceActivity, messageIdString, this.maxPendingMessagesTotalSize, typeof(TransportBindingElement).FullName);
}
}
}
return success;
}
internal abstract void FinishEnqueueMessage(Message message, Action dequeuedCallback, bool canDispatchOnThisThread);
protected virtual void AddHeadersTo(Message message)
{
Fx.Assert(message != null, "Message can't be null");
if (message.Version.Addressing != AddressingVersion.None)
{
if (message.Headers.MessageId == null)
{
message.Headers.MessageId = new UniqueId();
}
}
else
{
if (this.retransmitSettings.Enabled == true)
{
// we should only get here if some channel above us starts producing messages that don't match the encoder's message version.
throw FxTrace.Exception.AsError(new ProtocolException(SR.RetransmissionRequiresAddressingOnMessage(message.Version.Addressing.ToString())));
}
}
}
// Closes the channel ungracefully during error conditions.
protected override void OnAbort()
{
this.Cleanup(true, TimeSpan.Zero);
}
protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
{
this.OnOpen(timeout);
return new CompletedAsyncResult(callback, state);
}
protected override void OnEndOpen(IAsyncResult result)
{
CompletedAsyncResult.End(result);
}
protected override void OnOpen(TimeSpan timeout)
{
this.UdpOutputChannel.Open();
}
protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
{
return new CloseAsyncResult<QueueItemType>(
this,
new ChainedBeginHandler(base.OnBeginClose),
new ChainedEndHandler(base.OnEndClose),
timeout,
callback,
state);
}
protected override void OnEndClose(IAsyncResult result)
{
CloseAsyncResult<QueueItemType>.End(result);
}
// Closes the channel gracefully during normal conditions.
protected override void OnClose(TimeSpan timeout)
{
TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
this.Cleanup(false, timeoutHelper.RemainingTime());
base.OnClose(timeoutHelper.RemainingTime());
}
protected void SetOutputChannel(UdpOutputChannel udpOutputChannel)
{
Fx.Assert(this.UdpOutputChannel == null, "this.UdpOutputChannel must be null");
Fx.Assert(udpOutputChannel != null, "udpOutputChannel can't be null, since SetOutputChannel should be called only once");
this.UdpOutputChannel = udpOutputChannel;
}
// We're guaranteed by CommunicationObject that at most ONE of Close or BeginClose will be called once.
protected void Cleanup(bool aborting, TimeSpan timeout)
{
if (this.cleanedUp)
{
return;
}
lock (ThisLock)
{
if (this.cleanedUp)
{
return;
}
if (aborting)
{
this.UdpOutputChannel.Abort();
}
else
{
this.UdpOutputChannel.Close(timeout);
}
if (this.DuplicateDetector != null)
{
this.DuplicateDetector.Dispose();
}
if (this.ReceiveManager != null)
{
this.ReceiveManager.Close();
}
this.CleanupBufferManager();
this.cleanedUp = true;
}
}
private void CleanupBufferManager()
{
if (this.OwnsBufferManager)
{
this.BufferManager.Clear();
}
}
// Control flow for async path
// We use this mechanism to avoid initializing two async objects as logically cleanup+close is one operation.
// At any point in the Begin* methods, we may go async. The steps are:
// - Close inner UdpOutputChannel
// - Cleanup channel
// - Close channel
private class CloseAsyncResult<T> : AsyncResult
where T : class, IDisposable
{
private static AsyncCompletion completeCloseOutputChannelCallback = new AsyncCompletion(CompleteCloseOutputChannel);
private static AsyncCompletion completeBaseCloseCallback = new AsyncCompletion(CompleteBaseClose);
private UdpChannelBase<T> channel;
private TimeoutHelper timeoutHelper;
private ChainedBeginHandler baseBeginClose;
private ChainedEndHandler baseEndClose;
public CloseAsyncResult(UdpChannelBase<T> channel, ChainedBeginHandler baseBeginClose, ChainedEndHandler baseEndClose, TimeSpan timeout, AsyncCallback callback, object state)
: base(callback, state)
{
this.channel = channel;
this.baseBeginClose = baseBeginClose;
this.baseEndClose = baseEndClose;
this.timeoutHelper = new TimeoutHelper(timeout);
if (this.BeginCloseOutputChannel())
{
this.Complete(true);
}
}
public static void End(IAsyncResult result)
{
AsyncResult.End<CloseAsyncResult<T>>(result);
}
private static bool CompleteBaseClose(IAsyncResult result)
{
// AsyncResult.AsyncCompletionWrapperCallback takes care of catching exceptions for us.
CloseAsyncResult<T> thisPtr = (CloseAsyncResult<T>)result.AsyncState;
// We are completing the base class close operation at this point.
thisPtr.baseEndClose(result);
return true;
}
private static bool CompleteCloseOutputChannel(IAsyncResult result)
{
// AsyncResult.AsyncCompletionWrapperCallback takes care of catching exceptions for us.
CloseAsyncResult<T> thisPtr = (CloseAsyncResult<T>)result.AsyncState;
// We are completing the base class close operation at this point.
thisPtr.channel.UdpOutputChannel.EndClose(result);
thisPtr.channel.Cleanup(false, thisPtr.timeoutHelper.RemainingTime());
return thisPtr.BeginBaseClose();
}
private bool BeginCloseOutputChannel()
{
// AsyncResult.AsyncCompletionWrapperCallback takes care of catching the exceptions for us.
IAsyncResult result = this.channel.UdpOutputChannel.BeginClose(this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(completeCloseOutputChannelCallback), this);
// SyncContinue calls CompleteCloseOutputChannel for us in [....] case.
return this.SyncContinue(result);
}
private bool BeginBaseClose()
{
// AsyncResult.AsyncCompletionWrapperCallback takes care of catching the exceptions for us.
IAsyncResult result = this.baseBeginClose(this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(completeBaseCloseCallback), this);
// SyncContinue calls CompleteBaseClose for us in [....] case.
return this.SyncContinue(result);
}
}
}
}

View File

@ -0,0 +1,385 @@
//----------------------------------------------------------------
// 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;
class UdpChannelFactory<TChannel> : ChannelFactoryBase<TChannel>
{
MessageEncoderFactory messageEncoderFactory;
UdpTransportBindingElement udpTransportBindingElement;
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);
}
BufferManager BufferManager
{
get;
set;
}
public override T GetProperty<T>()
{
T messageEncoderProperty = this.messageEncoderFactory.Encoder.GetProperty<T>();
if (messageEncoderProperty != null)
{
return messageEncoderProperty;
}
if (typeof(T) == typeof(MessageVersion))
{
return (T)(object)this.messageEncoderFactory.Encoder.MessageVersion;
}
return base.GetProperty<T>();
}
protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
{
this.OnOpen(timeout);
return new CompletedAsyncResult(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;
}
protected override void OnEndOpen(IAsyncResult result)
{
CompletedAsyncResult.End(result);
}
protected override void OnOpen(TimeSpan timeout)
{
}
//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;
}
sealed class ClientUdpDuplexChannel : UdpDuplexChannel
{
EndpointAddress to;
ChannelParameterCollection channelParameters;
internal ClientUdpDuplexChannel(UdpChannelFactory<IDuplexChannel> factory, UdpSocket[] sockets, IPEndPoint remoteEndPoint, EndpointAddress localAddress, EndpointAddress to, Uri via, bool isMulticast)
: base(factory,
factory.messageEncoderFactory.Encoder,
factory.BufferManager,
sockets,
factory.udpTransportBindingElement.RetransmissionSettings,
factory.udpTransportBindingElement.MaxPendingMessagesTotalSize,
localAddress,
via,
isMulticast,
(int)factory.udpTransportBindingElement.MaxReceivedMessageSize)
{
Fx.Assert(to != null, "to address can't be null for this constructor...");
Fx.Assert(remoteEndPoint != null, "remoteEndPoint can't be null");
this.RemoteEndPoint = remoteEndPoint;
this.to = to;
if (factory.udpTransportBindingElement.DuplicateMessageHistoryLength > 0)
{
this.DuplicateDetector = new DuplicateMessageDetector(factory.udpTransportBindingElement.DuplicateMessageHistoryLength);
}
else
{
this.DuplicateDetector = null;
}
UdpOutputChannel udpOutputChannel = new ClientUdpOutputChannel(factory, remoteEndPoint, factory.messageEncoderFactory.Encoder, factory.BufferManager, sockets, factory.udpTransportBindingElement.RetransmissionSettings, to, via, isMulticast);
this.SetOutputChannel(udpOutputChannel);
}
protected override bool IgnoreSerializationException
{
get
{
return this.IsMulticast;
}
}
public override EndpointAddress RemoteAddress
{
get
{
return this.to;
}
}
public IPEndPoint RemoteEndPoint
{
get;
private set;
}
public override T GetProperty<T>()
{
if (typeof(T) == typeof(ChannelParameterCollection))
{
if (this.State == CommunicationState.Created)
{
lock (ThisLock)
{
if (this.channelParameters == null)
{
this.channelParameters = new ChannelParameterCollection();
}
}
}
return (T)(object)this.channelParameters;
}
else
{
return base.GetProperty<T>();
}
}
protected override void OnOpened()
{
this.ReceiveManager = new UdpSocketReceiveManager(this.Sockets,
UdpConstants.PendingReceiveCountPerProcessor * Environment.ProcessorCount,
base.BufferManager,
this);
//do the state change to CommunicationState.Opened before starting the receive loop.
//this avoids a ---- between transitioning state and processing messages that are
//already in the socket receive buffer.
base.OnOpened();
this.ReceiveManager.Open();
}
protected override void AddHeadersTo(Message message)
{
Fx.Assert(message != null, "Message can't be null");
if (message.Version.Addressing != AddressingVersion.None)
{
this.to.ApplyTo(message);
}
message.Properties.Via = this.Via;
base.AddHeadersTo(message);
}
}
}
}

View File

@ -0,0 +1,53 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System;
using System.Globalization;
static class UdpConstants
{
// max is 64K - 20 (IP header) - 8(UDP header) - 1 (wraparound)
public const int MaxMessageSizeOverIPv4 = 64 * 1024 - 20 - 8 - 1;
public const int MaxTimeToLive = 255;
public const long MinPendingMessagesTotalSize = 0;
public const int MinReceiveBufferSize = 1;
public const int MinTimeToLive = 0; //localhost traffic only
public const int PendingReceiveCountPerProcessor = 2;
public const string Scheme = "soap.udp";
public const string TimeSpanZero = "00:00:00";
public const string WsdlSoapUdpTransportUri = "http://schemas.microsoft.com/soap/udp";
public const string WsdlSoapUdpTransportNamespace = "http://schemas.microsoft.com/ws/06/2010/policy/soap/udp";
public const string WsdlSoapUdpTransportPrefix = "sud";
public const string RetransmissionEnabled = "RetransmissionEnabled";
internal static class Defaults
{
public static readonly TimeSpan ReceiveTimeout = TimeSpan.FromMinutes(1);
public static readonly TimeSpan SendTimeout = TimeSpan.FromMinutes(1);
public const string EncodingString = "utf-8";
public const string DelayLowerBound = "00:00:00.050";
public const string DelayUpperBound = "00:00:00.250";
public const int DuplicateMessageHistoryLength = 0;
public const int DuplicateMessageHistoryLengthWithRetransmission = 4096;
public const int InterfaceIndex = -1;
public const string MaxDelayPerRetransmission = "00:00:00.500";
public const int MaxRetransmitCount = 0;
public const int MaxUnicastRetransmitCount = 0;
public const int MaxMulticastRetransmitCount = 0;
public const long DefaultMaxPendingMessagesTotalSize = 0;
public static readonly long MaxPendingMessagesTotalSize = 1024 * 1024 * Environment.ProcessorCount; // 512 * 2K messages per processor
public const long MaxReceivedMessageSize = SocketReceiveBufferSize;
public const string MulticastInterfaceId = null;
public const int SocketReceiveBufferSize = 64 * 1024;
public const int TimeToLive = 1;
public static MessageEncoderFactory MessageEncoderFactory = new TextMessageEncodingBindingElement().CreateMessageEncoderFactory();
public static readonly TimeSpan DelayLowerBoundTimeSpan = TimeSpan.Parse(DelayLowerBound, CultureInfo.InvariantCulture);
public static readonly TimeSpan DelayUpperBoundTimeSpan = TimeSpan.Parse(DelayUpperBound, CultureInfo.InvariantCulture);
public static readonly TimeSpan MaxDelayPerRetransmissionTimeSpan = TimeSpan.Parse(MaxDelayPerRetransmission, CultureInfo.InvariantCulture);
}
}
}

View File

@ -0,0 +1,197 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Channels
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Runtime;
using System.Runtime.Diagnostics;
using System.ServiceModel.Diagnostics;
using System.Threading;
using System.Xml;
abstract class UdpDuplexChannel : UdpChannelBase<Message>, IDuplexChannel
{
protected UdpDuplexChannel(
ChannelManagerBase channelMananger,
MessageEncoder encoder,
BufferManager bufferManager,
UdpSocket[] sendSockets,
UdpRetransmissionSettings retransmissionSettings,
long maxPendingMessagesTotalSize,
EndpointAddress localAddress,
Uri via,
bool isMulticast,
int maxReceivedMessageSize)
: base(channelMananger, encoder, bufferManager, sendSockets, retransmissionSettings, maxPendingMessagesTotalSize, localAddress, via, isMulticast, maxReceivedMessageSize)
{
}
public virtual EndpointAddress RemoteAddress
{
get { return null; }
}
public override T GetProperty<T>()
{
if (typeof(T) == typeof(IDuplexChannel))
{
return (T)(object)this;
}
return base.GetProperty<T>();
}
public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state)
{
return this.BeginSend(message, this.DefaultSendTimeout, callback, state);
}
public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
{
ThrowIfDisposedOrNotOpen();
if (message is NullMessage)
{
return new CompletedAsyncResult(callback, state);
}
AddHeadersTo(message);
return this.UdpOutputChannel.BeginSend(message, timeout, callback, state);
}
public void EndSend(IAsyncResult result)
{
if (result is CompletedAsyncResult)
{
CompletedAsyncResult.End(result);
}
else
{
this.UdpOutputChannel.EndSend(result);
}
}
public void Send(Message message)
{
this.Send(message, this.DefaultSendTimeout);
}
public void Send(Message message, TimeSpan timeout)
{
if (message is NullMessage)
{
return;
}
this.UdpOutputChannel.Send(message, timeout);
}
public Message Receive()
{
return this.Receive(this.DefaultReceiveTimeout);
}
public Message Receive(TimeSpan timeout)
{
if (timeout < TimeSpan.Zero)
{
throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
}
this.ThrowPending();
return InputChannel.HelpReceive(this, timeout);
}
public IAsyncResult BeginReceive(AsyncCallback callback, object state)
{
return this.BeginReceive(this.DefaultReceiveTimeout, callback, state);
}
public IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state)
{
if (timeout < TimeSpan.Zero)
{
throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
}
this.ThrowPending();
return InputChannel.HelpBeginReceive(this, timeout, callback, state);
}
public Message EndReceive(IAsyncResult result)
{
return InputChannel.HelpEndReceive(result);
}
public bool TryReceive(TimeSpan timeout, out Message message)
{
if (timeout < TimeSpan.Zero)
{
throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
}
this.ThrowPending();
return base.Dequeue(timeout, out message);
}
public IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
{
if (timeout < TimeSpan.Zero)
{
throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
}
this.ThrowPending();
return base.BeginDequeue(timeout, callback, state);
}
public bool EndTryReceive(IAsyncResult result, out Message message)
{
return base.EndDequeue(result, out message);
}
public bool WaitForMessage(TimeSpan timeout)
{
if (timeout < TimeSpan.Zero)
{
throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
}
this.ThrowPending();
return base.WaitForItem(timeout);
}
public IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state)
{
if (timeout < TimeSpan.Zero)
{
throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("timeout", timeout, SR.TimeoutOutOfRange0));
}
this.ThrowPending();
return base.BeginWaitForItem(timeout, callback, state);
}
public bool EndWaitForMessage(IAsyncResult result)
{
return base.EndWaitForItem(result);
}
internal override void FinishEnqueueMessage(Message message, Action dequeuedCallback, bool canDispatchOnThisThread)
{
if (!this.IsMulticast)
{
//When using Multicast, we can't assume that receiving one message means that we are done receiving messages.
//For example, Discovery will send one message out and receive n responses that match. Because of this, we
//can only short circuit retransmission when using unicast.
this.UdpOutputChannel.CancelRetransmission(message.Headers.RelatesTo);
}
this.EnqueueAndDispatch(message, dequeuedCallback, canDispatchOnThisThread);
}
}
}

Some files were not shown because too many files have changed in this diff Show More