e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
495 lines
19 KiB
C#
495 lines
19 KiB
C#
//------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
namespace System.ServiceModel
|
|
{
|
|
using System.ComponentModel;
|
|
using System.Configuration;
|
|
using System.Runtime;
|
|
using System.ServiceModel.Channels;
|
|
using System.ServiceModel.Configuration;
|
|
using System.Xml;
|
|
|
|
public class NetTcpBinding : Binding, IBindingRuntimePreferences
|
|
{
|
|
OptionalReliableSession reliableSession;
|
|
// private BindingElements
|
|
TcpTransportBindingElement transport;
|
|
BinaryMessageEncodingBindingElement encoding;
|
|
TransactionFlowBindingElement context;
|
|
ReliableSessionBindingElement session;
|
|
NetTcpSecurity security = new NetTcpSecurity();
|
|
|
|
public NetTcpBinding() { Initialize(); }
|
|
public NetTcpBinding(SecurityMode securityMode)
|
|
: this()
|
|
{
|
|
this.security.Mode = securityMode;
|
|
}
|
|
|
|
public NetTcpBinding(SecurityMode securityMode, bool reliableSessionEnabled)
|
|
: this(securityMode)
|
|
{
|
|
this.ReliableSession.Enabled = reliableSessionEnabled;
|
|
}
|
|
|
|
public NetTcpBinding(string configurationName)
|
|
: this()
|
|
{
|
|
ApplyConfiguration(configurationName);
|
|
}
|
|
|
|
NetTcpBinding(TcpTransportBindingElement transport, BinaryMessageEncodingBindingElement encoding, TransactionFlowBindingElement context, ReliableSessionBindingElement session, NetTcpSecurity security)
|
|
: this()
|
|
{
|
|
this.security = security;
|
|
this.ReliableSession.Enabled = session != null;
|
|
InitializeFrom(transport, encoding, context, session);
|
|
}
|
|
|
|
[DefaultValue(NetTcpDefaults.TransactionsEnabled)]
|
|
public bool TransactionFlow
|
|
{
|
|
get { return context.Transactions; }
|
|
set { context.Transactions = value; }
|
|
}
|
|
|
|
public TransactionProtocol TransactionProtocol
|
|
{
|
|
get { return this.context.TransactionProtocol; }
|
|
set { this.context.TransactionProtocol = value; }
|
|
}
|
|
|
|
[DefaultValue(ConnectionOrientedTransportDefaults.TransferMode)]
|
|
public TransferMode TransferMode
|
|
{
|
|
get { return this.transport.TransferMode; }
|
|
set { this.transport.TransferMode = value; }
|
|
}
|
|
|
|
[DefaultValue(ConnectionOrientedTransportDefaults.HostNameComparisonMode)]
|
|
public HostNameComparisonMode HostNameComparisonMode
|
|
{
|
|
get { return transport.HostNameComparisonMode; }
|
|
set { transport.HostNameComparisonMode = value; }
|
|
}
|
|
|
|
[DefaultValue(TransportDefaults.MaxBufferPoolSize)]
|
|
public long MaxBufferPoolSize
|
|
{
|
|
get { return transport.MaxBufferPoolSize; }
|
|
set
|
|
{
|
|
transport.MaxBufferPoolSize = value;
|
|
}
|
|
}
|
|
|
|
[DefaultValue(TransportDefaults.MaxBufferSize)]
|
|
public int MaxBufferSize
|
|
{
|
|
get { return transport.MaxBufferSize; }
|
|
set { transport.MaxBufferSize = value; }
|
|
}
|
|
|
|
public int MaxConnections
|
|
{
|
|
get { return transport.MaxPendingConnections; }
|
|
set
|
|
{
|
|
transport.MaxPendingConnections = value;
|
|
transport.ConnectionPoolSettings.MaxOutboundConnectionsPerEndpoint = value;
|
|
}
|
|
}
|
|
|
|
internal bool IsMaxConnectionsSet
|
|
{
|
|
get { return transport.IsMaxPendingConnectionsSet; }
|
|
}
|
|
|
|
public int ListenBacklog
|
|
{
|
|
get { return transport.ListenBacklog; }
|
|
set { transport.ListenBacklog = value; }
|
|
}
|
|
|
|
internal bool IsListenBacklogSet
|
|
{
|
|
get { return transport.IsListenBacklogSet; }
|
|
}
|
|
|
|
[DefaultValue(TransportDefaults.MaxReceivedMessageSize)]
|
|
public long MaxReceivedMessageSize
|
|
{
|
|
get { return transport.MaxReceivedMessageSize; }
|
|
set { transport.MaxReceivedMessageSize = value; }
|
|
}
|
|
|
|
[DefaultValue(TcpTransportDefaults.PortSharingEnabled)]
|
|
public bool PortSharingEnabled
|
|
{
|
|
get { return transport.PortSharingEnabled; }
|
|
set { transport.PortSharingEnabled = value; }
|
|
}
|
|
|
|
public XmlDictionaryReaderQuotas ReaderQuotas
|
|
{
|
|
get { return encoding.ReaderQuotas; }
|
|
set
|
|
{
|
|
if (value == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
|
|
value.CopyTo(encoding.ReaderQuotas);
|
|
}
|
|
}
|
|
|
|
bool IBindingRuntimePreferences.ReceiveSynchronously
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public OptionalReliableSession ReliableSession
|
|
{
|
|
get
|
|
{
|
|
return reliableSession;
|
|
}
|
|
set
|
|
{
|
|
if (value == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
|
|
}
|
|
this.reliableSession.CopySettings(value);
|
|
}
|
|
}
|
|
|
|
public override string Scheme { get { return transport.Scheme; } }
|
|
|
|
public EnvelopeVersion EnvelopeVersion
|
|
{
|
|
get { return EnvelopeVersion.Soap12; }
|
|
}
|
|
|
|
public NetTcpSecurity Security
|
|
{
|
|
get { return security; }
|
|
set
|
|
{
|
|
if (value == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
|
|
security = value;
|
|
}
|
|
}
|
|
|
|
static TransactionFlowBindingElement GetDefaultTransactionFlowBindingElement()
|
|
{
|
|
return new TransactionFlowBindingElement(NetTcpDefaults.TransactionsEnabled);
|
|
}
|
|
|
|
void Initialize()
|
|
{
|
|
transport = new TcpTransportBindingElement();
|
|
encoding = new BinaryMessageEncodingBindingElement();
|
|
context = GetDefaultTransactionFlowBindingElement();
|
|
session = new ReliableSessionBindingElement();
|
|
this.reliableSession = new OptionalReliableSession(session);
|
|
}
|
|
|
|
void InitializeFrom(TcpTransportBindingElement transport, BinaryMessageEncodingBindingElement encoding, TransactionFlowBindingElement context, ReliableSessionBindingElement session)
|
|
{
|
|
Fx.Assert(transport != null, "Invalid (null) transport value.");
|
|
Fx.Assert(encoding != null, "Invalid (null) encoding value.");
|
|
Fx.Assert(context != null, "Invalid (null) context value.");
|
|
Fx.Assert(security != null, "Invalid (null) security value.");
|
|
|
|
// transport
|
|
this.HostNameComparisonMode = transport.HostNameComparisonMode;
|
|
this.MaxBufferPoolSize = transport.MaxBufferPoolSize;
|
|
this.MaxBufferSize = transport.MaxBufferSize;
|
|
if (transport.IsMaxPendingConnectionsSet)
|
|
{
|
|
this.MaxConnections = transport.MaxPendingConnections;
|
|
}
|
|
if (transport.IsListenBacklogSet)
|
|
{
|
|
this.ListenBacklog = transport.ListenBacklog;
|
|
}
|
|
this.MaxReceivedMessageSize = transport.MaxReceivedMessageSize;
|
|
this.PortSharingEnabled = transport.PortSharingEnabled;
|
|
this.TransferMode = transport.TransferMode;
|
|
|
|
// encoding
|
|
this.ReaderQuotas = encoding.ReaderQuotas;
|
|
|
|
// context
|
|
this.TransactionFlow = context.Transactions;
|
|
this.TransactionProtocol = context.TransactionProtocol;
|
|
|
|
//session
|
|
if (session != null)
|
|
{
|
|
// only set properties that have standard binding manifestations
|
|
this.session.InactivityTimeout = session.InactivityTimeout;
|
|
this.session.Ordered = session.Ordered;
|
|
}
|
|
}
|
|
|
|
// check that properties of the HttpTransportBindingElement and
|
|
// MessageEncodingBindingElement not exposed as properties on BasicHttpBinding
|
|
// match default values of the binding elements
|
|
bool IsBindingElementsMatch(TcpTransportBindingElement transport, BinaryMessageEncodingBindingElement encoding, TransactionFlowBindingElement context, ReliableSessionBindingElement session)
|
|
{
|
|
if (!this.transport.IsMatch(transport))
|
|
return false;
|
|
if (!this.encoding.IsMatch(encoding))
|
|
return false;
|
|
if (!this.context.IsMatch(context))
|
|
return false;
|
|
if (reliableSession.Enabled)
|
|
{
|
|
if (!this.session.IsMatch(session))
|
|
return false;
|
|
}
|
|
else if (session != null)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ApplyConfiguration(string configurationName)
|
|
{
|
|
NetTcpBindingCollectionElement section = NetTcpBindingCollectionElement.GetBindingCollectionElement();
|
|
NetTcpBindingElement element = section.Bindings[configurationName];
|
|
if (element == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(
|
|
SR.GetString(SR.ConfigInvalidBindingConfigurationName,
|
|
configurationName,
|
|
ConfigurationStrings.NetTcpBindingCollectionElementName)));
|
|
}
|
|
else
|
|
{
|
|
element.ApplyConfiguration(this);
|
|
}
|
|
}
|
|
|
|
// In the Win8 profile, some settings for the binding security are not supported.
|
|
void CheckSettings()
|
|
{
|
|
if (!UnsafeNativeMethods.IsTailoredApplication.Value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
NetTcpSecurity security = this.Security;
|
|
if (security == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SecurityMode mode = security.Mode;
|
|
if (mode == SecurityMode.None)
|
|
{
|
|
return;
|
|
}
|
|
else if (mode == SecurityMode.Message)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedSecuritySetting, "Mode", mode)));
|
|
}
|
|
|
|
// Message.ClientCredentialType = Certificate, IssuedToken or Windows are not supported.
|
|
if (mode == SecurityMode.TransportWithMessageCredential)
|
|
{
|
|
MessageSecurityOverTcp message = security.Message;
|
|
if (message != null)
|
|
{
|
|
MessageCredentialType mct = message.ClientCredentialType;
|
|
if ((mct == MessageCredentialType.Certificate) || (mct == MessageCredentialType.IssuedToken) || (mct == MessageCredentialType.Windows))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedSecuritySetting, "Message.ClientCredentialType", mct)));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Transport.ClientCredentialType = Certificate is not supported.
|
|
Fx.Assert((mode == SecurityMode.Transport) || (mode == SecurityMode.TransportWithMessageCredential), "Unexpected SecurityMode value: " + mode);
|
|
TcpTransportSecurity transport = security.Transport;
|
|
if ((transport != null) && (transport.ClientCredentialType == TcpClientCredentialType.Certificate))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedSecuritySetting, "Transport.ClientCredentialType", transport.ClientCredentialType)));
|
|
}
|
|
}
|
|
|
|
public override BindingElementCollection CreateBindingElements()
|
|
{
|
|
this.CheckSettings();
|
|
|
|
// return collection of BindingElements
|
|
BindingElementCollection bindingElements = new BindingElementCollection();
|
|
// order of BindingElements is important
|
|
// add context
|
|
bindingElements.Add(context);
|
|
// add session
|
|
if (reliableSession.Enabled)
|
|
bindingElements.Add(session);
|
|
// add security (*optional)
|
|
SecurityBindingElement wsSecurity = CreateMessageSecurity();
|
|
if (wsSecurity != null)
|
|
bindingElements.Add(wsSecurity);
|
|
// add encoding
|
|
bindingElements.Add(encoding);
|
|
// add transport security
|
|
BindingElement transportSecurity = CreateTransportSecurity();
|
|
if (transportSecurity != null)
|
|
{
|
|
bindingElements.Add(transportSecurity);
|
|
}
|
|
transport.ExtendedProtectionPolicy = security.Transport.ExtendedProtectionPolicy;
|
|
// add transport (tcp)
|
|
bindingElements.Add(transport);
|
|
|
|
return bindingElements.Clone();
|
|
}
|
|
|
|
internal static bool TryCreate(BindingElementCollection elements, out Binding binding)
|
|
{
|
|
binding = null;
|
|
if (elements.Count > 6)
|
|
return false;
|
|
|
|
// collect all binding elements
|
|
TcpTransportBindingElement transport = null;
|
|
BinaryMessageEncodingBindingElement encoding = null;
|
|
TransactionFlowBindingElement context = null;
|
|
ReliableSessionBindingElement session = null;
|
|
SecurityBindingElement wsSecurity = null;
|
|
BindingElement transportSecurity = null;
|
|
|
|
foreach (BindingElement element in elements)
|
|
{
|
|
if (element is SecurityBindingElement)
|
|
wsSecurity = element as SecurityBindingElement;
|
|
else if (element is TransportBindingElement)
|
|
transport = element as TcpTransportBindingElement;
|
|
else if (element is MessageEncodingBindingElement)
|
|
encoding = element as BinaryMessageEncodingBindingElement;
|
|
else if (element is TransactionFlowBindingElement)
|
|
context = element as TransactionFlowBindingElement;
|
|
else if (element is ReliableSessionBindingElement)
|
|
session = element as ReliableSessionBindingElement;
|
|
else
|
|
{
|
|
if (transportSecurity != null)
|
|
return false;
|
|
transportSecurity = element;
|
|
}
|
|
}
|
|
|
|
if (transport == null)
|
|
return false;
|
|
if (encoding == null)
|
|
return false;
|
|
if (context == null)
|
|
context = GetDefaultTransactionFlowBindingElement();
|
|
|
|
TcpTransportSecurity tcpTransportSecurity = new TcpTransportSecurity();
|
|
UnifiedSecurityMode mode = GetModeFromTransportSecurity(transportSecurity);
|
|
|
|
NetTcpSecurity security;
|
|
if (!TryCreateSecurity(wsSecurity, mode, session != null, transportSecurity, tcpTransportSecurity, out security))
|
|
return false;
|
|
|
|
if (!SetTransportSecurity(transportSecurity, security.Mode, tcpTransportSecurity))
|
|
return false;
|
|
|
|
NetTcpBinding netTcpBinding = new NetTcpBinding(transport, encoding, context, session, security);
|
|
if (!netTcpBinding.IsBindingElementsMatch(transport, encoding, context, session))
|
|
return false;
|
|
|
|
binding = netTcpBinding;
|
|
return true;
|
|
}
|
|
|
|
BindingElement CreateTransportSecurity()
|
|
{
|
|
return this.security.CreateTransportSecurity();
|
|
}
|
|
|
|
static UnifiedSecurityMode GetModeFromTransportSecurity(BindingElement transport)
|
|
{
|
|
return NetTcpSecurity.GetModeFromTransportSecurity(transport);
|
|
}
|
|
|
|
static bool SetTransportSecurity(BindingElement transport, SecurityMode mode, TcpTransportSecurity transportSecurity)
|
|
{
|
|
return NetTcpSecurity.SetTransportSecurity(transport, mode, transportSecurity);
|
|
}
|
|
|
|
SecurityBindingElement CreateMessageSecurity()
|
|
{
|
|
if (this.security.Mode == SecurityMode.Message || this.security.Mode == SecurityMode.TransportWithMessageCredential)
|
|
{
|
|
return this.security.CreateMessageSecurity(this.ReliableSession.Enabled);
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static bool TryCreateSecurity(SecurityBindingElement sbe, UnifiedSecurityMode mode, bool isReliableSession, BindingElement transportSecurity, TcpTransportSecurity tcpTransportSecurity, out NetTcpSecurity security)
|
|
{
|
|
if (sbe != null)
|
|
mode &= UnifiedSecurityMode.Message | UnifiedSecurityMode.TransportWithMessageCredential;
|
|
else
|
|
mode &= ~(UnifiedSecurityMode.Message | UnifiedSecurityMode.TransportWithMessageCredential);
|
|
|
|
SecurityMode securityMode = SecurityModeHelper.ToSecurityMode(mode);
|
|
Fx.Assert(SecurityModeHelper.IsDefined(securityMode), string.Format("Invalid SecurityMode value: {0}.", securityMode.ToString()));
|
|
|
|
if (NetTcpSecurity.TryCreate(sbe, securityMode, isReliableSession, transportSecurity, tcpTransportSecurity, out security))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeReaderQuotas()
|
|
{
|
|
return (!EncoderDefaults.IsDefaultReaderQuotas(this.ReaderQuotas));
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeSecurity()
|
|
{
|
|
return this.security.InternalShouldSerialize();
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeTransactionProtocol()
|
|
{
|
|
return (TransactionProtocol != NetTcpDefaults.TransactionProtocol);
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeReliableSession()
|
|
{
|
|
return (this.ReliableSession.Ordered != ReliableSessionDefaults.Ordered
|
|
|| this.ReliableSession.InactivityTimeout != ReliableSessionDefaults.InactivityTimeout
|
|
|| this.ReliableSession.Enabled != ReliableSessionDefaults.Enabled);
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeListenBacklog()
|
|
{
|
|
return transport.ShouldSerializeListenBacklog();
|
|
}
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
public bool ShouldSerializeMaxConnections()
|
|
{
|
|
return transport.ShouldSerializeListenBacklog();
|
|
}
|
|
}
|
|
}
|