From ddca7f4a4a627168d03905338bf6634d8d0a9898 Mon Sep 17 00:00:00 2001 From: v-carwan Date: Thu, 31 Oct 2019 13:37:29 +0800 Subject: [PATCH 1/7] Unit test for SecurityTokenManager. --- .../IdentityModel/SecurityTokenManagerTest.cs | 95 +++++++++++++++++++ .../SecurityTokenSerializerTest.cs | 18 ++-- 2 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 src/System.ServiceModel.Primitives/tests/IdentityModel/SecurityTokenManagerTest.cs diff --git a/src/System.ServiceModel.Primitives/tests/IdentityModel/SecurityTokenManagerTest.cs b/src/System.ServiceModel.Primitives/tests/IdentityModel/SecurityTokenManagerTest.cs new file mode 100644 index 00000000000..fc1088105a6 --- /dev/null +++ b/src/System.ServiceModel.Primitives/tests/IdentityModel/SecurityTokenManagerTest.cs @@ -0,0 +1,95 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +using System.Collections.ObjectModel; +using System.IdentityModel.Policy; +using System.IdentityModel.Selectors; +using System.IdentityModel.Tokens; +using Infrastructure.Common; +using Xunit; + +public class SecurityTokenManagerTest +{ + [WcfFact] + public static void Methods_Override() + { + var tokenManager = new SecurityTokenManagerImpl(); + SecurityTokenVersionImpl tokenVersion = new SecurityTokenVersionImpl(); + SecurityTokenRequirement tokenRequirement = new SecurityTokenRequirement(); + + SecurityTokenAuthenticator authenticator = tokenManager.CreateSecurityTokenAuthenticator(tokenRequirement, out SecurityTokenResolver resolver); + SecurityTokenProvider provider = tokenManager.CreateSecurityTokenProvider(tokenRequirement); + SecurityTokenSerializer serializer = tokenManager.CreateSecurityTokenSerializer(tokenVersion); + + Assert.IsType(authenticator); + Assert.IsType(resolver); + Assert.IsType(provider); + Assert.IsType(serializer); + } +} + +public class SecurityTokenManagerImpl : SecurityTokenManager +{ + public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) + { + Assert.IsType(tokenRequirement); + outOfBandTokenResolver = new SecurityTokenResolverImpl(); + return new SecurityTokenAuthenticatorImpl(); + } + + public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) + { + Assert.IsType(tokenRequirement); + return new SecurityTokenProviderSyncImpl(); + } + + public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion tokenVersion) + { + Assert.IsType(tokenVersion); + return new SecurityTokenSerializerImpl(); + } +} + +public class SecurityTokenVersionImpl : SecurityTokenVersion +{ + public override ReadOnlyCollection GetSecuritySpecifications() + { + return null; + } +} + +public class SecurityTokenAuthenticatorImpl : SecurityTokenAuthenticator +{ + protected override bool CanValidateTokenCore(SecurityToken token) + { + return false; + } + + protected override ReadOnlyCollection ValidateTokenCore(SecurityToken token) + { + return null; + } +} + +public class SecurityTokenResolverImpl : SecurityTokenResolver +{ + protected override bool TryResolveSecurityKeyCore(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityKey key) + { + key = null; + return false; + } + + protected override bool TryResolveTokenCore(SecurityKeyIdentifier keyIdentifier, out SecurityToken token) + { + token = null; + return false; + } + + protected override bool TryResolveTokenCore(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityToken token) + { + token = null; + return false; + } +} diff --git a/src/System.ServiceModel.Primitives/tests/IdentityModel/SecurityTokenSerializerTest.cs b/src/System.ServiceModel.Primitives/tests/IdentityModel/SecurityTokenSerializerTest.cs index f9f45f680a7..ba165678a2c 100644 --- a/src/System.ServiceModel.Primitives/tests/IdentityModel/SecurityTokenSerializerTest.cs +++ b/src/System.ServiceModel.Primitives/tests/IdentityModel/SecurityTokenSerializerTest.cs @@ -22,8 +22,8 @@ public static void Methods_NonNullParam_InvokeAndReturn() var xmlWriter = XmlWriter.Create(new MemoryStream()); var dummyToken = new DummySecurityToken(); var keyIdentifier = new SecurityKeyIdentifier(); - var keyIdentifierClause = new SecurityKeyIdentifierClauseImp("DummyClause"); - var sts = new SecurityTokenSerializerImp(); + var keyIdentifierClause = new SecurityKeyIdentifierClauseImpl("DummyClause"); + var sts = new SecurityTokenSerializerImpl(); Assert.NotNull(sts); Assert.True(sts.CanReadKeyIdentifier(xmlReader)); @@ -38,7 +38,7 @@ public static void Methods_NonNullParam_InvokeAndReturn() SecurityKeyIdentifierClause identifierClause = sts.ReadKeyIdentifierClause(xmlReader); Assert.IsType(token); Assert.IsType(identifier); - Assert.IsType(identifierClause); + Assert.IsType(identifierClause); sts.WriteToken(xmlWriter, dummyToken); sts.WriteKeyIdentifier(xmlWriter, keyIdentifier); @@ -51,7 +51,7 @@ public static void Methods_NonNullParam_InvokeAndReturn() [WcfFact] public static void Methods_NullParam_Throws() { - var sts = new SecurityTokenSerializerImp(); + var sts = new SecurityTokenSerializerImpl(); Assert.NotNull(sts); Assert.Throws(() => sts.CanReadKeyIdentifier(null)); @@ -72,7 +72,7 @@ public static void Methods_NullParam_Throws() } } -public class SecurityTokenSerializerImp : SecurityTokenSerializer +public class SecurityTokenSerializerImpl : SecurityTokenSerializer { public bool WriteTokenCoreCalled = false; public bool WriteKeyIdentifierCoreCalled = false; @@ -110,7 +110,7 @@ protected override bool CanWriteTokenCore(SecurityToken token) protected override SecurityKeyIdentifierClause ReadKeyIdentifierClauseCore(XmlReader reader) { - return new SecurityKeyIdentifierClauseImp("DummyClause"); + return new SecurityKeyIdentifierClauseImpl("DummyClause"); } protected override SecurityKeyIdentifier ReadKeyIdentifierCore(XmlReader reader) @@ -139,13 +139,13 @@ protected override void WriteTokenCore(XmlWriter writer, SecurityToken token) } } -public class SecurityKeyIdentifierClauseImp : SecurityKeyIdentifierClause +public class SecurityKeyIdentifierClauseImpl : SecurityKeyIdentifierClause { - public SecurityKeyIdentifierClauseImp(string clauseType) : base(clauseType) + public SecurityKeyIdentifierClauseImpl(string clauseType) : base(clauseType) { } - public SecurityKeyIdentifierClauseImp(string clauseType, byte[] nonce, int length) : base(clauseType, nonce, length) + public SecurityKeyIdentifierClauseImpl(string clauseType, byte[] nonce, int length) : base(clauseType, nonce, length) { } } From d933f404ea299115a2874c7e1891b1ea53d5c451 Mon Sep 17 00:00:00 2001 From: Stephen Bonikowsky Date: Wed, 30 Oct 2019 10:17:02 -0700 Subject: [PATCH 2/7] Removed commented out code in public contract source. * They were added initially so it would be easier to enable them later if needed but at this point we are done with adding new APIs for the current WSFederation project. --- .../ref/System.ServiceModel.Primitives.cs | 20 ------ .../ref/System.ServiceModel.Security.cs | 72 ------------------- 2 files changed, 92 deletions(-) diff --git a/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs b/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs index 403e02123ca..c4e53d5ed3a 100644 --- a/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs +++ b/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs @@ -94,18 +94,7 @@ protected virtual void EndCancelTokenCore(System.IAsyncResult result) { } public partial class SecurityTokenRequirement { public SecurityTokenRequirement() { } - //public static string TokenTypeProperty { get { return default(string); } } - //public static string KeyUsageProperty { get { return default(string); } } - //public static string KeyTypeProperty { get { return default(string); } } - //public static string KeySizeProperty { get { return default(string); } } - //public static string RequireCryptographicTokenProperty { get { return default(string); } } - //public static string PeerAuthenticationMode { get { return default(string); } } - //public static string IsOptionalTokenProperty { get { return default(string); } } public string TokenType { get { return default; } set { } } - //public bool RequireCryptographicToken { get { return default(System.Boolean); } set { } } - //public SecurityKeyUsage KeyUsage { get { return default(SecurityKeyUsage); } set { } } - //public SecurityKeyType KeyType { get { return default(SecurityKeyType); } set { } } - //public System.Int32 KeySize { get { return default(System.Int32); } set { } } public System.Collections.Generic.IDictionary Properties { get { return default; } } public TValue GetProperty(string propertyName) { return default; } public bool TryGetProperty(string propertyName, out TValue result) { result = default; return default; } @@ -157,11 +146,6 @@ public abstract partial class SecurityKey { internal SecurityKey() { } public abstract int KeySize { get; } - //public abstract byte[] DecryptKey(string algorithm, byte[] keyData) { return default(byte[]); } - //public abstract byte[] EncryptKey(string algorithm, byte[] keyData) { return default(byte[]); } - //public abstract bool IsAsymmetricAlgorithm(string algorithm) { return default(bool); } - //public abstract bool IsSupportedAlgorithm(string algorithm) { return default(bool); } - //public abstract bool IsSymmetricAlgorithm(string algorithm) { return default(bool); } } public class SecurityKeyIdentifier : System.Collections.Generic.IEnumerable { @@ -198,10 +182,6 @@ public abstract partial class SecurityToken public abstract System.Collections.ObjectModel.ReadOnlyCollection SecurityKeys { get; } public abstract DateTime ValidFrom { get; } public abstract DateTime ValidTo { get; } - //public virtual bool CanCreateKeyIdentifierClause() where T : System.IdentityModel.Tokens.SecurityKeyIdentifierClause { return default(bool); } - //public virtual T CreateKeyIdentifierClause() where T : System.IdentityModel.Tokens.SecurityKeyIdentifierClause { return default(T); } - //public virtual bool MatchesKeyIdentifierClause(System.IdentityModel.Tokens.SecurityKeyIdentifierClause keyIdentifierClause) { return default(bool); } - //public virtual System.IdentityModel.Tokens.SecurityKey ResolveKeyIdentifierClause(System.IdentityModel.Tokens.SecurityKeyIdentifierClause keyIdentifierClause) { return default(System.IdentityModel.Tokens.SecurityKey); } } public abstract partial class SymmetricSecurityKey : SecurityKey { diff --git a/src/System.ServiceModel.Security/ref/System.ServiceModel.Security.cs b/src/System.ServiceModel.Security/ref/System.ServiceModel.Security.cs index 52db9badf42..df9d8da479d 100644 --- a/src/System.ServiceModel.Security/ref/System.ServiceModel.Security.cs +++ b/src/System.ServiceModel.Security/ref/System.ServiceModel.Security.cs @@ -118,17 +118,6 @@ protected SecurityAlgorithmSuite() { } public abstract string DefaultAsymmetricSignatureAlgorithm { get; } public abstract int DefaultSignatureKeyDerivationLength { get; } public abstract int DefaultSymmetricKeyLength { get; } - //public virtual bool IsCanonicalizationAlgorithmSupported(string algorithm) { return default; } - //public virtual bool IsDigestAlgorithmSupported(string algorithm) { return default; } - //public virtual bool IsEncryptionAlgorithmSupported(string algorithm) { return default; } - //public virtual bool IsEncryptionKeyDerivationAlgorithmSupported(string algorithm) { return default; } - //public virtual bool IsSymmetricKeyWrapAlgorithmSupported(string algorithm) { return default; } - //public virtual bool IsAsymmetricKeyWrapAlgorithmSupported(string algorithm) { return default; } - //public virtual bool IsSymmetricSignatureAlgorithmSupported(string algorithm) { return default; } - //public virtual bool IsAsymmetricSignatureAlgorithmSupported(string algorithm) { return default; } - //public virtual bool IsSignatureKeyDerivationAlgorithmSupported(string algorithm) { return default; } - //public abstract bool IsSymmetricKeyLengthSupported(int length); - //public abstract bool IsAsymmetricKeyLengthSupported(int length); } public abstract partial class SecurityPolicyVersion { @@ -171,28 +160,11 @@ public class IssuedSecurityTokenParameters : System.ServiceModel.Security.Tokens { protected IssuedSecurityTokenParameters(IssuedSecurityTokenParameters other) { } public IssuedSecurityTokenParameters() { } - //public IssuedSecurityTokenParameters(string tokenType) { } - //public IssuedSecurityTokenParameters(string tokenType, EndpointAddress issuerAddress) { } - //public IssuedSecurityTokenParameters(string tokenType, EndpointAddress issuerAddress, Channels.Binding issuerBinding) { } - //internal protected override bool HasAsymmetricKey { get { return default; } } - //public System.Collections.ObjectModel.Collection AdditionalRequestParameters { get { return default; } } public MessageSecurityVersion DefaultMessageSecurityVersion { get { return default; } set { } } public EndpointAddress IssuerAddress { get { return default; } set { } } - //public EndpointAddress IssuerMetadataAddress { get { return default; } set { } } public Channels.Binding IssuerBinding { get { return default; } set { } } public System.IdentityModel.Tokens.SecurityKeyType KeyType { get { return default; } set { } } - //public int KeySize { get { return default; } set { } } - //public bool UseStrTransform { get { return default; } set { } } - //public System.Collections.ObjectModel.Collection ClaimTypeRequirements { get { return default; } } public string TokenType { get { return default; } set { } } - //internal protected override bool SupportsClientAuthentication { get { return default; } } - //internal protected override bool SupportsServerAuthentication { get { return default; } } - //internal protected override bool SupportsClientWindowsIdentity { get { return default; } } - //protected override System.ServiceModel.Security.Tokens.SecurityTokenParameters CloneCore() { return default; } - //internal protected override System.IdentityModel.Tokens.SecurityKeyIdentifierClause CreateKeyIdentifierClause(System.IdentityModel.Tokens.SecurityToken token, SecurityTokenReferenceStyle referenceStyle) { return default; } - //public System.Collections.ObjectModel.Collection CreateRequestParameters(MessageSecurityVersion messageSecurityVersion, SecurityTokenSerializer securityTokenSerializer) { return default; } - //public override string ToString() { return default; } - //protected internal override void InitializeSecurityTokenRequirement(IdentityModel.Selectors.SecurityTokenRequirement requirement) { } } public partial class SecureConversationSecurityTokenParameters : System.ServiceModel.Security.Tokens.SecurityTokenParameters { @@ -210,42 +182,7 @@ internal SecurityTokenParameters() { } public abstract partial class ServiceModelSecurityTokenRequirement : System.IdentityModel.Selectors.SecurityTokenRequirement { protected ServiceModelSecurityTokenRequirement() { } - //static public string SecurityAlgorithmSuiteProperty { get { return default(string); } } - //static public string SecurityBindingElementProperty { get { return default(string); } } - //static public string IssuerAddressProperty { get { return default(string); } } - //static public string IssuerBindingProperty { get { return default(string); } } - //static public string SecureConversationSecurityBindingElementProperty { get { return default(string); } } - //static public string SupportSecurityContextCancellationProperty { get { return default(string); } } - //static public string MessageSecurityVersionProperty { get { return default(string); } } - //static public string IssuerBindingContextProperty { get { return default(string); } } - //static public string TransportSchemeProperty { get { return default(string); } } - //static public string IsInitiatorProperty { get { return default(string); } } - //static public string TargetAddressProperty { get { return default(string); } } - //static public string ViaProperty { get { return default(string); } } - //static public string ListenUriProperty { get { return default(string); } } - //static public string AuditLogLocationProperty { get { return default(string); } } - //static public string SuppressAuditFailureProperty { get { return default(string); } } - //static public string MessageAuthenticationAuditLevelProperty { get { return default(string); } } - //static public string IsOutOfBandTokenProperty { get { return default(string); } } - //static public string PreferSslCertificateAuthenticatorProperty { get { return default(string); } } - //static public string SupportingTokenAttachmentModeProperty { get { return default(string); } } - //static public string MessageDirectionProperty { get { return default(string); } } - //static public string HttpAuthenticationSchemeProperty { get { return default(string); } } - //static public string IssuedSecurityTokenParametersProperty { get { return default(string); } } - //static public string PrivacyNoticeUriProperty { get { return default(string); } } - //static public string PrivacyNoticeVersionProperty { get { return default(string); } } - //static public string DuplexClientLocalAddressProperty { get { return default(string); } } - //static public string EndpointFilterTableProperty { get { return default(string); } } static public string ChannelParametersCollectionProperty { get { return default; } } - //static public string ExtendedProtectionPolicy { get { return default(string); } } - //public bool IsInitiator { get { return default(bool); } } - //public System.ServiceModel.Security.SecurityAlgorithmSuite SecurityAlgorithmSuite { get { return default(System.ServiceModel.Security.SecurityAlgorithmSuite); } set { } } - //public System.ServiceModel.Channels.SecurityBindingElement SecurityBindingElement { get { return default(System.ServiceModel.Channels.SecurityBindingElement); } set { } } - //public System.ServiceModel.EndpointAddress IssuerAddress { get { return default(System.ServiceModel.EndpointAddress); } set { } } - //public System.ServiceModel.Channels.Binding IssuerBinding { get { return default(System.ServiceModel.Channels.Binding); } set { } } - //public System.ServiceModel.Channels.SecurityBindingElement SecureConversationSecurityBindingElement { get { return default(System.ServiceModel.Channels.SecurityBindingElement); } set { } } - //public System.IdentityModel.Selectors.SecurityTokenVersion MessageSecurityVersion { get { return default(System.IdentityModel.Selectors.SecurityTokenVersion); } set { } } - //public string TransportScheme { get { return default(string); } set { } } } public partial class SupportingTokenParameters { @@ -279,15 +216,6 @@ public GenericXmlSecurityToken(System.Xml.XmlElement tokenXml, public override DateTime ValidFrom { get; } public override DateTime ValidTo { get; } public override System.Collections.ObjectModel.ReadOnlyCollection SecurityKeys { get; } - // public SecurityKeyIdentifierClause InternalTokenReference { get; } - // public SecurityKeyIdentifierClause ExternalTokenReference { get; } - // public XmlElement TokenXml { get; } - // public SecurityToken ProofToken { get; } - // public ReadOnlyCollection AuthorizationPolicies { get; } - // public override string ToString() {} - // public override bool CanCreateKeyIdentifierClause() {} - // public override T CreateKeyIdentifierClause() {} - // public override bool MatchesKeyIdentifierClause(.SecurityKeyIdentifierClause keyIdentifierClause) {} } public enum SecurityKeyType { From 0ed7c73d77af9d6678ef71db7b0073319d0890df Mon Sep 17 00:00:00 2001 From: Matt Connew Date: Fri, 1 Nov 2019 13:59:46 -0700 Subject: [PATCH 3/7] Added EditorBrowsable attribute to unsupported methods to hide from intellisense --- .../ref/System.ServiceModel.Duplex.cs | 5 +++++ .../ref/System.ServiceModel.Http.cs | 1 + .../ref/System.ServiceModel.NetTcp.cs | 1 + .../ref/System.ServiceModel.Primitives.cs | 10 ++++++++++ .../ref/System.ServiceModel.Security.cs | 12 ++++++------ 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/System.ServiceModel.Duplex/ref/System.ServiceModel.Duplex.cs b/src/System.ServiceModel.Duplex/ref/System.ServiceModel.Duplex.cs index 86479316f96..9744b25fc27 100644 --- a/src/System.ServiceModel.Duplex/ref/System.ServiceModel.Duplex.cs +++ b/src/System.ServiceModel.Duplex/ref/System.ServiceModel.Duplex.cs @@ -23,7 +23,9 @@ public partial class DuplexChannelFactory : System.ServiceModel.Channe public DuplexChannelFactory(System.ServiceModel.InstanceContext callbackInstance, System.ServiceModel.Channels.Binding binding) : base(default(System.Type)) { } public DuplexChannelFactory(System.ServiceModel.InstanceContext callbackInstance, System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(default(System.Type)) { } public DuplexChannelFactory(System.ServiceModel.InstanceContext callbackInstance, System.ServiceModel.Channels.Binding binding, string remoteAddress) : base(default(System.Type)) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public DuplexChannelFactory(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName) : base(default(System.Type)) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public DuplexChannelFactory(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(default(System.Type)) { } public override TChannel CreateChannel(System.ServiceModel.EndpointAddress address, System.Uri via) { return default(TChannel); } public TChannel CreateChannel(System.ServiceModel.InstanceContext callbackInstance) { return default(TChannel); } @@ -34,8 +36,11 @@ public abstract partial class DuplexClientBase : System.ServiceModel.C { protected DuplexClientBase(System.ServiceModel.InstanceContext callbackInstance) { } protected DuplexClientBase(System.ServiceModel.InstanceContext callbackInstance, System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] protected DuplexClientBase(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] protected DuplexClientBase(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] protected DuplexClientBase(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress) { } } public sealed partial class InstanceContext : System.ServiceModel.Channels.CommunicationObject, System.ServiceModel.IExtensibleObject diff --git a/src/System.ServiceModel.Http/ref/System.ServiceModel.Http.cs b/src/System.ServiceModel.Http/ref/System.ServiceModel.Http.cs index 5ef04ebeb19..c26b3427697 100644 --- a/src/System.ServiceModel.Http/ref/System.ServiceModel.Http.cs +++ b/src/System.ServiceModel.Http/ref/System.ServiceModel.Http.cs @@ -114,6 +114,7 @@ public partial class NetHttpBinding : System.ServiceModel.HttpBindingBase { public NetHttpBinding() { } public NetHttpBinding(System.ServiceModel.BasicHttpSecurityMode securityMode) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public NetHttpBinding(string configurationName) { } [System.ComponentModel.DefaultValueAttribute((System.ServiceModel.NetHttpMessageEncoding)(0))] public System.ServiceModel.NetHttpMessageEncoding MessageEncoding { get { return default(System.ServiceModel.NetHttpMessageEncoding); } set { } } diff --git a/src/System.ServiceModel.NetTcp/ref/System.ServiceModel.NetTcp.cs b/src/System.ServiceModel.NetTcp/ref/System.ServiceModel.NetTcp.cs index 84979ca01bf..e380dea8d6c 100644 --- a/src/System.ServiceModel.NetTcp/ref/System.ServiceModel.NetTcp.cs +++ b/src/System.ServiceModel.NetTcp/ref/System.ServiceModel.NetTcp.cs @@ -17,6 +17,7 @@ public partial class NetTcpBinding : System.ServiceModel.Channels.Binding { public NetTcpBinding() { } public NetTcpBinding(System.ServiceModel.SecurityMode securityMode) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public NetTcpBinding(string configurationName) { } public System.ServiceModel.EnvelopeVersion EnvelopeVersion { get { return default(System.ServiceModel.EnvelopeVersion); } } [System.ComponentModel.DefaultValueAttribute((long)524288)] diff --git a/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs b/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs index c4e53d5ed3a..e47b2cb6af5 100644 --- a/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs +++ b/src/System.ServiceModel.Primitives/ref/System.ServiceModel.Primitives.cs @@ -205,6 +205,7 @@ protected ChannelFactory() { } protected override System.TimeSpan DefaultCloseTimeout { get { return default; } } protected override System.TimeSpan DefaultOpenTimeout { get { return default; } } public System.ServiceModel.Description.ServiceEndpoint Endpoint { get { return default; } } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] protected virtual void ApplyConfiguration(string configurationName) { } protected abstract System.ServiceModel.Description.ServiceEndpoint CreateDescription(); protected virtual System.ServiceModel.Channels.IChannelFactory CreateFactory() { return default; } @@ -212,6 +213,7 @@ protected internal void EnsureOpened() { } public T GetProperty() where T : class { return default; } protected void InitializeEndpoint(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress address) { } protected void InitializeEndpoint(System.ServiceModel.Description.ServiceEndpoint endpoint) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] protected void InitializeEndpoint(string configurationName, System.ServiceModel.EndpointAddress address) { } protected override void OnAbort() { } protected override System.IAsyncResult OnBeginClose(System.TimeSpan timeout, System.AsyncCallback callback, object state) { return default; } @@ -228,7 +230,9 @@ public partial class ChannelFactory : System.ServiceModel.ChannelFacto { public ChannelFactory(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) { } public ChannelFactory(System.ServiceModel.Description.ServiceEndpoint endpoint) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public ChannelFactory(string endpointConfigurationName) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public ChannelFactory(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) { } protected ChannelFactory(System.Type channelType) { } public TChannel CreateChannel() { return default; } @@ -248,8 +252,11 @@ public abstract partial class ClientBase : System.IDisposable, System. protected ClientBase() { } protected ClientBase(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) { } protected ClientBase(System.ServiceModel.Description.ServiceEndpoint endpoint) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] protected ClientBase(string endpointConfigurationName) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] protected ClientBase(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] protected ClientBase(string endpointConfigurationName, string remoteAddress) { } protected TChannel Channel { get { return default; } } public System.ServiceModel.ChannelFactory ChannelFactory { get { return default; } } @@ -320,8 +327,11 @@ void System.ServiceModel.Channels.IOutputChannel.Send(System.ServiceModel.Channe System.ServiceModel.Channels.Message System.ServiceModel.Channels.IRequestChannel.EndRequest(System.IAsyncResult result) { return default; } System.ServiceModel.Channels.Message System.ServiceModel.Channels.IRequestChannel.Request(System.ServiceModel.Channels.Message message) { return default; } System.ServiceModel.Channels.Message System.ServiceModel.Channels.IRequestChannel.Request(System.ServiceModel.Channels.Message message, System.TimeSpan timeout) { return default; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] System.IAsyncResult System.ServiceModel.IClientChannel.BeginDisplayInitializationUI(System.AsyncCallback callback, object state) { return default; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] void System.ServiceModel.IClientChannel.DisplayInitializationUI() { } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] void System.ServiceModel.IClientChannel.EndDisplayInitializationUI(System.IAsyncResult result) { } void System.ServiceModel.ICommunicationObject.Abort() { } System.IAsyncResult System.ServiceModel.ICommunicationObject.BeginClose(System.AsyncCallback callback, object state) { return default; } diff --git a/src/System.ServiceModel.Security/ref/System.ServiceModel.Security.cs b/src/System.ServiceModel.Security/ref/System.ServiceModel.Security.cs index df9d8da479d..f8c803677c8 100644 --- a/src/System.ServiceModel.Security/ref/System.ServiceModel.Security.cs +++ b/src/System.ServiceModel.Security/ref/System.ServiceModel.Security.cs @@ -205,12 +205,12 @@ namespace System.IdentityModel.Tokens { public partial class GenericXmlSecurityToken : System.IdentityModel.Tokens.SecurityToken { - public GenericXmlSecurityToken(System.Xml.XmlElement tokenXml, - System.IdentityModel.Tokens.SecurityToken proofToken, - DateTime effectiveTime, - DateTime expirationTime, - SecurityKeyIdentifierClause internalTokenReference, - SecurityKeyIdentifierClause externalTokenReference, + public GenericXmlSecurityToken(System.Xml.XmlElement tokenXml, + System.IdentityModel.Tokens.SecurityToken proofToken, + DateTime effectiveTime, + DateTime expirationTime, + SecurityKeyIdentifierClause internalTokenReference, + SecurityKeyIdentifierClause externalTokenReference, System.Collections.ObjectModel.ReadOnlyCollection authorizationPolicies) {} public override string Id { get; } public override DateTime ValidFrom { get; } From e865c429c9e3cd544b69bf612b297b63e2676d5a Mon Sep 17 00:00:00 2001 From: Stephen Bonikowsky Date: Tue, 29 Oct 2019 16:05:46 -0700 Subject: [PATCH 4/7] Add "encodingStyle" attribute to generated SOAP message. * This fix was initially produced by @maheshnlrb with PR #3891 but the commit history got sufficiently scrambled that is was easier to reproduce his changes in a clean up-to-date branch. --- .../XmlSerializerOperationFormatter.cs | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/XmlSerializerOperationFormatter.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/XmlSerializerOperationFormatter.cs index 8b151b9f0a2..334921f2a25 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/XmlSerializerOperationFormatter.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/XmlSerializerOperationFormatter.cs @@ -20,6 +20,7 @@ internal class XmlSerializerOperationFormatter : OperationFormatter private const string soap11Encoding = "http://schemas.xmlsoap.org/soap/encoding/"; private const string soap12Encoding = "http://www.w3.org/2003/05/soap-encoding"; + private bool _isEncoded; private MessageInfo _requestMessageInfo; private MessageInfo _replyMessageInfo; @@ -27,6 +28,12 @@ public XmlSerializerOperationFormatter(OperationDescription description, XmlSeri MessageInfo requestMessageInfo, MessageInfo replyMessageInfo) : base(description, xmlSerializerFormatAttribute.Style == OperationFormatStyle.Rpc, xmlSerializerFormatAttribute.IsEncoded) { + if (xmlSerializerFormatAttribute.IsEncoded && xmlSerializerFormatAttribute.Style != OperationFormatStyle.Rpc) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.SFxDocEncodedNotSupported, description.Name))); + } + + _isEncoded = xmlSerializerFormatAttribute.IsEncoded; _requestMessageInfo = requestMessageInfo; _replyMessageInfo = replyMessageInfo; } @@ -83,13 +90,12 @@ protected override void AddHeadersToMessage(Message message, MessageDescription MemoryStream memoryStream = new MemoryStream(); XmlDictionaryWriter bufferWriter = XmlDictionaryWriter.CreateTextWriter(memoryStream); bufferWriter.WriteStartElement("root"); - serializer.Serialize(bufferWriter, headerValues, null); + serializer.Serialize(bufferWriter, headerValues, null, _isEncoded ? GetEncoding(message.Version.Envelope) : null); bufferWriter.WriteEndElement(); bufferWriter.Flush(); XmlDocument doc = new XmlDocument(); memoryStream.Position = 0; doc.Load(memoryStream); - //doc.Save(Console.Out); foreach (XmlElement element in doc.DocumentElement.ChildNodes) { MessageHeaderDescription matchingHeaderDescription = headerDescriptionTable.Get(element.LocalName, element.NamespaceURI); @@ -236,7 +242,7 @@ protected override void GetHeadersFromMessage(Message message, MessageDescriptio if (!bufferReader.IsEmptyElement) { bufferReader.ReadStartElement(); - object[] headerValues = (object[])serializer.Deserialize(bufferReader); + object[] headerValues = (object[])serializer.Deserialize(bufferReader, _isEncoded ? GetEncoding(message.Version.Envelope) : null); int headerIndex = 0; foreach (MessageHeaderDescription headerDescription in messageDescription.Headers) { @@ -285,6 +291,12 @@ private static void AddUnknownHeader(MessageHeaderDescription unknownHeaderDescr protected override void WriteBodyAttributes(XmlDictionaryWriter writer, MessageVersion version) { + if (_isEncoded && version.Envelope == EnvelopeVersion.Soap11) + { + string encoding = GetEncoding(version.Envelope); + writer.WriteAttributeString("encodingStyle", version.Envelope.Namespace, encoding); + } + writer.WriteAttributeString("xmlns", "xsi", null, XmlUtil.XmlSerializerSchemaInstanceNamespace); writer.WriteAttributeString("xmlns", "xsd", null, XmlUtil.XmlSerializerSchemaNamespace); } @@ -374,6 +386,7 @@ private void SerializeBody(XmlDictionaryWriter writer, MessageVersion version, X bodyParameters[paramIndex++] = parameters[bodyParts[i].Index]; } + string encoding = _isEncoded ? GetEncoding(version.Envelope) : null; serializer.Serialize(writer, bodyParameters, null); } @@ -444,7 +457,7 @@ private object DeserializeBody(XmlDictionaryReader reader, MessageVersion versio return null; } - object[] bodyParameters = (object[])serializer.Deserialize(reader); + object[] bodyParameters = (object[])serializer.Deserialize(reader, _isEncoded ? GetEncoding(version.Envelope) : null); int paramIndex = 0; if (IsValidReturnValue(returnPart)) { @@ -568,7 +581,9 @@ internal void SetHeaderAttributes(MessageHeaderDescription headerDescription, bo if (_attributes[headerDescription.Index] == null) { _attributes[headerDescription.Index] = new List>(); - } ((List>)_attributes[headerDescription.Index]).Add(new MessageHeader(null, mustUnderstand, actor, relay)); + } + + ((List>)_attributes[headerDescription.Index]).Add(new MessageHeader(null, mustUnderstand, actor, relay)); } else { From 51aac76369a2c3d31577387f68ebb732462f13dc Mon Sep 17 00:00:00 2001 From: Stephen Bonikowsky Date: Wed, 30 Oct 2019 09:14:55 -0700 Subject: [PATCH 5/7] Merge pull request #3994 from StephenBonikowsky/stebon/portsocketconnectionfix Port FullFx fix for SocketConnection sync/async timeout ignore problem. --- .../ServiceModel/Channels/SocketConnection.cs | 823 ++++++++++-------- 1 file changed, 448 insertions(+), 375 deletions(-) diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SocketConnection.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SocketConnection.cs index 35cb1e0dff8..5852f976f16 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SocketConnection.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/SocketConnection.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. - +using System.Diagnostics; using System.Diagnostics.Contracts; using System.Net; using System.Net.Sockets; @@ -14,26 +14,36 @@ namespace System.ServiceModel.Channels { internal class SocketConnection : IConnection { - private static EventHandler s_onReceiveAsyncCompleted; - private static EventHandler s_onSocketSendCompleted; + static AsyncCallback s_onReceiveCompleted; + static EventHandler s_onReceiveAsyncCompleted; + static EventHandler s_onSocketSendCompleted; // common state private Socket _socket; - private bool _noDelay = false; - private TimeSpan _sendTimeout; - private TimeSpan _receiveTimeout; + private TimeSpan _asyncSendTimeout; + private TimeSpan _readFinTimeout; + private TimeSpan _asyncReceiveTimeout; + + // Socket.SendTimeout/Socket.ReceiveTimeout only work with the synchronous API calls and therefore they + // do not get updated when asynchronous Send/Read operations are performed. In order to make sure we + // Set the proper timeouts on the Socket itself we need to keep these two additional fields. + private TimeSpan _socketSyncSendTimeout; + private TimeSpan _socketSyncReceiveTimeout; + private CloseState _closeState; + private bool _isShutdown; + private bool _noDelay = false; private bool _aborted; // close state - private static Action s_onWaitForFinComplete = new Action(OnWaitForFinComplete); private TimeoutHelper _closeTimeoutHelper; - private bool _isShutdown; + private static Action s_onWaitForFinComplete = new Action(OnWaitForFinComplete); // read state - private SocketAsyncEventArgs _asyncReadEventArgs; - private TimeSpan _readFinTimeout; private int _asyncReadSize; + private SocketAsyncEventArgs _asyncReadEventArgs; + private byte[] _readBuffer; + private int _asyncReadBufferSize; private object _asyncReadState; private Action _asyncReadCallback; private Exception _asyncReadException; @@ -46,37 +56,100 @@ internal class SocketConnection : IConnection private Exception _asyncWriteException; private bool _asyncWritePending; - private static Action s_onSendTimeout; - private static Action s_onReceiveTimeout; private IOTimer _receiveTimer; + private static Action s_onReceiveTimeout; private IOTimer _sendTimer; + private static Action s_onSendTimeout; private string _timeoutErrorString; private TransferOperation _timeoutErrorTransferOperation; + private IPEndPoint _remoteEndpoint; private ConnectionBufferPool _connectionBufferPool; - private string _remoteEndpointAddressString; + private string _remoteEndpointAddress; - public SocketConnection(Socket socket, ConnectionBufferPool connectionBufferPool) + public SocketConnection(Socket socket, ConnectionBufferPool connectionBufferPool, bool autoBindToCompletionPort) { _connectionBufferPool = connectionBufferPool ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(connectionBufferPool)); _socket = socket ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(socket)); _closeState = CloseState.Open; - AsyncReadBuffer = _connectionBufferPool.Take(); - AsyncReadBufferSize = AsyncReadBuffer.Length; - _sendTimeout = _receiveTimeout = TimeSpan.MaxValue; - _closeState = CloseState.Open; - _socket.SendBufferSize = _socket.ReceiveBufferSize = AsyncReadBufferSize; - _sendTimeout = _receiveTimeout = TimeSpan.MaxValue; - } + _readBuffer = connectionBufferPool.Take(); + _asyncReadBufferSize = _readBuffer.Length; + _socket.SendBufferSize = _socket.ReceiveBufferSize = _asyncReadBufferSize; + _asyncSendTimeout = _asyncReceiveTimeout = TimeSpan.MaxValue; + _socketSyncSendTimeout = _socketSyncReceiveTimeout = TimeSpan.MaxValue; - public int AsyncReadBufferSize { get; } + _remoteEndpoint = null; - public byte[] AsyncReadBuffer { get; private set; } + if (autoBindToCompletionPort) + { + _socket.UseOnlyOverlappedIO = false; + } + + // In SMSvcHost, sockets must be duplicated to the target process. Binding a handle to a completion port + // prevents any duplicated handle from ever binding to a completion port. The target process is where we + // want to use completion ports for performance. This means that in SMSvcHost, socket.UseOnlyOverlappedIO + // must be set to true to prevent completion port use. + if (_socket.UseOnlyOverlappedIO) + { + // Init BeginRead state + if (s_onReceiveCompleted == null) + { + s_onReceiveCompleted = Fx.ThunkCallback(new AsyncCallback(OnReceiveCompleted)); + } + } + } + public int AsyncReadBufferSize + { + get { return _asyncReadBufferSize; } + } + + public byte[] AsyncReadBuffer + { + get + { + return _readBuffer; + } + } private object ThisLock { get { return this; } } + public IPEndPoint RemoteIPEndPoint + { + get + { + // this property should only be called on the receive path + if (_remoteEndpoint == null && _closeState == CloseState.Open) + { + try + { + _remoteEndpoint = (IPEndPoint)_socket.RemoteEndPoint; + } + catch (SocketException socketException) + { + // will never be a timeout error, so TimeSpan.Zero is ok + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + ConvertReceiveException(socketException, TimeSpan.Zero, TimeSpan.Zero)); + } + catch (ObjectDisposedException objectDisposedException) + { + Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Undefined); + if (ReferenceEquals(exceptionToThrow, objectDisposedException)) + { + throw; + } + else + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exceptionToThrow); + } + } + } + + return _remoteEndpoint; + } + } + private IOTimer SendTimer { get @@ -85,7 +158,7 @@ private IOTimer SendTimer { if (s_onSendTimeout == null) { - s_onSendTimeout = OnSendTimeout; + s_onSendTimeout = new Action(OnSendTimeout); } _sendTimer = new IOTimer(s_onSendTimeout, this); @@ -103,7 +176,7 @@ private IOTimer ReceiveTimer { if (s_onReceiveTimeout == null) { - s_onReceiveTimeout = OnReceiveTimeout; + s_onReceiveTimeout = new Action(OnReceiveTimeout); } _receiveTimer = new IOTimer(s_onReceiveTimeout, this); @@ -113,116 +186,64 @@ private IOTimer ReceiveTimer } } - private IPEndPoint RemoteEndPoint - { - get - { - if (!_socket.Connected) - { - return null; - } - return (IPEndPoint)_socket.RemoteEndPoint; - } - } - - private string RemoteEndpointAddressString + private string RemoteEndpointAddress { get { - if (_remoteEndpointAddressString == null) + if (_remoteEndpointAddress == null) { - IPEndPoint remote = RemoteEndPoint; - if (remote == null) + try { - return string.Empty; + if (TryGetEndpoints(out IPEndPoint local, out IPEndPoint remote)) + { + _remoteEndpointAddress = remote.Address + ":" + remote.Port; + } + else + { + //null indicates not initialized. + _remoteEndpointAddress = string.Empty; + } } - _remoteEndpointAddressString = remote.Address + ":" + remote.Port; - } + catch (Exception exception) + { + if (Fx.IsFatal(exception)) + { + throw; + } - return _remoteEndpointAddressString; + } + } + return _remoteEndpointAddress; } } - private static void OnReceiveAsyncCompleted(object sender, SocketAsyncEventArgs e) + private static void OnReceiveTimeout(object state) { - ((SocketConnection)e.UserToken).OnReceiveAsync(sender, e); + SocketConnection thisPtr = (SocketConnection)state; + thisPtr.Abort(SR.Format(SR.SocketAbortedReceiveTimedOut, thisPtr._asyncReceiveTimeout), TransferOperation.Read); } - private static void OnSendAsyncCompleted(object sender, SocketAsyncEventArgs e) + private static void OnSendTimeout(object state) { - ((SocketConnection)e.UserToken).OnSendAsync(sender, e); + SocketConnection thisPtr = (SocketConnection)state; + thisPtr.Abort(4, // TraceEventType.Warning + SR.Format(SR.SocketAbortedSendTimedOut, thisPtr._asyncSendTimeout), TransferOperation.Write); } - private static void OnWaitForFinComplete(object state) + private static void OnReceiveCompleted(IAsyncResult result) { - // Callback for read on a socket which has had Shutdown called on it. When - // the response FIN packet is received from the remote host, the pending - // read will complete with 0 bytes read. If more than 0 bytes has been read, - // then something has gone wrong as we should have no pending data to be received. - SocketConnection thisPtr = (SocketConnection)state; - - try - { - int bytesRead; - - try - { - bytesRead = thisPtr.EndRead(); - - if (bytesRead > 0) - { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( - new CommunicationException(SR.Format(SR.SocketCloseReadReceivedData, thisPtr.RemoteEndPoint))); - } - } - catch (TimeoutException timeoutException) - { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException( - SR.Format(SR.SocketCloseReadTimeout, thisPtr.RemoteEndPoint, thisPtr._readFinTimeout), - timeoutException)); - } - - thisPtr.ContinueClose(thisPtr._closeTimeoutHelper.RemainingTime()); - } - catch (Exception e) - { - if (Fx.IsFatal(e)) - { - throw; - } - - Fx.Exception.TraceUnhandledException(e); - - // The user has no opportunity to clean up the connection in the async and linger - // code path, ensure cleanup finishes. - thisPtr.Abort(); - } + ((SocketConnection)result.AsyncState).OnReceive(result); } - private static void OnReceiveTimeout(SocketConnection socketConnection) + private static void OnReceiveAsyncCompleted(object sender, SocketAsyncEventArgs e) { - try - { - socketConnection.Abort(SR.Format(SR.SocketAbortedReceiveTimedOut, socketConnection._receiveTimeout), TransferOperation.Read); - } - catch (SocketException) - { - // Guard against unhandled SocketException in timer callbacks - } + ((SocketConnection)e.UserToken).OnReceiveAsync(sender, e); } - private static void OnSendTimeout(SocketConnection socketConnection) + private static void OnSendAsyncCompleted(object sender, SocketAsyncEventArgs e) { - try - { - socketConnection.Abort(4, // TraceEventType.Warning - SR.Format(SR.SocketAbortedSendTimedOut, socketConnection._sendTimeout), TransferOperation.Write); - } - catch (SocketException) - { - // Guard against unhandled SocketException in timer callbacks - } + ((SocketConnection)e.UserToken).OnSendAsync(sender, e); } public void Abort() @@ -258,23 +279,26 @@ private void Abort(int traceEventType, string timeoutErrorString, TransferOperat _aborted = true; _closeState = CloseState.Closed; - if (!_asyncReadPending) + if (_asyncReadPending) + { + CancelReceiveTimer(); + } + else { DisposeReadEventArgs(); } - if (!_asyncWritePending) + if (_asyncWritePending) + { + CancelSendTimer(); + } + else { DisposeWriteEventArgs(); } - - DisposeReceiveTimer(); - DisposeSendTimer(); } - _socket.LingerState = new LingerOption(true, 0); - _socket.Shutdown(SocketShutdown.Both); - _socket.Dispose(); + _socket.Close(0); } private void AbortRead() @@ -326,23 +350,61 @@ private void CloseAsyncAndLinger() int bytesRead = EndRead(); - // Any NetTcp session handshake will have been completed at this point so if any data is returned, something - // very wrong has happened. if (bytesRead > 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( - new CommunicationException(SR.Format(SR.SocketCloseReadReceivedData, RemoteEndPoint))); + new CommunicationException(SR.Format(SR.SocketCloseReadReceivedData, _socket.RemoteEndPoint))); } } catch (TimeoutException timeoutException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException( - SR.Format(SR.SocketCloseReadTimeout, RemoteEndPoint, _readFinTimeout), timeoutException)); + SR.Format(SR.SocketCloseReadTimeout, _socket.RemoteEndPoint, _readFinTimeout), timeoutException)); } ContinueClose(_closeTimeoutHelper.RemainingTime()); } + private static void OnWaitForFinComplete(object state) + { + SocketConnection thisPtr = (SocketConnection)state; + + try + { + int bytesRead; + + try + { + bytesRead = thisPtr.EndRead(); + + if (bytesRead > 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new CommunicationException(SR.Format(SR.SocketCloseReadReceivedData, thisPtr._socket.RemoteEndPoint))); + } + } + catch (TimeoutException timeoutException) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException( + SR.Format(SR.SocketCloseReadTimeout, thisPtr._socket.RemoteEndPoint, thisPtr._readFinTimeout), + timeoutException)); + } + + thisPtr.ContinueClose(thisPtr._closeTimeoutHelper.RemainingTime()); + } + catch (Exception e) + { + if (Fx.IsFatal(e)) + { + throw; + } + + // The user has no opportunity to clean up the connection in the async and linger + // code path, ensure cleanup finishes. + thisPtr.Abort(); + } + } + public void Close(TimeSpan timeout, bool asyncAndLinger) { lock (ThisLock) @@ -355,15 +417,10 @@ public void Close(TimeSpan timeout, bool asyncAndLinger) _closeState = CloseState.Closing; } - _closeTimeoutHelper = new TimeoutHelper(timeout); - // first we shutdown our send-side - Shutdown(timeout); - CloseCore(asyncAndLinger); - } + _closeTimeoutHelper = new TimeoutHelper(timeout); + Shutdown(_closeTimeoutHelper.RemainingTime()); - private void CloseCore(bool asyncAndLinger) - { if (asyncAndLinger) { CloseAsyncAndLinger(); @@ -378,10 +435,7 @@ private void CloseSync() { byte[] dummy = new byte[1]; - // A FIN (shutdown) packet has already been sent to the remote host and we're waiting for the remote - // host to send a FIN back. A pending read on a socket will complete returning zero bytes when a FIN - // packet is received. - + // then we check for a FIN from the other side (i.e. read zero) int bytesRead; _readFinTimeout = _closeTimeoutHelper.RemainingTime(); @@ -389,32 +443,25 @@ private void CloseSync() { bytesRead = ReadCore(dummy, 0, 1, _readFinTimeout, true); - // Any NetTcp session handshake will have been completed at this point so if any data is returned, something - // very wrong has happened. if (bytesRead > 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( - new CommunicationException(SR.Format(SR.SocketCloseReadReceivedData, RemoteEndPoint))); + new CommunicationException(SR.Format(SR.SocketCloseReadReceivedData, _socket.RemoteEndPoint))); } } catch (TimeoutException timeoutException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException( - SR.Format(SR.SocketCloseReadTimeout, RemoteEndPoint, _readFinTimeout), timeoutException)); + SR.Format(SR.SocketCloseReadTimeout, _socket.RemoteEndPoint, _readFinTimeout), timeoutException)); } // finally we call Close with whatever time is remaining ContinueClose(_closeTimeoutHelper.RemainingTime()); } - private void ContinueClose(TimeSpan timeout) + public void ContinueClose(TimeSpan timeout) { - // Use linger to attempt a graceful socket shutdown. Allowing a clean shutdown handshake - // will allow the service side to close it's socket gracefully too. A hard shutdown would - // cause the server to receive an exception which affects performance and scalability. - _socket.LingerState = new LingerOption(true, (int)timeout.TotalSeconds); - _socket.Shutdown(SocketShutdown.Both); - _socket.Dispose(); + _socket.Close(TimeoutHelper.ToMilliseconds(timeout)); lock (ThisLock) { @@ -434,12 +481,10 @@ private void ContinueClose(TimeSpan timeout) } _closeState = CloseState.Closed; - DisposeReceiveTimer(); - DisposeSendTimer(); } } - private void Shutdown(TimeSpan timeout) + public void Shutdown(TimeSpan timeout) { lock (ThisLock) { @@ -451,12 +496,6 @@ private void Shutdown(TimeSpan timeout) _isShutdown = true; } - ShutdownCore(timeout); - } - - private void ShutdownCore(TimeSpan timeout) - { - // Attempt to close the socket gracefully by sending a shutdown (FIN) packet try { _socket.Shutdown(SocketShutdown.Send); @@ -464,7 +503,7 @@ private void ShutdownCore(TimeSpan timeout) catch (SocketException socketException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( - ConvertSendException(socketException, TimeSpan.MaxValue)); + ConvertSendException(socketException, TimeSpan.MaxValue, _socketSyncSendTimeout)); } catch (ObjectDisposedException objectDisposedException) { @@ -500,29 +539,69 @@ private void ThrowIfClosed() } } - private Exception ConvertSendException(SocketException socketException, TimeSpan remainingTime) + private bool TryGetEndpoints(out IPEndPoint localIPEndpoint, out IPEndPoint remoteIPEndpoint) + { + localIPEndpoint = null; + remoteIPEndpoint = null; + + if (_closeState == CloseState.Open) + { + try + { + remoteIPEndpoint = _remoteEndpoint ?? (IPEndPoint)_socket.RemoteEndPoint; + localIPEndpoint = (IPEndPoint)_socket.LocalEndPoint; + } + catch (Exception exception) + { + if (Fx.IsFatal(exception)) + { + throw; + } + + } + } + + return localIPEndpoint != null && remoteIPEndpoint != null; + } + + public object GetCoreTransport() + { + return _socket; + } + + public IAsyncResult BeginValidate(Uri uri, AsyncCallback callback, object state) + { + return new CompletedAsyncResult(true, callback, state); + } + + public bool EndValidate(IAsyncResult result) + { + return CompletedAsyncResult.End(result); + } + + private Exception ConvertSendException(SocketException socketException, TimeSpan remainingTime, TimeSpan timeout) { - return ConvertTransferException(socketException, _sendTimeout, socketException, - _aborted, _timeoutErrorString, _timeoutErrorTransferOperation, this, remainingTime); + return ConvertTransferException(socketException, timeout, socketException, + TransferOperation.Write, _aborted, _timeoutErrorString, _timeoutErrorTransferOperation, this, remainingTime); } - private Exception ConvertReceiveException(SocketException socketException, TimeSpan remainingTime) + private Exception ConvertReceiveException(SocketException socketException, TimeSpan remainingTime, TimeSpan timeout) { - return ConvertTransferException(socketException, _receiveTimeout, socketException, - _aborted, _timeoutErrorString, _timeoutErrorTransferOperation, this, remainingTime); + return ConvertTransferException(socketException, timeout, socketException, + TransferOperation.Read, _aborted, _timeoutErrorString, _timeoutErrorTransferOperation, this, remainingTime); } internal static Exception ConvertTransferException(SocketException socketException, TimeSpan timeout, Exception originalException) { return ConvertTransferException(socketException, timeout, originalException, - false, null, TransferOperation.Undefined, null, TimeSpan.MaxValue); + TransferOperation.Undefined, false, null, TransferOperation.Undefined, null, TimeSpan.MaxValue); } private Exception ConvertObjectDisposedException(ObjectDisposedException originalException, TransferOperation transferOperation) { if (_timeoutErrorString != null) { - return ConvertTimeoutErrorException(originalException, _timeoutErrorString, _timeoutErrorTransferOperation); + return ConvertTimeoutErrorException(originalException, transferOperation, _timeoutErrorString, _timeoutErrorTransferOperation); } else if (_aborted) { @@ -535,30 +614,30 @@ private Exception ConvertObjectDisposedException(ObjectDisposedException origina } private static Exception ConvertTransferException(SocketException socketException, TimeSpan timeout, Exception originalException, - bool aborted, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation, + TransferOperation transferOperation, bool aborted, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation, SocketConnection socketConnection, TimeSpan remainingTime) { - if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE) + if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE) { return new CommunicationObjectAbortedException(socketException.Message, socketException); } if (timeoutErrorString != null) { - return ConvertTimeoutErrorException(originalException, timeoutErrorString, timeoutErrorTransferOperation); + return ConvertTimeoutErrorException(originalException, transferOperation, timeoutErrorString, timeoutErrorTransferOperation); } // 10053 can occur due to our timeout sockopt firing, so map to TimeoutException in that case - if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAECONNABORTED && + if (socketException.ErrorCode == UnsafeNativeMethods.WSAECONNABORTED && remainingTime <= TimeSpan.Zero) { TimeoutException timeoutException = new TimeoutException(SR.Format(SR.TcpConnectionTimedOut, timeout), originalException); return timeoutException; } - if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAENETRESET || - (int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAECONNABORTED || - (int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAECONNRESET) + if (socketException.ErrorCode == UnsafeNativeMethods.WSAENETRESET || + socketException.ErrorCode == UnsafeNativeMethods.WSAECONNABORTED || + socketException.ErrorCode == UnsafeNativeMethods.WSAECONNRESET) { if (aborted) { @@ -570,7 +649,7 @@ private static Exception ConvertTransferException(SocketException socketExceptio return communicationException; } } - else if ((int)socketException.SocketErrorCode == UnsafeNativeMethods.WSAETIMEDOUT) + else if (socketException.ErrorCode == UnsafeNativeMethods.WSAETIMEDOUT) { TimeoutException timeoutException = new TimeoutException(SR.Format(SR.TcpConnectionTimedOut, timeout), originalException); return timeoutException; @@ -579,21 +658,25 @@ private static Exception ConvertTransferException(SocketException socketExceptio { if (aborted) { - return new CommunicationObjectAbortedException(SR.Format(SR.TcpTransferError, (int)socketException.SocketErrorCode, socketException.Message), originalException); + return new CommunicationObjectAbortedException(SR.Format(SR.TcpTransferError, socketException.ErrorCode, socketException.Message), originalException); } else { - CommunicationException communicationException = new CommunicationException(SR.Format(SR.TcpTransferError, (int)socketException.SocketErrorCode, socketException.Message), originalException); + CommunicationException communicationException = new CommunicationException(SR.Format(SR.TcpTransferError, socketException.ErrorCode, socketException.Message), originalException); return communicationException; } } } - private static Exception ConvertTimeoutErrorException(Exception originalException, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation) + private static Exception ConvertTimeoutErrorException(Exception originalException, + TransferOperation transferOperation, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation) { - Contract.Assert(timeoutErrorString != null, "Argument timeoutErrorString must not be null."); + if (timeoutErrorString == null) + { + Fx.Assert("Argument timeoutErrorString must not be null."); + } - if (timeoutErrorTransferOperation != TransferOperation.Undefined) + if (transferOperation == timeoutErrorTransferOperation) { return new TimeoutException(timeoutErrorString, originalException); } @@ -605,38 +688,20 @@ private static Exception ConvertTimeoutErrorException(Exception originalExceptio public AsyncCompletionResult BeginWrite(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, Action callback, object state) - { - if (WcfEventSource.Instance.SocketAsyncWriteStartIsEnabled()) - { - TraceWriteStart(size, true); - } - - return BeginWriteCore(buffer, offset, size, immediate, timeout, callback, state); - } - - private void TraceWriteStart(int size, bool async) - { - if (!async) - { - WcfEventSource.Instance.SocketWriteStart(_socket.GetHashCode(), size, RemoteEndpointAddressString); - } - else - { - WcfEventSource.Instance.SocketAsyncWriteStart(_socket.GetHashCode(), size, RemoteEndpointAddressString); - } - } - - private AsyncCompletionResult BeginWriteCore(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, - Action callback, object state) { ConnectionUtilities.ValidateBufferBounds(buffer, offset, size); bool abortWrite = true; try { + if (WcfEventSource.Instance.SocketAsyncWriteStartIsEnabled()) + { + TraceWriteStart(size, true); + } + lock (ThisLock) { - Contract.Assert(!_asyncWritePending, "Called BeginWrite twice."); + Fx.Assert(!_asyncWritePending, "Called BeginWrite twice."); ThrowIfClosed(); EnsureWriteEventArgs(); SetImmediate(immediate); @@ -662,7 +727,7 @@ private AsyncCompletionResult BeginWriteCore(byte[] buffer, int offset, int size catch (SocketException socketException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( - ConvertSendException(socketException, TimeSpan.MaxValue)); + ConvertSendException(socketException, TimeSpan.MaxValue, _asyncSendTimeout)); } catch (ObjectDisposedException objectDisposedException) { @@ -686,11 +751,6 @@ private AsyncCompletionResult BeginWriteCore(byte[] buffer, int offset, int size } public void EndWrite() - { - EndWriteCore(); - } - - private void EndWriteCore() { if (_asyncWriteException != null) { @@ -702,8 +762,7 @@ private void EndWriteCore() { if (!_asyncWritePending) { - Contract.Assert(false, "SocketConnection.EndWrite called with no write pending."); - throw new Exception("SocketConnection.EndWrite called with no write pending."); + throw Fx.AssertAndThrow("SocketConnection.EndWrite called with no write pending."); } SetUserToken(_asyncWriteEventArgs, null); @@ -716,6 +775,73 @@ private void EndWriteCore() } } + private void OnSendAsync(object sender, SocketAsyncEventArgs eventArgs) + { + Fx.Assert(eventArgs != null, "Argument 'eventArgs' cannot be NULL."); + CancelSendTimer(); + + try + { + HandleSendAsyncCompleted(); + Fx.Assert(eventArgs.BytesTransferred == _asyncWriteEventArgs.Count, "The socket SendAsync did not send all the bytes."); + } + catch (SocketException socketException) + { + _asyncWriteException = ConvertSendException(socketException, TimeSpan.MaxValue, _asyncSendTimeout); + } + catch (Exception exception) + { + if (Fx.IsFatal(exception)) + { + throw; + } + + _asyncWriteException = exception; + } + + FinishWrite(); + } + + private void HandleSendAsyncCompleted() + { + if (_asyncWriteEventArgs.SocketError == SocketError.Success) + { + return; + } + + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException((int)_asyncWriteEventArgs.SocketError)); + } + + // This method should be called inside ThisLock + private void DisposeWriteEventArgs() + { + if (_asyncWriteEventArgs != null) + { + _asyncWriteEventArgs.Completed -= s_onSocketSendCompleted; + _asyncWriteEventArgs.Dispose(); + } + } + + private void AbortWrite() + { + lock (ThisLock) + { + if (_asyncWritePending) + { + if (_closeState != CloseState.Closed) + { + SetUserToken(_asyncWriteEventArgs, null); + _asyncWritePending = false; + CancelSendTimer(); + } + else + { + DisposeWriteEventArgs(); + } + } + } + } + private void FinishWrite() { Action asyncWriteCallback = _asyncWriteCallback; @@ -728,11 +854,6 @@ private void FinishWrite() } public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout) - { - WriteCore(buffer, offset, size, immediate, timeout); - } - - private void WriteCore(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout) { // as per http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b201213 // we shouldn't write more than 64K synchronously to a socket @@ -759,7 +880,7 @@ private void WriteCore(byte[] buffer, int offset, int size, bool immediate, Time catch (SocketException socketException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( - ConvertSendException(socketException, timeoutHelper.RemainingTime())); + ConvertSendException(socketException, timeoutHelper.RemainingTime(), _socketSyncSendTimeout)); } catch (ObjectDisposedException objectDisposedException) { @@ -775,6 +896,18 @@ private void WriteCore(byte[] buffer, int offset, int size, bool immediate, Time } } + private void TraceWriteStart(int size, bool async) + { + if (!async) + { + WcfEventSource.Instance.SocketWriteStart(_socket.GetHashCode(), size, RemoteEndpointAddress); + } + else + { + WcfEventSource.Instance.SocketAsyncWriteStart(_socket.GetHashCode(), size, RemoteEndpointAddress); + } + } + public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, BufferManager bufferManager) { try @@ -791,13 +924,7 @@ public int Read(byte[] buffer, int offset, int size, TimeSpan timeout) { ConnectionUtilities.ValidateBufferBounds(buffer, offset, size); ThrowIfNotOpen(); - int bytesRead = ReadCore(buffer, offset, size, timeout, false); - if (WcfEventSource.Instance.SocketReadStopIsEnabled()) - { - TraceSocketReadStop(bytesRead, false); - } - - return bytesRead; + return ReadCore(buffer, offset, size, timeout, false); } private int ReadCore(byte[] buffer, int offset, int size, TimeSpan timeout, bool closing) @@ -812,7 +939,7 @@ private int ReadCore(byte[] buffer, int offset, int size, TimeSpan timeout, bool catch (SocketException socketException) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( - ConvertReceiveException(socketException, timeoutHelper.RemainingTime())); + ConvertReceiveException(socketException, timeoutHelper.RemainingTime(), _socketSyncReceiveTimeout)); } catch (ObjectDisposedException objectDisposedException) { @@ -830,32 +957,26 @@ private int ReadCore(byte[] buffer, int offset, int size, TimeSpan timeout, bool return bytesRead; } - public virtual AsyncCompletionResult BeginRead(int offset, int size, TimeSpan timeout, - Action callback, object state) - { - ConnectionUtilities.ValidateBufferBounds(AsyncReadBufferSize, offset, size); - ThrowIfNotOpen(); - var completionResult = BeginReadCore(offset, size, timeout, callback, state); - if (completionResult == AsyncCompletionResult.Completed && WcfEventSource.Instance.SocketReadStopIsEnabled()) - { - TraceSocketReadStop(_asyncReadSize, true); - } - - return completionResult; - } - private void TraceSocketReadStop(int bytesRead, bool async) { if (!async) { - WcfEventSource.Instance.SocketReadStop((_socket != null) ? _socket.GetHashCode() : -1, bytesRead, RemoteEndpointAddressString); + WcfEventSource.Instance.SocketReadStop((_socket != null) ? _socket.GetHashCode() : -1, bytesRead, RemoteEndpointAddress); } else { - WcfEventSource.Instance.SocketAsyncReadStop((_socket != null) ? _socket.GetHashCode() : -1, bytesRead, RemoteEndpointAddressString); + WcfEventSource.Instance.SocketAsyncReadStop((_socket != null) ? _socket.GetHashCode() : -1, bytesRead, RemoteEndpointAddress); } } + public virtual AsyncCompletionResult BeginRead(int offset, int size, TimeSpan timeout, + Action callback, object state) + { + ConnectionUtilities.ValidateBufferBounds(AsyncReadBufferSize, offset, size); + ThrowIfNotOpen(); + return BeginReadCore(offset, size, timeout, callback, state); + } + private AsyncCompletionResult BeginReadCore(int offset, int size, TimeSpan timeout, Action callback, object state) { @@ -874,27 +995,48 @@ private AsyncCompletionResult BeginReadCore(int offset, int size, TimeSpan timeo try { - if (offset != _asyncReadEventArgs.Offset || - size != _asyncReadEventArgs.Count) + if (_socket.UseOnlyOverlappedIO) { - _asyncReadEventArgs.SetBuffer(offset, size); - } + // ReceiveAsync does not respect UseOnlyOverlappedIO but BeginReceive does. + IAsyncResult result = _socket.BeginReceive(AsyncReadBuffer, offset, size, SocketFlags.None, s_onReceiveCompleted, this); + + if (!result.CompletedSynchronously) + { + abortRead = false; + return AsyncCompletionResult.Queued; + } - if (ReceiveAsync()) + _asyncReadSize = _socket.EndReceive(result); + } + else { - abortRead = false; - return AsyncCompletionResult.Queued; + if (offset != _asyncReadEventArgs.Offset || + size != _asyncReadEventArgs.Count) + { + _asyncReadEventArgs.SetBuffer(offset, size); + } + + if (ReceiveAsync()) + { + abortRead = false; + return AsyncCompletionResult.Queued; + } + + HandleReceiveAsyncCompleted(); + _asyncReadSize = _asyncReadEventArgs.BytesTransferred; } - HandleReceiveAsyncCompleted(); - _asyncReadSize = _asyncReadEventArgs.BytesTransferred; + if (WcfEventSource.Instance.SocketReadStopIsEnabled()) + { + TraceSocketReadStop(_asyncReadSize, true); + } abortRead = false; return AsyncCompletionResult.Completed; } catch (SocketException socketException) { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ConvertReceiveException(socketException, TimeSpan.MaxValue)); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ConvertReceiveException(socketException, TimeSpan.MaxValue, _asyncReceiveTimeout)); } catch (ObjectDisposedException objectDisposedException) { @@ -922,19 +1064,61 @@ private bool ReceiveAsync() return _socket.ReceiveAsync(_asyncReadEventArgs); } + private void OnReceive(IAsyncResult result) + { + CancelReceiveTimer(); + if (result.CompletedSynchronously) + { + return; + } + + try + { + _asyncReadSize = _socket.EndReceive(result); + + if (WcfEventSource.Instance.SocketReadStopIsEnabled()) + { + TraceSocketReadStop(_asyncReadSize, true); + } + } + catch (SocketException socketException) + { + _asyncReadException = ConvertReceiveException(socketException, TimeSpan.MaxValue, _asyncReceiveTimeout); + } + catch (ObjectDisposedException objectDisposedException) + { + _asyncReadException = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read); + } + catch (Exception exception) + { + if (Fx.IsFatal(exception)) + { + throw; + } + _asyncReadException = exception; + } + + FinishRead(); + } + private void OnReceiveAsync(object sender, SocketAsyncEventArgs eventArgs) { - Contract.Assert(eventArgs != null, "Argument 'eventArgs' cannot be NULL."); + Fx.Assert(eventArgs != null, "Argument 'eventArgs' cannot be NULL."); CancelReceiveTimer(); try { HandleReceiveAsyncCompleted(); _asyncReadSize = eventArgs.BytesTransferred; + + if (WcfEventSource.Instance.SocketReadStopIsEnabled()) + { + TraceSocketReadStop(_asyncReadSize, true); + } } catch (SocketException socketException) { - _asyncReadException = ConvertReceiveException(socketException, TimeSpan.MaxValue); + _asyncReadException = ConvertReceiveException(socketException, TimeSpan.MaxValue, _asyncReceiveTimeout); } catch (Exception exception) { @@ -958,14 +1142,8 @@ private void HandleReceiveAsyncCompleted() throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException((int)_asyncReadEventArgs.SocketError)); } - private void FinishRead() { - if (_asyncReadException != null && WcfEventSource.Instance.SocketReadStopIsEnabled()) - { - TraceSocketReadStop(_asyncReadSize, true); - } - Action asyncReadCallback = _asyncReadCallback; object asyncReadState = _asyncReadState; @@ -977,12 +1155,6 @@ private void FinishRead() // Both BeginRead/ReadAsync paths completed themselves. EndRead's only job is to deliver the result. public int EndRead() - { - return EndReadCore(); - } - - // Both BeginRead/ReadAsync paths completed themselves. EndRead's only job is to deliver the result. - private int EndReadCore() { if (_asyncReadException != null) { @@ -994,8 +1166,7 @@ private int EndReadCore() { if (!_asyncReadPending) { - Contract.Assert(false, "SocketConnection.EndRead called with no read pending."); - throw new Exception("SocketConnection.EndRead called with no read pending."); + throw Fx.AssertAndThrow("SocketConnection.EndRead called with no read pending."); } SetUserToken(_asyncReadEventArgs, null); @@ -1023,108 +1194,15 @@ private void DisposeReadEventArgs() TryReturnReadBuffer(); } - // This method should be called inside ThisLock - private void DisposeReceiveTimer() - { - if (_receiveTimer != null) - { - _receiveTimer.Dispose(); - } - } - - private void OnSendAsync(object sender, SocketAsyncEventArgs eventArgs) - { - Contract.Assert(eventArgs != null, "Argument 'eventArgs' cannot be NULL."); - CancelSendTimer(); - - try - { - HandleSendAsyncCompleted(); - Contract.Assert(eventArgs.BytesTransferred == _asyncWriteEventArgs.Count, "The socket SendAsync did not send all the bytes."); - } - catch (SocketException socketException) - { - _asyncWriteException = ConvertSendException(socketException, TimeSpan.MaxValue); - } - catch (Exception exception) - { - if (Fx.IsFatal(exception)) - { - throw; - } - - _asyncWriteException = exception; - } - - FinishWrite(); - } - - private void HandleSendAsyncCompleted() - { - if (_asyncWriteEventArgs.SocketError == SocketError.Success) - { - return; - } - - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException((int)_asyncWriteEventArgs.SocketError)); - } - - // This method should be called inside ThisLock - private void DisposeWriteEventArgs() - { - if (_asyncWriteEventArgs != null) - { - _asyncWriteEventArgs.Completed -= s_onSocketSendCompleted; - _asyncWriteEventArgs.Dispose(); - } - } - - // This method should be called inside ThisLock - private void DisposeSendTimer() - { - if (_sendTimer != null) - { - _sendTimer.Dispose(); - } - } - - private void AbortWrite() - { - lock (ThisLock) - { - if (_asyncWritePending) - { - if (_closeState != CloseState.Closed) - { - SetUserToken(_asyncWriteEventArgs, null); - _asyncWritePending = false; - CancelSendTimer(); - } - else - { - DisposeWriteEventArgs(); - } - } - } - } - - // This method should be called inside ThisLock - private void ReturnReadBuffer() - { - // We release the buffer only if there is no outstanding I/O - TryReturnReadBuffer(); - } - - // This method should be called inside ThisLock private void TryReturnReadBuffer() { // The buffer must not be returned and nulled when an abort occurs. Since the buffer // is also accessed by higher layers, code that has not yet realized the stack is // aborted may be attempting to read from the buffer. - if (AsyncReadBuffer != null && !_aborted) + if (_readBuffer != null && !_aborted) { - _connectionBufferPool.Return(AsyncReadBuffer); - AsyncReadBuffer = null; + _connectionBufferPool.Return(_readBuffer); + _readBuffer = null; } } @@ -1164,7 +1242,7 @@ private void SetReadTimeout(TimeSpan timeout, bool synchronous, bool closing) new TimeoutException(SR.Format(SR.TcpConnectionTimedOut, timeout))); } - if (UpdateTimeout(_receiveTimeout, timeout)) + if (ShouldUpdateTimeout(_socketSyncReceiveTimeout, timeout)) { lock (ThisLock) { @@ -1174,12 +1252,12 @@ private void SetReadTimeout(TimeSpan timeout, bool synchronous, bool closing) } _socket.ReceiveTimeout = TimeoutHelper.ToMilliseconds(timeout); } - _receiveTimeout = timeout; + _socketSyncReceiveTimeout = timeout; } } else { - _receiveTimeout = timeout; + _asyncReceiveTimeout = timeout; if (timeout == TimeSpan.MaxValue) { CancelReceiveTimer(); @@ -1204,19 +1282,19 @@ private void SetWriteTimeout(TimeSpan timeout, bool synchronous) new TimeoutException(SR.Format(SR.TcpConnectionTimedOut, timeout))); } - if (UpdateTimeout(_sendTimeout, timeout)) + if (ShouldUpdateTimeout(_socketSyncSendTimeout, timeout)) { lock (ThisLock) { ThrowIfNotOpen(); _socket.SendTimeout = TimeoutHelper.ToMilliseconds(timeout); } - _sendTimeout = timeout; + _socketSyncSendTimeout = timeout; } } else { - _sendTimeout = timeout; + _asyncSendTimeout = timeout; if (timeout == TimeSpan.MaxValue) { CancelSendTimer(); @@ -1228,7 +1306,7 @@ private void SetWriteTimeout(TimeSpan timeout, bool synchronous) } } - private bool UpdateTimeout(TimeSpan oldTimeout, TimeSpan newTimeout) + private bool ShouldUpdateTimeout(TimeSpan oldTimeout, TimeSpan newTimeout) { if (oldTimeout == newTimeout) { @@ -1253,7 +1331,7 @@ private void EnsureReadEventArgs() } _asyncReadEventArgs = new SocketAsyncEventArgs(); - _asyncReadEventArgs.SetBuffer(AsyncReadBuffer, 0, AsyncReadBuffer.Length); + _asyncReadEventArgs.SetBuffer(_readBuffer, 0, _readBuffer.Length); _asyncReadEventArgs.Completed += s_onReceiveAsyncCompleted; } } @@ -1274,11 +1352,6 @@ private void EnsureWriteEventArgs() } } - public object GetCoreTransport() - { - return _socket; - } - private enum CloseState { Open, @@ -1313,7 +1386,7 @@ private IConnection CreateConnection(IPAddress address, int port) AddressFamily addressFamily = address.AddressFamily; socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp); socket.Connect(new IPEndPoint(address, port)); - return new SocketConnection(socket, _connectionBufferPool); + return new SocketConnection(socket, _connectionBufferPool, false); } catch { @@ -1330,7 +1403,7 @@ private async Task CreateConnectionAsync(IPAddress address, int por AddressFamily addressFamily = address.AddressFamily; socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp); await socket.ConnectAsync(new IPEndPoint(address, port)); - return new SocketConnection(socket, _connectionBufferPool); + return new SocketConnection(socket, _connectionBufferPool, false); } catch { From 21b64d485cf8f7d3005db3e09a01653f74f25046 Mon Sep 17 00:00:00 2001 From: Matt Connew Date: Fri, 4 Oct 2019 17:51:47 -0700 Subject: [PATCH 6/7] Fix contract methods which use out parameters --- .../ServiceModel/Channels/MethodCall.cs | 38 +++++++++++++++++++ .../Channels/ServiceChannelProxy.cs | 4 +- .../Description/MessagePartDescription.cs | 6 +-- .../Dispatcher/ProxyOperationRuntime.cs | 2 +- .../Common/Scenarios/ServiceInterfaces.cs | 3 ++ .../Service/ServiceContractTests.4.0.0.cs | 8 ++++ .../ServiceContractAsyncInterfaces.cs | 3 ++ .../App_code/ServiceContractAsyncServices.cs | 6 +++ 8 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/MethodCall.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/MethodCall.cs index fa4178cf3db..c6d5ba30455 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/MethodCall.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/MethodCall.cs @@ -5,12 +5,16 @@ using System.Diagnostics.Contracts; using System.Reflection; +using System.Runtime; +using System.ServiceModel.Description; namespace System.ServiceModel.Channels { // MethodCall associates a MethodBase with the arguments to pass to it. internal class MethodCall { + private object[] _inArgs; + public MethodCall(object[] args) { Contract.Assert(args != null); @@ -21,10 +25,44 @@ public MethodCall(MethodBase methodBase, object[] args) : this(args) { Contract.Assert(methodBase != null); MethodBase = methodBase; + CreateInArgs(); } public MethodBase MethodBase { get; private set; } public object[] Args { get; private set; } + + public object[] InArgs => _inArgs ?? Args; + + private void CreateInArgs() + { + var parameters = MethodBase.GetParameters(); + int inCount = 0; + foreach(var param in parameters) + { + if (ServiceReflector.FlowsIn(param)) + { + inCount++; + } + } + + if (inCount == Args.Length) // All parameters are InArgs so do nothing and fallback to returning Args + { + return; + } + + _inArgs = new object[inCount]; + int inPos = 0; + for(int argPos = 0; argPos < parameters.Length; argPos++) + { + if (ServiceReflector.FlowsIn(parameters[argPos])) + { + _inArgs[inPos] = Args[argPos]; + inPos++; + } + } + + Fx.Assert((inPos - 1) != (inCount), $"Incorrect number of arguments put into _inArgs array, expected {inCount} and copied {inPos - 1}"); + } } } diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/ServiceChannelProxy.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/ServiceChannelProxy.cs index dc772aa347d..33f015580ff 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/ServiceChannelProxy.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Channels/ServiceChannelProxy.cs @@ -164,9 +164,9 @@ public static Task CreateTask(ServiceChannel channel, MethodCall methodCall, Pro { if (operation.TaskTResult == ServiceReflector.VoidType) { - return TaskCreator.CreateTask(channel, operation, methodCall.Args); + return TaskCreator.CreateTask(channel, operation, methodCall.InArgs); } - return TaskCreator.CreateGenericTask(channel, operation, methodCall.Args); + return TaskCreator.CreateGenericTask(channel, operation, methodCall.InArgs); } private static Task CreateGenericTask(ServiceChannel channel, ProxyOperationRuntime operation, object[] inputParameters) diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Description/MessagePartDescription.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Description/MessagePartDescription.cs index fbebeb7267b..7a2f150fc7c 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Description/MessagePartDescription.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Description/MessagePartDescription.cs @@ -11,7 +11,7 @@ namespace System.ServiceModel.Description { - [DebuggerDisplay("Name={_name}, Namespace={_ns}, Type={Type}, Index={_index}}")] + [DebuggerDisplay("Name={XmlName}, Namespace={Namespace}, Type={Type}, Index={Index}}")] public class MessagePartDescription { private ProtectionLevel _protectionLevel; @@ -22,14 +22,14 @@ public MessagePartDescription(string name, string ns) { if (name == null) { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("name", SR.SFxParameterNameCannotBeNull); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(name), SR.SFxParameterNameCannotBeNull); } XmlName = new XmlName(name, true /*isEncoded*/); if (!string.IsNullOrEmpty(ns)) { - NamingHelper.CheckUriParameter(ns, "ns"); + NamingHelper.CheckUriParameter(ns, nameof(ns)); } Namespace = ns; diff --git a/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ProxyOperationRuntime.cs b/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ProxyOperationRuntime.cs index 2abae4ed4ee..eab1f82e87a 100644 --- a/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ProxyOperationRuntime.cs +++ b/src/System.Private.ServiceModel/src/System/ServiceModel/Dispatcher/ProxyOperationRuntime.cs @@ -299,7 +299,7 @@ internal object[] MapSyncInputs(MethodCall methodCall, out object[] outs) return Array.Empty(); } - return methodCall.Args; + return methodCall.InArgs; } internal object[] MapAsyncBeginInputs(MethodCall methodCall, out AsyncCallback callback, out object asyncState) diff --git a/src/System.Private.ServiceModel/tests/Common/Scenarios/ServiceInterfaces.cs b/src/System.Private.ServiceModel/tests/Common/Scenarios/ServiceInterfaces.cs index 0db061e1806..270cb933cb8 100644 --- a/src/System.Private.ServiceModel/tests/Common/Scenarios/ServiceInterfaces.cs +++ b/src/System.Private.ServiceModel/tests/Common/Scenarios/ServiceInterfaces.cs @@ -495,6 +495,9 @@ public interface IServiceContractUniqueTypeOutSyncService { [OperationContract] void Request(string stringRequest, out UniqueType uniqueTypeResponse); + + [OperationContract] + void Request2(out UniqueType uniqueTypeResponse, string stringRequest); } [ServiceContract] diff --git a/src/System.Private.ServiceModel/tests/Scenarios/Contract/Service/ServiceContractTests.4.0.0.cs b/src/System.Private.ServiceModel/tests/Scenarios/Contract/Service/ServiceContractTests.4.0.0.cs index f860466fa26..5dd31d1360f 100644 --- a/src/System.Private.ServiceModel/tests/Scenarios/Contract/Service/ServiceContractTests.4.0.0.cs +++ b/src/System.Private.ServiceModel/tests/Scenarios/Contract/Service/ServiceContractTests.4.0.0.cs @@ -225,6 +225,14 @@ public static void ServiceContract_TypedProxy_SyncOperation_UniqueTypeOutArg() // *** EXECUTE *** \\ serviceProxy.Request(message, out uniqueType); + // *** VALIDATE *** \\ + Assert.True((uniqueType.stringValue == message), + String.Format("The value of the 'stringValue' field in the UniqueType instance was not as expected. expected {0} but got {1}", message, uniqueType.stringValue)); + + // *** EXECUTE *** \\ + uniqueType = null; + serviceProxy.Request2(out uniqueType, message); + // *** VALIDATE *** \\ Assert.True((uniqueType.stringValue == message), String.Format("The value of the 'stringValue' field in the UniqueType instance was not as expected. expected {0} but got {1}", message, uniqueType.stringValue)); diff --git a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/ServiceContractAsyncInterfaces.cs b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/ServiceContractAsyncInterfaces.cs index f4319614d64..8104ea8f2b3 100644 --- a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/ServiceContractAsyncInterfaces.cs +++ b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/ServiceContractAsyncInterfaces.cs @@ -40,6 +40,9 @@ public interface IServiceContractUniqueTypeOutSyncService { [OperationContract] void Request(string stringRequest, out UniqueType uniqueTypeResponse); + + [OperationContract] + void Request2(out UniqueType uniqueTypeResponse, string stringRequest); } [ServiceContract] diff --git a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/ServiceContractAsyncServices.cs b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/ServiceContractAsyncServices.cs index a9066aad895..89c419ee870 100644 --- a/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/ServiceContractAsyncServices.cs +++ b/src/System.Private.ServiceModel/tools/IISHostedWcfService/App_code/ServiceContractAsyncServices.cs @@ -49,6 +49,12 @@ public void Request(string stringRequest, out UniqueType uniqueTypeResponse) uniqueTypeResponse = new UniqueType(); uniqueTypeResponse.stringValue = stringRequest; } + + public void Request2(out UniqueType uniqueTypeResponse, string stringRequest) + { + uniqueTypeResponse = new UniqueType(); + uniqueTypeResponse.stringValue = stringRequest; + } } public class ServiceContractUniqueTypeRefSyncService : IServiceContractUniqueTypeRefSyncService From f9ab67aac1ef2aa54db7ceb627e04ab1f45da904 Mon Sep 17 00:00:00 2001 From: Stephen Bonikowsky Date: Thu, 24 Oct 2019 17:09:09 -0700 Subject: [PATCH 7/7] Enable or disable shipping different packages. * By default always ship WCF packages. * By default do not ship dotnet-svcutil.xmlserializer packages. * Enable or disable either one by setting their respective properties to true or false, can be done from the build definition that produces final release packages. * Fixes #3975 --- eng/Versioning.props | 2 ++ .../src/System.Private.ServiceModel.csproj | 1 + .../src/System.ServiceModel.Duplex.Facade.csproj | 1 + .../src/System.ServiceModel.Http.Facade.csproj | 1 + .../src/System.ServiceModel.NetTcp.Facade.csproj | 1 + .../src/System.ServiceModel.Primitives.Facade.csproj | 1 + .../src/System.ServiceModel.Security.Facade.csproj | 1 + src/svcutilcore/src/dotnet-svcutil.xmlserializer.csproj | 2 +- 8 files changed, 9 insertions(+), 1 deletion(-) diff --git a/eng/Versioning.props b/eng/Versioning.props index 94b37faf74b..18951dc162e 100644 --- a/eng/Versioning.props +++ b/eng/Versioning.props @@ -1,6 +1,8 @@ true + false + true diff --git a/src/System.Private.ServiceModel/src/System.Private.ServiceModel.csproj b/src/System.Private.ServiceModel/src/System.Private.ServiceModel.csproj index d983ae8f79c..6020f5fb120 100644 --- a/src/System.Private.ServiceModel/src/System.Private.ServiceModel.csproj +++ b/src/System.Private.ServiceModel/src/System.Private.ServiceModel.csproj @@ -18,6 +18,7 @@ true true true + $(Ship_WcfPackages) diff --git a/src/System.ServiceModel.Duplex/src/System.ServiceModel.Duplex.Facade.csproj b/src/System.ServiceModel.Duplex/src/System.ServiceModel.Duplex.Facade.csproj index b04c4af4b91..6a3b41b491c 100644 --- a/src/System.ServiceModel.Duplex/src/System.ServiceModel.Duplex.Facade.csproj +++ b/src/System.ServiceModel.Duplex/src/System.ServiceModel.Duplex.Facade.csproj @@ -13,6 +13,7 @@ $(BuildFrameworks)$(HarvestFrameworks) true true + $(Ship_WcfPackages) diff --git a/src/System.ServiceModel.Http/src/System.ServiceModel.Http.Facade.csproj b/src/System.ServiceModel.Http/src/System.ServiceModel.Http.Facade.csproj index 6c473e7c556..088abf7d963 100644 --- a/src/System.ServiceModel.Http/src/System.ServiceModel.Http.Facade.csproj +++ b/src/System.ServiceModel.Http/src/System.ServiceModel.Http.Facade.csproj @@ -13,6 +13,7 @@ $(BuildFrameworks)$(HarvestFrameworks) true true + $(Ship_WcfPackages) diff --git a/src/System.ServiceModel.NetTcp/src/System.ServiceModel.NetTcp.Facade.csproj b/src/System.ServiceModel.NetTcp/src/System.ServiceModel.NetTcp.Facade.csproj index bf2ebd53af2..21ec3e8bd10 100644 --- a/src/System.ServiceModel.NetTcp/src/System.ServiceModel.NetTcp.Facade.csproj +++ b/src/System.ServiceModel.NetTcp/src/System.ServiceModel.NetTcp.Facade.csproj @@ -13,6 +13,7 @@ $(BuildFrameworks)$(HarvestFrameworks) true true + $(Ship_WcfPackages) diff --git a/src/System.ServiceModel.Primitives/src/System.ServiceModel.Primitives.Facade.csproj b/src/System.ServiceModel.Primitives/src/System.ServiceModel.Primitives.Facade.csproj index 91273150c3c..745f9d8c9a4 100644 --- a/src/System.ServiceModel.Primitives/src/System.ServiceModel.Primitives.Facade.csproj +++ b/src/System.ServiceModel.Primitives/src/System.ServiceModel.Primitives.Facade.csproj @@ -13,6 +13,7 @@ $(BuildFrameworks)$(HarvestFrameworks) true true + $(Ship_WcfPackages) diff --git a/src/System.ServiceModel.Security/src/System.ServiceModel.Security.Facade.csproj b/src/System.ServiceModel.Security/src/System.ServiceModel.Security.Facade.csproj index 352c7893b90..18e88759a61 100644 --- a/src/System.ServiceModel.Security/src/System.ServiceModel.Security.Facade.csproj +++ b/src/System.ServiceModel.Security/src/System.ServiceModel.Security.Facade.csproj @@ -13,6 +13,7 @@ $(BuildFrameworks)$(HarvestFrameworks) true true + $(Ship_WcfPackages) diff --git a/src/svcutilcore/src/dotnet-svcutil.xmlserializer.csproj b/src/svcutilcore/src/dotnet-svcutil.xmlserializer.csproj index 6154a777a29..1ed89c059df 100644 --- a/src/svcutilcore/src/dotnet-svcutil.xmlserializer.csproj +++ b/src/svcutilcore/src/dotnet-svcutil.xmlserializer.csproj @@ -12,7 +12,7 @@ true AnyCPU {EAB2959D-0A16-4F60-A453-765491E1C069} - false + $(Ship_SvcUtilXmlSerPackages)