Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BuildToolsVersion.txt2
-rw-r--r--Documentation/project-docs/issue-guide.md4
-rw-r--r--dependencies.props40
-rw-r--r--external/test-runtime/XUnit.Runtime.depproj2
-rw-r--r--external/test-runtime/optional.json6
-rw-r--r--pkg/Microsoft.Private.PackageBaseline/packageIndex.json4
-rw-r--r--pkg/test/packageSettings/System.IO.Packaging/netcoreapp1.0/workaroundDowngrade.targets7
-rw-r--r--pkg/test/packageSettings/System.Security.Cryptography.Pkcs/netcoreapp1.0/workaroundDowngrade.targets7
-rw-r--r--src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems5
-rw-r--r--src/Common/src/CoreLib/System/Buffers/IMemoryOwner.cs18
-rw-r--r--src/Common/src/CoreLib/System/Buffers/IPinnable.cs25
-rw-r--r--src/Common/src/CoreLib/System/Buffers/IRetainable.cs26
-rw-r--r--src/Common/src/CoreLib/System/Buffers/MemoryHandle.cs27
-rw-r--r--src/Common/src/CoreLib/System/Buffers/MemoryManager.cs66
-rw-r--r--src/Common/src/CoreLib/System/Buffers/OwnedMemory.cs95
-rw-r--r--src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs14
-rw-r--r--src/Common/src/CoreLib/System/Collections/Generic/List.cs2
-rw-r--r--src/Common/src/CoreLib/System/Memory.cs154
-rw-r--r--src/Common/src/CoreLib/System/MemoryExtensions.Fast.cs4
-rw-r--r--src/Common/src/CoreLib/System/MemoryExtensions.cs10
-rw-r--r--src/Common/src/CoreLib/System/ReadOnlyMemory.cs84
-rw-r--r--src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs67
-rw-r--r--src/Common/src/CoreLib/System/SpanHelpers.Char.cs128
-rw-r--r--src/Common/src/CoreLib/System/String.Searching.cs116
-rw-r--r--src/Common/src/CoreLib/System/String.cs1
-rw-r--r--src/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs2
-rw-r--r--src/Common/src/Interop/Windows/SChannel/Interop.SchProtocols.cs6
-rw-r--r--src/Common/src/System/Collections/Concurrent/ConcurrentQueue_Segment.cs335
-rw-r--r--src/Common/src/System/Net/SecurityProtocol.cs15
-rw-r--r--src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs24
-rw-r--r--src/Common/tests/System/Buffers/NativeMemoryManager.cs (renamed from src/Common/tests/System/Buffers/NativeOwnedMemory.cs)54
-rw-r--r--src/Common/tests/System/Net/SslProtocolSupport.cs43
-rw-r--r--src/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs35
-rw-r--r--src/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs10
-rw-r--r--src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs2
-rw-r--r--src/Microsoft.VisualBasic/src/MatchingRefApiCompatBaseline.netstandard.txt22
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Conversions.vb8
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/DesignerGeneratedAttribute.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/ExceptionUtils.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/IncompleteInitialization.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/NewLateBinding.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Operators.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/OptionCompareAttribute.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/OptionTextAttribute.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/StandardModuleAttribute.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/StaticLocalInitFlag.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Utils.LateBinder.vb4
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/ControlChars.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/HideModuleNameAttribute.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/Interaction.vb2
-rw-r--r--src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/Strings.vb2
-rw-r--r--src/Native/Unix/System.Net.Http.Native/pal_easy.cpp2
-rw-r--r--src/Native/Unix/System.Net.Http.Native/pal_easy.h2
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509chain.cpp7
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp5
-rw-r--r--src/System.Collections.Concurrent/src/System.Collections.Concurrent.csproj3
-rw-r--r--src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentQueue.cs323
-rw-r--r--src/System.Data.SqlClient/dir.props2
-rw-r--r--src/System.Data.SqlClient/pkg/System.Data.SqlClient.pkgproj15
-rw-r--r--src/System.Data.SqlClient/ref/Configurations.props1
-rw-r--r--src/System.Data.SqlClient/ref/System.Data.SqlClient.NetCoreApp.cs14
-rw-r--r--src/System.Data.SqlClient/ref/System.Data.SqlClient.cs1
-rw-r--r--src/System.Data.SqlClient/ref/System.Data.SqlClient.csproj19
-rw-r--r--src/System.Data.SqlClient/src/Configurations.props6
-rw-r--r--src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt9
-rw-r--r--src/System.Data.SqlClient/src/PinvokeAnalyzerExceptionList.analyzerdata.netcoreapp44
-rw-r--r--src/System.Data.SqlClient/src/System.Data.SqlClient.csproj28
-rw-r--r--src/System.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs96
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs100
-rw-r--r--src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs25
-rw-r--r--src/System.Diagnostics.Process/tests/ProcessTests.cs6
-rw-r--r--src/System.Drawing.Common/src/System.Drawing.Common.csproj2
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/FontFamily.Unix.cs30
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/FontFamily.Windows.cs30
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/FontFamily.cs19
-rw-r--r--src/System.Drawing.Common/tests/FontTests.cs45
-rw-r--r--src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs4
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Unix.cs86
-rw-r--r--src/System.IO.FileSystem/tests/FileStream/ReadWriteSpan.netcoreapp.cs8
-rw-r--r--src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj4
-rw-r--r--src/System.IO.Pipelines/ref/System.IO.Pipelines.cs2
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs18
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs25
-rw-r--r--src/System.IO.Pipelines/tests/BackpressureTests.cs46
-rw-r--r--src/System.IO.Pipelines/tests/PipePoolTests.cs65
-rw-r--r--src/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs78
-rw-r--r--src/System.IO.Pipelines/tests/PipeWriterTests.cs14
-rw-r--r--src/System.IO.Pipelines/tests/TestMemoryPool.cs60
-rw-r--r--src/System.IO/tests/Stream/Stream.ReadWriteSpan.netcoreapp.cs4
-rw-r--r--src/System.IO/tests/System.IO.Tests.csproj4
-rw-r--r--src/System.Memory/ref/System.Memory.cs99
-rw-r--r--src/System.Memory/src/System.Memory.csproj5
-rw-r--r--src/System.Memory/src/System/Buffers/ArrayMemoryPool.ArrayMemoryPoolBuffer.cs57
-rw-r--r--src/System.Memory/src/System/Buffers/ArrayMemoryPool.cs2
-rw-r--r--src/System.Memory/src/System/Buffers/MemoryPool.cs2
-rw-r--r--src/System.Memory/src/System/Buffers/ReadOnlySequence.cs44
-rw-r--r--src/System.Memory/src/System/Buffers/ReadOnlySequence_helpers.cs32
-rw-r--r--src/System.Memory/src/System/Runtime/InteropServices/SequenceMarshal.cs8
-rw-r--r--src/System.Memory/src/System/ThrowHelper.cs20
-rw-r--r--src/System.Memory/tests/Memory/CtorArray.cs10
-rw-r--r--src/System.Memory/tests/Memory/CustomMemoryForTest.cs45
-rw-r--r--src/System.Memory/tests/Memory/MemoryManager.cs (renamed from src/System.Memory/tests/Memory/OwnedMemory.cs)105
-rw-r--r--src/System.Memory/tests/Memory/Pin.cs26
-rw-r--r--src/System.Memory/tests/Memory/Retain.cs165
-rw-r--r--src/System.Memory/tests/Memory/Slice.cs44
-rw-r--r--src/System.Memory/tests/Memory/Span.cs20
-rw-r--r--src/System.Memory/tests/Memory/ToString.cs26
-rw-r--r--src/System.Memory/tests/MemoryMarshal/TryGetArray.cs18
-rw-r--r--src/System.Memory/tests/MemoryMarshal/TryGetMemoryManager.cs89
-rw-r--r--src/System.Memory/tests/MemoryMarshal/TryGetOwnedMemory.cs93
-rw-r--r--src/System.Memory/tests/MemoryPool/MemoryPool.cs224
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs16
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs16
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs33
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.TryGet.cs29
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs5
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.char.cs5
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/Pin.cs26
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/Retain.cs165
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/Slice.cs44
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/Span.cs20
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/ToString.cs26
-rw-r--r--src/System.Memory/tests/Resources/System.Memory.Tests.rd.xml2
-rw-r--r--src/System.Memory/tests/Span/Reflection.cs186
-rw-r--r--src/System.Memory/tests/System.Memory.Tests.csproj11
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs14
-rw-r--r--src/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs45
-rw-r--r--src/System.Net.Http/src/System.Net.Http.csproj3
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs15
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs15
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs1
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs1
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs1
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs5
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs133
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs74
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs5
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs74
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs4
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs2
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs113
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/ReadOnlyMemoryContentTest.cs385
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj4
-rw-r--r--src/System.Net.HttpListener/src/System/Net/Managed/WebSockets/HttpWebSocket.Managed.cs7
-rw-r--r--src/System.Net.Mail/tests/Functional/SmtpClientTest.cs20
-rw-r--r--src/System.Net.Primitives/src/System/Net/CookieContainer.cs19
-rw-r--r--src/System.Net.Security/ref/System.Net.Security.cs3
-rw-r--r--src/System.Net.Security/src/System.Net.Security.csproj1
-rw-r--r--src/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs99
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SecureChannel.cs18
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SniHelper.cs391
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs2
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs4
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslState.cs10
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslStream.cs45
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs3
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs38
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs38
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/SniHelperTest.cs3255
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs135
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs6
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/SslStreamSystemDefaultsTest.cs59
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj7
-rw-r--r--src/System.Net.Security/tests/UnitTests/Fakes/FakeSslState.cs2
-rw-r--r--src/System.Net.Security/tests/UnitTests/SslStreamAllowedProtocolsTest.cs29
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs6
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs20
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs1
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.netcoreapp.cs2
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.netcoreapp.cs4
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj4
-rw-r--r--src/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.cs4
-rw-r--r--src/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/WebSocketProtocol.cs5
-rw-r--r--src/System.Net.WebSockets.WebSocketProtocol/tests/WebSocketProtocolTests.cs16
-rw-r--r--src/System.Net.WebSockets/ref/System.Net.WebSockets.cs2
-rw-r--r--src/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs13
-rw-r--r--src/System.Net.WebSockets/tests/WebSocketTests.netcoreapp.cs11
-rw-r--r--src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs10
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs10
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/XmlSchemaImporter.cs13
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs34
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs2
-rw-r--r--src/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryContext.cs4
-rw-r--r--src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/MessageAction.cs3
-rw-r--r--src/System.Private.Xml/tests/Writers/RwFactory/CXmlDriverVariation.cs3
-rw-r--r--src/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/TC_SchemaSet_Compile.cs1
-rw-r--r--src/System.Private.Xml/tests/XmlSchema/XmlSchemaValidatorApi/ValidateMisc.cs2
-rw-r--r--src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XslCompiledTransform.cs38
-rw-r--r--src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltApiV2.cs2
-rw-r--r--src/System.Private.Xml/tests/Xslt/XslTransformApi/XSLTransform.cs2
-rw-r--r--src/System.Runtime.Caching/src/MatchingRefApiCompatBaseline.txt6
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/CachingSectionGroup.cs2
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheElement.cs2
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheSection.cs2
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheSettingsCollection.cs2
-rw-r--r--src/System.Runtime.Serialization.Xml/src/MatchingRefApiCompatBaseline.txt3
-rw-r--r--src/System.Runtime/ref/System.Runtime.cs87
-rw-r--r--src/System.Runtime/src/ApiCompatBaseline.uap.txt10
-rw-r--r--src/System.Runtime/src/ApiCompatBaseline.uapaot.txt8
-rw-r--r--src/System.Runtime/src/System.Runtime.csproj1
-rw-r--r--src/System.Security.Cryptography.Csp/src/Internal/Cryptography/Helpers.cs14
-rw-r--r--src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DESCryptoServiceProvider.Unix.cs9
-rw-r--r--src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RC2CryptoServiceProvider.Unix.cs8
-rw-r--r--src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/TripleDESCryptoServiceProvider.cs9
-rw-r--r--src/System.Security.Cryptography.Csp/tests/CreateTransformCompat.cs67
-rw-r--r--src/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj1
-rw-r--r--src/System.Security.Cryptography.X509Certificates/tests/ChainTests.cs19
-rw-r--r--src/System.Threading.Thread/tests/ThreadTests.cs20
-rw-r--r--src/System.Xml.XmlSerializer/ref/System.Xml.XmlSerializer.cs8
-rw-r--r--src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.netcoreapp.txt7
-rw-r--r--src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uap.txt7
-rw-r--r--src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uapaot.txt7
-rw-r--r--src/shims/ApiCompatBaseline.uapaot.netstandard20.txt8
-rw-r--r--tools-local/ILAsmVersion.txt2
214 files changed, 6818 insertions, 3258 deletions
diff --git a/BuildToolsVersion.txt b/BuildToolsVersion.txt
index 7d7e2d494c..ae89f1826c 100644
--- a/BuildToolsVersion.txt
+++ b/BuildToolsVersion.txt
@@ -1 +1 @@
-2.1.0-preview3-02629-02
+2.1.0-preview2-02629-01
diff --git a/Documentation/project-docs/issue-guide.md b/Documentation/project-docs/issue-guide.md
index 5e0fc52ea3..008222056b 100644
--- a/Documentation/project-docs/issue-guide.md
+++ b/Documentation/project-docs/issue-guide.md
@@ -55,8 +55,8 @@ Areas are tracked by labels area-* (e.g. area-System.Collections). Each area
| [System.Composition](https://github.com/dotnet/corefx/labels/area-System.Composition) | **[@maryamariyan](https://github.com/maryamariyan)**, [@ViktorHofer](https://github.com/ViktorHofer) | |
| [System.Configuration](https://github.com/dotnet/corefx/labels/area-System.Configuration) | [@maryamariyan](https://github.com/maryamariyan) | |
| [System.Console](https://github.com/dotnet/corefx/labels/area-System.Console) | **[@joperezr](https://github.com/joperezr)**, [@ianhays](https://github.com/ianhays) | |
-| [System.Data](https://github.com/dotnet/corefx/labels/area-System.Data) | **[@divega](https://github.com/divega)**, [@ajcvickers](https://github.com/ajcvickers), [@keeratsingh](https://github.com/keeratsingh), [@afsanehr](https://github.com/afsanehr), [@david-engel](https://github.com/david-engel), [@saurabh500](https://github.com/saurabh500) | |
-| [System.Data.SqlClient](https://github.com/dotnet/corefx/labels/area-System.Data.SqlClient) | **[@keeratsingh](https://github.com/keeratsingh)**, [@afsanehr](https://github.com/afsanehr), [@david-engel](https://github.com/david-engel), [@saurabh500](https://github.com/saurabh500) | |
+| [System.Data](https://github.com/dotnet/corefx/labels/area-System.Data) | **[@divega](https://github.com/divega)**, [@ajcvickers](https://github.com/ajcvickers), [@keeratsingh](https://github.com/keeratsingh), [@afsanehr](https://github.com/afsanehr), [@david-engel](https://github.com/david-engel) | |
+| [System.Data.SqlClient](https://github.com/dotnet/corefx/labels/area-System.Data.SqlClient) | **[@keeratsingh](https://github.com/keeratsingh)**, [@afsanehr](https://github.com/afsanehr), [@david-engel](https://github.com/david-engel) | |
| [System.Diagnostics](https://github.com/dotnet/corefx/labels/area-System.Diagnostics) | **[@joperezr](https://github.com/joperezr)**, [@wtgodbe](https://github.com/wtgodbe) | <ul><li>System.Diagnostics.EventLog [@Anipik](https://github.com/Anipik)</li></ul> |
| [System.Diagnostics.Process](https://github.com/dotnet/corefx/labels/area-System.Diagnostics.Process) | **[@joperezr](https://github.com/joperezr)**, [@wtgodbe](https://github.com/wtgodbe) | |
| [System.Diagnostics.Tracing](https://github.com/dotnet/corefx/labels/area-System.Diagnostics.Tracing) | [@brianrob](https://github.com/brianrob), [@vancem](https://github.com/vancem), [@valenis](https://github.com/valenis) | Packages:<ul><li>System.Diagnostics.DiagnosticSource</li><li>System.Diagnostics.PerformanceCounter - [@adiaaida](https://github.com/adiaaida)</li><li>System.Diagnostics.Tracing</li><li>System.Diagnostics.TraceSource</li></ul><br/> |
diff --git a/dependencies.props b/dependencies.props
index a3f91b9be6..fd03675b90 100644
--- a/dependencies.props
+++ b/dependencies.props
@@ -9,15 +9,15 @@
These ref versions are pulled from https://github.com/dotnet/versions.
-->
<PropertyGroup>
- <CoreFxCurrentRef>557c1e3cd387554127d14604466e78d45af8df54</CoreFxCurrentRef>
- <CoreClrCurrentRef>68931eec8b1b9daed99ab9fbe0baf26fd0637dc0</CoreClrCurrentRef>
- <CoreSetupCurrentRef>557c1e3cd387554127d14604466e78d45af8df54</CoreSetupCurrentRef>
+ <CoreFxCurrentRef>d5ab69777647515ec8671bd46ad19aeafa289dd1</CoreFxCurrentRef>
+ <CoreClrCurrentRef>d5ab69777647515ec8671bd46ad19aeafa289dd1</CoreClrCurrentRef>
+ <CoreSetupCurrentRef>d5ab69777647515ec8671bd46ad19aeafa289dd1</CoreSetupCurrentRef>
<ExternalCurrentRef>96dc7805f5df4a70a55783964ce69dcd91bfca80</ExternalCurrentRef>
- <ProjectNTfsCurrentRef>80227ec4e1f84877b5298d87680848011ad6462b</ProjectNTfsCurrentRef>
- <ProjectNTfsTestILCCurrentRef>80227ec4e1f84877b5298d87680848011ad6462b</ProjectNTfsTestILCCurrentRef>
+ <ProjectNTfsCurrentRef>5c5d8906d00f58ed9c9e00595212ac4cdb0028b3</ProjectNTfsCurrentRef>
+ <ProjectNTfsTestILCCurrentRef>5c5d8906d00f58ed9c9e00595212ac4cdb0028b3</ProjectNTfsTestILCCurrentRef>
<SniCurrentRef>8bd1ec5fac9f0eec34ff6b34b1d878b4359e02dd</SniCurrentRef>
<StandardCurrentRef>6298244e25cf84d91e3cda9627315f2425274624</StandardCurrentRef>
- <BuildToolsCurrentRef>68931eec8b1b9daed99ab9fbe0baf26fd0637dc0</BuildToolsCurrentRef>
+ <BuildToolsCurrentRef>d5ab69777647515ec8671bd46ad19aeafa289dd1</BuildToolsCurrentRef>
</PropertyGroup>
<!-- Product dependency versions. -->
@@ -31,16 +31,15 @@
<!-- Tests/infrastructure dependency versions. -->
<PropertyGroup>
- <CoreFxExpectedPrerelease>preview3-26329-05</CoreFxExpectedPrerelease>
- <MicrosoftNETCorePlatformsPackageVersion>2.1.0-preview3-26329-05</MicrosoftNETCorePlatformsPackageVersion>
- <MicrosoftNETCoreRuntimeCoreCLRPackageVersion>2.1.0-preview3-26329-01</MicrosoftNETCoreRuntimeCoreCLRPackageVersion>
- <ProjectNTfsExpectedPrerelease>beta-26329-00</ProjectNTfsExpectedPrerelease>
- <ProjectNTfsTestILCExpectedPrerelease>beta-26329-00</ProjectNTfsTestILCExpectedPrerelease>
- <ProjectNTfsTestILCPackageVersion>1.0.0-beta-26329-00</ProjectNTfsTestILCPackageVersion>
- <MicrosoftNETCoreDotNetHostPackageVersion>2.1.0-preview3-26329-02</MicrosoftNETCoreDotNetHostPackageVersion>
- <MicrosoftNETCoreDotNetHostPolicyPackageVersion>2.1.0-preview3-26329-02</MicrosoftNETCoreDotNetHostPolicyPackageVersion>
- <MicrosoftNETCoreAppPackageVersion>2.1.0-preview3-26329-02</MicrosoftNETCoreAppPackageVersion>
- <MicrosoftDotNetPlatformAbstractionsPackageVersion>2.1.0-preview3-26329-02</MicrosoftDotNetPlatformAbstractionsPackageVersion>
+ <CoreFxExpectedPrerelease>preview2-26403-05</CoreFxExpectedPrerelease>
+ <MicrosoftNETCorePlatformsPackageVersion>2.1.0-preview2-26403-05</MicrosoftNETCorePlatformsPackageVersion>
+ <MicrosoftNETCoreRuntimeCoreCLRPackageVersion>2.1.0-preview2-26403-07</MicrosoftNETCoreRuntimeCoreCLRPackageVersion>
+ <ProjectNTfsExpectedPrerelease>beta-26330-00</ProjectNTfsExpectedPrerelease>
+ <ProjectNTfsTestILCExpectedPrerelease>beta-26330-00</ProjectNTfsTestILCExpectedPrerelease>
+ <ProjectNTfsTestILCPackageVersion>1.0.0-beta-26330-00</ProjectNTfsTestILCPackageVersion>
+ <MicrosoftNETCoreDotNetHostPackageVersion>2.1.0-preview2-26403-06</MicrosoftNETCoreDotNetHostPackageVersion>
+ <MicrosoftNETCoreDotNetHostPolicyPackageVersion>2.1.0-preview2-26403-06</MicrosoftNETCoreDotNetHostPolicyPackageVersion>
+ <MicrosoftNETCoreAppPackageVersion>2.1.0-preview2-26403-06</MicrosoftNETCoreAppPackageVersion>
<!-- CoreFX-built SNI identity package -->
<RuntimeNativeSystemDataSqlClientSniPackageVersion>4.4.0</RuntimeNativeSystemDataSqlClientSniPackageVersion>
@@ -48,7 +47,7 @@
<AppXRunnerVersion>1.0.3-prerelease-00921-01</AppXRunnerVersion>
<XunitPerfAnalysisPackageVersion>1.0.0-beta-build0018</XunitPerfAnalysisPackageVersion>
<TraceEventPackageVersion>2.0.5</TraceEventPackageVersion>
- <XunitNetcoreExtensionsVersion>2.1.0-preview3-02629-02</XunitNetcoreExtensionsVersion>
+ <XunitNetcoreExtensionsVersion>2.1.0-preview2-02629-01</XunitNetcoreExtensionsVersion>
<!-- Roslyn optimization data package version -->
<OptimizationDataVersion>2.0.0-rc-61101-17</OptimizationDataVersion>
@@ -57,7 +56,7 @@
<!-- Package versions used as toolsets -->
<PropertyGroup>
<FeedTasksPackage>Microsoft.DotNet.Build.Tasks.Feed</FeedTasksPackage>
- <FeedTasksPackageVersion>2.1.0-preview3-02629-02</FeedTasksPackageVersion>
+ <FeedTasksPackageVersion>2.1.0-preview2-02629-01</FeedTasksPackageVersion>
</PropertyGroup>
<!-- Publish symbol build task package -->
@@ -176,11 +175,6 @@
<ElementName>MicrosoftNETCoreAppPackageVersion</ElementName>
<PackageId>Microsoft.NETCore.App</PackageId>
</XmlUpdateStep>
- <XmlUpdateStep Include="CoreSetup">
- <Path>$(MSBuildThisFileFullPath)</Path>
- <ElementName>MicrosoftDotNetPlatformAbstractionsPackageVersion</ElementName>
- <PackageId>Microsoft.DotNet.PlatformAbstractions</PackageId>
- </XmlUpdateStep>
<UpdateStep Include="BuildTools">
<UpdaterType>File</UpdaterType>
<Path>$(MSBuildThisFileDirectory)BuildToolsVersion.txt</Path>
diff --git a/external/test-runtime/XUnit.Runtime.depproj b/external/test-runtime/XUnit.Runtime.depproj
index 8e8f63db98..2b96e94ba3 100644
--- a/external/test-runtime/XUnit.Runtime.depproj
+++ b/external/test-runtime/XUnit.Runtime.depproj
@@ -51,7 +51,7 @@
<Version>0.10.0-alpha-experimental</Version>
</PackageReference>
<PackageReference Condition="'$(TargetGroup)' != 'uapaot'" Include="Microsoft.DotNet.PlatformAbstractions">
- <Version>$(MicrosoftDotNetPlatformAbstractionsPackageVersion)</Version>
+ <Version>2.0.4</Version>
</PackageReference>
<PackageReference Include="CommandLineParser">
<Version>2.1.1-beta</Version>
diff --git a/external/test-runtime/optional.json b/external/test-runtime/optional.json
index b399048807..777514af15 100644
--- a/external/test-runtime/optional.json
+++ b/external/test-runtime/optional.json
@@ -3,9 +3,9 @@
"net45": {
"dependencies": {
"Microsoft.DotNet.IBCMerge": "4.6.0-alpha-00001",
- "TestILC.amd64ret": "1.0.0-beta-26329-00",
- "TestILC.armret": "1.0.0-beta-26329-00",
- "TestILC.x86ret": "1.0.0-beta-26329-00"
+ "TestILC.amd64ret": "1.0.0-beta-26330-00",
+ "TestILC.armret": "1.0.0-beta-26330-00",
+ "TestILC.x86ret": "1.0.0-beta-26330-00"
}
}
}
diff --git a/pkg/Microsoft.Private.PackageBaseline/packageIndex.json b/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
index ea787d868e..c80d67c06a 100644
--- a/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
+++ b/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
@@ -1238,7 +1238,7 @@
"monotouch10": "Any",
"net461": "4.1.0.0",
"uap10.0.16299": "4.3.0.0",
- "uap10.0.16300": "4.3.1.0",
+ "uap10.0.16300": "4.4.0.0",
"xamarinios10": "Any",
"xamarinmac20": "Any",
"xamarintvos10": "Any",
@@ -1249,7 +1249,7 @@
"4.1.0.0": "4.1.0",
"4.1.1.0": "4.3.0",
"4.2.0.0": "4.4.0",
- "4.3.1.0": "4.5.0"
+ "4.4.0.0": "4.5.0"
}
},
"System.Data.SqlXml": {
diff --git a/pkg/test/packageSettings/System.IO.Packaging/netcoreapp1.0/workaroundDowngrade.targets b/pkg/test/packageSettings/System.IO.Packaging/netcoreapp1.0/workaroundDowngrade.targets
new file mode 100644
index 0000000000..1ec61540e4
--- /dev/null
+++ b/pkg/test/packageSettings/System.IO.Packaging/netcoreapp1.0/workaroundDowngrade.targets
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <!-- issue https://github.com/dotnet/corefx/issues/28551 -->
+ <PackageReference Include="NETStandard.Library" Version="1.6.1" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/pkg/test/packageSettings/System.Security.Cryptography.Pkcs/netcoreapp1.0/workaroundDowngrade.targets b/pkg/test/packageSettings/System.Security.Cryptography.Pkcs/netcoreapp1.0/workaroundDowngrade.targets
new file mode 100644
index 0000000000..1ec61540e4
--- /dev/null
+++ b/pkg/test/packageSettings/System.Security.Cryptography.Pkcs/netcoreapp1.0/workaroundDowngrade.targets
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <!-- issue https://github.com/dotnet/corefx/issues/28551 -->
+ <PackageReference Include="NETStandard.Library" Version="1.6.1" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems b/src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems
index 1143580173..d5c432e128 100644
--- a/src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems
+++ b/src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems
@@ -46,9 +46,10 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\ArrayPool.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\ArrayPoolEventSource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\ConfigurableArrayPool.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\IRetainable.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\IMemoryOwner.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\IPinnable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\MemoryHandle.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\OwnedMemory.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Buffers\MemoryManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\TlsOverPerCoreLockedStacksArrayPool.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Buffers\Utilities.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Byte.cs" />
diff --git a/src/Common/src/CoreLib/System/Buffers/IMemoryOwner.cs b/src/Common/src/CoreLib/System/Buffers/IMemoryOwner.cs
new file mode 100644
index 0000000000..a796fbbadf
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Buffers/IMemoryOwner.cs
@@ -0,0 +1,18 @@
+// 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.
+
+namespace System.Buffers
+{
+ /// <summary>
+ /// Owner of Memory<typeparamref name="T"/> that is responsible for disposing the underlying memory appropriately.
+ /// </summary>
+ public interface IMemoryOwner<T> : IDisposable
+ {
+ /// <summary>
+ /// Returns a Memory<typeparamref name="T"/>.
+ /// </summary>
+ Memory<T> Memory { get; }
+
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Buffers/IPinnable.cs b/src/Common/src/CoreLib/System/Buffers/IPinnable.cs
new file mode 100644
index 0000000000..623e716a05
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Buffers/IPinnable.cs
@@ -0,0 +1,25 @@
+// 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.
+
+namespace System.Buffers
+{
+ /// <summary>
+ /// Provides a mechanism for pinning and unpinning objects to prevent the GC from moving them.
+ /// </summary>
+ public interface IPinnable
+ {
+ /// <summary>
+ /// Call this method to indicate that the IPinnable object can not be moved by the garbage collector.
+ /// The address of the pinned object can be taken.
+ /// <param name="elementIndex">The offset to the element within the memory at which the returned <see cref="MemoryHandle"/> points to.</param>
+ /// </summary>
+ MemoryHandle Pin(int elementIndex);
+
+ /// <summary>
+ /// Call this method to indicate that the IPinnable object no longer needs to be pinned.
+ /// The garbage collector is free to move the object now.
+ /// </summary>
+ void Unpin();
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Buffers/IRetainable.cs b/src/Common/src/CoreLib/System/Buffers/IRetainable.cs
deleted file mode 100644
index 6ac508859c..0000000000
--- a/src/Common/src/CoreLib/System/Buffers/IRetainable.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.Runtime;
-using System.Runtime.CompilerServices;
-
-namespace System.Buffers
-{
- /// <summary>
- /// Provides a mechanism for manual lifetime management.
- /// </summary>
- public interface IRetainable
- {
- /// <summary>
- /// Call this method to indicate that the IRetainable object is in use.
- /// Do not dispose until Release is called.
- /// </summary>
- void Retain();
- /// <summary>
- /// Call this method to indicate that the IRetainable object is no longer in use.
- /// The object can now be disposed.
- /// </summary>
- bool Release();
- }
-} \ No newline at end of file
diff --git a/src/Common/src/CoreLib/System/Buffers/MemoryHandle.cs b/src/Common/src/CoreLib/System/Buffers/MemoryHandle.cs
index 7544038629..8859b49953 100644
--- a/src/Common/src/CoreLib/System/Buffers/MemoryHandle.cs
+++ b/src/Common/src/CoreLib/System/Buffers/MemoryHandle.cs
@@ -12,37 +12,32 @@ namespace System.Buffers
/// </summary>
public unsafe struct MemoryHandle : IDisposable
{
- private IRetainable _retainable;
private void* _pointer;
private GCHandle _handle;
+ private IPinnable _pinnable;
/// <summary>
/// Creates a new memory handle for the memory.
/// </summary>
- /// <param name="retainable">reference to manually managed object</param>
- /// <param name="pointer">pointer to memory, or null if a pointer was not provided when the handle was created</param>
+ /// <param name="pointer">pointer to memory</param>
+ /// <param name="pinnable">reference to manually managed object, or default if there is no memory manager</param>
/// <param name="handle">handle used to pin array buffers</param>
[CLSCompliant(false)]
- public MemoryHandle(IRetainable retainable, void* pointer = null, GCHandle handle = default(GCHandle))
+ public MemoryHandle(void* pointer, GCHandle handle = default, IPinnable pinnable = default)
{
- _retainable = retainable;
_pointer = pointer;
_handle = handle;
+ _pinnable = pinnable;
}
/// <summary>
- /// Returns the pointer to memory, or null if a pointer was not provided when the handle was created.
+ /// Returns the pointer to memory, where the memory is assumed to be pinned and hence the address won't change.
/// </summary>
[CLSCompliant(false)]
public void* Pointer => _pointer;
/// <summary>
- /// Returns false if the pointer to memory is null.
- /// </summary>
- public bool HasPointer => _pointer != null;
-
- /// <summary>
- /// Frees the pinned handle and releases IRetainable.
+ /// Frees the pinned handle and releases IPinnable.
/// </summary>
public void Dispose()
{
@@ -51,14 +46,14 @@ namespace System.Buffers
_handle.Free();
}
- if (_retainable != null)
+ if (_pinnable != null)
{
- _retainable.Release();
- _retainable = null;
+ _pinnable.Unpin();
+ _pinnable = null;
}
_pointer = null;
}
}
-} \ No newline at end of file
+}
diff --git a/src/Common/src/CoreLib/System/Buffers/MemoryManager.cs b/src/Common/src/CoreLib/System/Buffers/MemoryManager.cs
new file mode 100644
index 0000000000..cc47e02a27
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Buffers/MemoryManager.cs
@@ -0,0 +1,66 @@
+// 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.Runtime;
+using System.Runtime.CompilerServices;
+
+namespace System.Buffers
+{
+ /// <summary>
+ /// Manager of Memory<typeparamref name="T"/> that provides the implementation.
+ /// </summary>
+ public abstract class MemoryManager<T> : IMemoryOwner<T>, IPinnable
+ {
+ /// <summary>
+ /// The number of items in the Memory<typeparamref name="T"/>.
+ /// </summary>
+ public virtual int Length => GetSpan().Length;
+
+ /// <summary>
+ /// Returns a Memory<typeparamref name="T"/>.
+ /// </summary>
+ public virtual Memory<T> Memory => new Memory<T>(this, 0, Length);
+
+ /// <summary>
+ /// Returns a span wrapping the underlying memory.
+ /// </summary>
+ public abstract Span<T> GetSpan();
+
+ /// <summary>
+ /// Returns a handle to the memory that has been pinned and hence its address can be taken.
+ /// <param name="elementIndex">The offset to the element within the memory at which the returned <see cref="MemoryHandle"/> points to. (default = 0)</param>
+ /// </summary>
+ public abstract MemoryHandle Pin(int elementIndex = 0);
+
+ /// <summary>
+ /// Lets the garbage collector know that the object is free to be moved now.
+ /// </summary>
+ public abstract void Unpin();
+
+ /// <summary>
+ /// Returns an array segment.
+ /// <remarks>Returns the default array segment if not overriden.</remarks>
+ /// </summary>
+ protected internal virtual bool TryGetArray(out ArraySegment<T> segment)
+ {
+ segment = default;
+ return false;
+ }
+
+ /// <summary>
+ /// Implements IDisposable.
+ /// </summary>
+ void IDisposable.Dispose()
+ {
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Clean up of any leftover managed and unmanaged resources.
+ /// </summary>
+ protected abstract void Dispose(bool disposing);
+
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Buffers/OwnedMemory.cs b/src/Common/src/CoreLib/System/Buffers/OwnedMemory.cs
deleted file mode 100644
index 8acd5b224a..0000000000
--- a/src/Common/src/CoreLib/System/Buffers/OwnedMemory.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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.Runtime;
-using System.Runtime.CompilerServices;
-
-namespace System.Buffers
-{
- /// <summary>
- /// Owner of Memory<typeparamref name="T"/> that provides appropriate lifetime management mechanisms for it.
- /// </summary>
- public abstract class OwnedMemory<T> : IDisposable, IRetainable
- {
- /// <summary>
- /// The number of items in the Memory<typeparamref name="T"/>.
- /// </summary>
- public abstract int Length { get; }
-
- /// <summary>
- /// Returns a span wrapping the underlying memory.
- /// </summary>
- public abstract Span<T> Span { get; }
-
- /// <summary>
- /// Returns a Memory<typeparamref name="T"/> if the underlying memory has not been freed.
- /// </summary>
- /// <exception cref="System.ObjectDisposedException">
- /// Thrown when the underlying memory has already been disposed.
- /// </exception>
- public Memory<T> Memory
- {
- get
- {
- if (IsDisposed)
- {
- ThrowHelper.ThrowObjectDisposedException_MemoryDisposed();
- }
- return new Memory<T>(owner: this, 0, Length);
- }
- }
-
- /// <summary>
- /// Returns a handle for the array that has been pinned and hence its address can be taken
- /// </summary>
- public abstract MemoryHandle Pin(int byteOffset = 0);
-
- /// <summary>
- /// Returns an array segment.
- /// </summary>
- protected internal abstract bool TryGetArray(out ArraySegment<T> segment);
-
- /// <summary>
- /// Implements IDisposable.
- /// </summary>
- /// <exception cref="System.InvalidOperationException">
- /// Throw when there are still retained references to the memory
- /// </exception>
- public void Dispose()
- {
- if (IsRetained)
- {
- ThrowHelper.ThrowInvalidOperationException_OutstandingReferences();
- }
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Clean up of any leftover managed and unmanaged resources.
- /// </summary>
- protected abstract void Dispose(bool disposing);
-
- /// <summary>
- /// Return true if someone is holding a reference to the memory.
- /// </summary>
- protected abstract bool IsRetained { get; }
-
- /// <summary>
- /// Return true if the underlying memory has been freed.
- /// </summary>
- public abstract bool IsDisposed { get; }
-
- /// <summary>
- /// Implements IRetainable. Prevent accidental disposal of the memory.
- /// </summary>
- public abstract void Retain();
-
- /// <summary>
- /// Implements IRetainable. The memory can now be diposed.
- /// </summary>
- public abstract bool Release();
-
- }
-}
diff --git a/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs b/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs
index d299af3ea7..ec72a8c780 100644
--- a/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs
+++ b/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs
@@ -339,7 +339,7 @@ namespace System.Collections.Generic
{
if (entries[i].hashCode >= 0)
{
- array[index + i] = new KeyValuePair<TKey, TValue>(entries[i].key, entries[i].value);
+ array[index++] = new KeyValuePair<TKey, TValue>(entries[i].key, entries[i].value);
}
}
}
@@ -923,7 +923,7 @@ namespace System.Collections.Generic
{
if (entries[i].hashCode >= 0)
{
- dictEntryArray[index + i] = new DictionaryEntry(entries[i].key, entries[i].value);
+ dictEntryArray[index++] = new DictionaryEntry(entries[i].key, entries[i].value);
}
}
}
@@ -943,7 +943,7 @@ namespace System.Collections.Generic
{
if (entries[i].hashCode >= 0)
{
- objects[index + i] = new KeyValuePair<TKey, TValue>(entries[i].key, entries[i].value);
+ objects[index++] = new KeyValuePair<TKey, TValue>(entries[i].key, entries[i].value);
}
}
}
@@ -1317,7 +1317,7 @@ namespace System.Collections.Generic
Entry[] entries = _dictionary._entries;
for (int i = 0; i < count; i++)
{
- if (entries[i].hashCode >= 0) array[index + i] = entries[i].key;
+ if (entries[i].hashCode >= 0) array[index++] = entries[i].key;
}
}
@@ -1377,7 +1377,7 @@ namespace System.Collections.Generic
{
for (int i = 0; i < count; i++)
{
- if (entries[i].hashCode >= 0) objects[index + i] = entries[i].key;
+ if (entries[i].hashCode >= 0) objects[index++] = entries[i].key;
}
}
catch (ArrayTypeMismatchException)
@@ -1506,7 +1506,7 @@ namespace System.Collections.Generic
Entry[] entries = _dictionary._entries;
for (int i = 0; i < count; i++)
{
- if (entries[i].hashCode >= 0) array[index + i] = entries[i].value;
+ if (entries[i].hashCode >= 0) array[index++] = entries[i].value;
}
}
@@ -1566,7 +1566,7 @@ namespace System.Collections.Generic
{
for (int i = 0; i < count; i++)
{
- if (entries[i].hashCode >= 0) objects[index + i] = entries[i].value;
+ if (entries[i].hashCode >= 0) objects[index++] = entries[i].value;
}
}
catch (ArrayTypeMismatchException)
diff --git a/src/Common/src/CoreLib/System/Collections/Generic/List.cs b/src/Common/src/CoreLib/System/Collections/Generic/List.cs
index cc82302628..b8fd8eb5e2 100644
--- a/src/Common/src/CoreLib/System/Collections/Generic/List.cs
+++ b/src/Common/src/CoreLib/System/Collections/Generic/List.cs
@@ -166,12 +166,12 @@ namespace System.Collections.Generic
set
{
- _version++;
if ((uint)index >= (uint)_size)
{
ThrowHelper.ThrowArgumentOutOfRange_IndexException();
}
_items[index] = value;
+ _version++;
}
}
diff --git a/src/Common/src/CoreLib/System/Memory.cs b/src/Common/src/CoreLib/System/Memory.cs
index e1316f8509..5c2f509fd2 100644
--- a/src/Common/src/CoreLib/System/Memory.cs
+++ b/src/Common/src/CoreLib/System/Memory.cs
@@ -28,15 +28,18 @@ namespace System
// as code uses Unsafe.As to cast between them.
// The highest order bit of _index is used to discern whether _object is an array/string or an owned memory
- // if (_index >> 31) == 1, object _object is an OwnedMemory<T>
- // else, object _object is a T[] or a string. It can only be a string if the Memory<T> was created by
+ // if (_index >> 31) == 1, object _object is an MemoryManager<T>
+ // else, object _object is a T[] or a string.
+ // if (_length >> 31) == 1, _object is a pre-pinned array, so Pin() will not allocate a new GCHandle
+ // else, Pin() needs to allocate a new GCHandle to pin the object.
+ // It can only be a string if the Memory<T> was created by
// using unsafe / marshaling code to reinterpret a ReadOnlyMemory<char> wrapped around a string as
// a Memory<T>.
private readonly object _object;
private readonly int _index;
private readonly int _length;
- private const int RemoveOwnedFlagBitMask = 0x7FFFFFFF;
+ private const int RemoveFlagsBitMask = 0x7FFFFFFF;
/// <summary>
/// Creates a new memory over the entirety of the target array.
@@ -112,22 +115,72 @@ namespace System
_length = length;
}
- // Constructor for internal use only.
+ /// <summary>
+ /// Creates a new memory from a memory manager that provides specific method implementations beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
+ /// </summary>
+ /// <param name="manager">The memory manager.</param>
+ /// <param name="start">The index at which to begin the memory.</param>
+ /// <param name="length">The number of items in the memory.</param>
+ /// <remarks>Returns default when <paramref name="manager"/> is null.</remarks>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
+ /// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal Memory(OwnedMemory<T> owner, int index, int length)
+ public Memory(MemoryManager<T> manager, int start, int length)
{
- // No validation performed; caller must provide any necessary validation.
- _object = owner;
- _index = index | (1 << 31); // Before using _index, check if _index < 0, then 'and' it with RemoveOwnedFlagBitMask
+ if (manager == null)
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ this = default;
+ return; // returns default
+ }
+ if ((uint)start > (uint)manager.Length || (uint)length > (uint)(manager.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _object = manager;
+ _index = start | (1 << 31); // Before using _index, check if _index < 0, then 'and' it with RemoveFlagsBitMask
_length = length;
}
+ /// <summary>
+ /// Creates a new memory over the portion of the pre-pinned target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
+ /// </summary>
+ /// <param name="array">The pre-pinned target array.</param>
+ /// <param name="start">The index at which to begin the memory.</param>
+ /// <param name="length">The number of items in the memory.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private Memory(object obj, int index, int length)
+ public static Memory<T> CreateFromPinnedArray(T[] array, int start, int length)
+ {
+ if (array == null)
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ return default;
+ }
+ if (default(T) == null && array.GetType() != typeof(T[]))
+ ThrowHelper.ThrowArrayTypeMismatchException();
+ if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ // Before using _length, check if _length < 0, then 'and' it with RemoveFlagsBitMask
+ return new Memory<T>((object)array, start, length | (1 << 31));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Memory(object obj, int start, int length)
{
// No validation performed; caller must provide any necessary validation.
_object = obj;
- _index = index;
+ _index = start;
_length = length;
}
@@ -155,12 +208,12 @@ namespace System
/// <summary>
/// The number of items in the memory.
/// </summary>
- public int Length => _length;
+ public int Length => _length & RemoveFlagsBitMask;
/// <summary>
/// Returns true if Length is 0.
/// </summary>
- public bool IsEmpty => _length == 0;
+ public bool IsEmpty => (_length & RemoveFlagsBitMask) == 0;
/// <summary>
/// For <see cref="Memory{Char}"/>, returns a new instance of string that represents the characters pointed to by the memory.
@@ -170,9 +223,9 @@ namespace System
{
if (typeof(T) == typeof(char))
{
- return (_object is string str) ? str.Substring(_index, _length) : Span.ToString();
+ return (_object is string str) ? str.Substring(_index, _length & RemoveFlagsBitMask) : Span.ToString();
}
- return string.Format("System.Memory<{0}>[{1}]", typeof(T).Name, _length);
+ return string.Format("System.Memory<{0}>[{1}]", typeof(T).Name, _length & RemoveFlagsBitMask);
}
/// <summary>
@@ -185,12 +238,13 @@ namespace System
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Memory<T> Slice(int start)
{
- if ((uint)start > (uint)_length)
+ int actualLength = _length & RemoveFlagsBitMask;
+ if ((uint)start > (uint)actualLength)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
}
- return new Memory<T>(_object, _index + start, _length - start);
+ return new Memory<T>(_object, _index + start, actualLength - start);
}
/// <summary>
@@ -204,7 +258,8 @@ namespace System
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Memory<T> Slice(int start, int length)
{
- if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
+ int actualLength = _length & RemoveFlagsBitMask;
+ if ((uint)start > (uint)actualLength || (uint)length > (uint)(actualLength - start))
{
ThrowHelper.ThrowArgumentOutOfRangeException();
}
@@ -222,10 +277,12 @@ namespace System
{
if (_index < 0)
{
- return ((OwnedMemory<T>)_object).Span.Slice(_index & RemoveOwnedFlagBitMask, _length);
+ Debug.Assert(_length >= 0);
+ return ((MemoryManager<T>)_object).GetSpan().Slice(_index & RemoveFlagsBitMask, _length);
}
else if (typeof(T) == typeof(char) && _object is string s)
{
+ Debug.Assert(_length >= 0);
// This is dangerous, returning a writable span for a string that should be immutable.
// However, we need to handle the case where a ReadOnlyMemory<char> was created from a string
// and then cast to a Memory<T>. Such a cast can only be done with unsafe or marshaling code,
@@ -239,7 +296,7 @@ namespace System
}
else if (_object != null)
{
- return new Span<T>((T[])_object, _index, _length);
+ return new Span<T>((T[])_object, _index, _length & RemoveFlagsBitMask);
}
else
{
@@ -280,7 +337,7 @@ namespace System
{
if (_index < 0)
{
- return ((OwnedMemory<T>)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf<T>());
+ return ((MemoryManager<T>)_object).Pin((_index & RemoveFlagsBitMask));
}
else if (typeof(T) == typeof(char) && _object is string s)
{
@@ -295,72 +352,21 @@ namespace System
#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
#endif // FEATURE_PORTABLE_SPAN
- return new MemoryHandle(null, pointer, handle);
+ return new MemoryHandle(pointer, handle);
}
else if (_object is T[] array)
{
- var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+ GCHandle handle = _length < 0 ? default : GCHandle.Alloc(array, GCHandleType.Pinned);
#if FEATURE_PORTABLE_SPAN
void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
#endif // FEATURE_PORTABLE_SPAN
- return new MemoryHandle(null, pointer, handle);
+ return new MemoryHandle(pointer, handle);
}
return default;
}
- /// <summary>[Obsolete, use Pin()] Creates a handle for the memory.</summary>
- /// <param name="pin">
- /// If pin is true, the GC will not move the array until the returned <see cref="MemoryHandle"/>
- /// is disposed, enabling taking and using the memory's address.
- /// </param>
- public unsafe MemoryHandle Retain(bool pin = false)
- {
- MemoryHandle memoryHandle = default;
- if (pin)
- {
- if (_index < 0)
- {
- memoryHandle = ((OwnedMemory<T>)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf<T>());
- }
- else if (typeof(T) == typeof(char) && _object is string s)
- {
- // This case can only happen if a ReadOnlyMemory<char> was created around a string
- // and then that was cast to a Memory<char> using unsafe / marshaling code. This needs
- // to work, however, so that code that uses a single Memory<char> field to store either
- // a readable ReadOnlyMemory<char> or a writable Memory<char> can still be pinned and
- // used for interop purposes.
- GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
-#if FEATURE_PORTABLE_SPAN
- void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
-#else
- void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
-#endif // FEATURE_PORTABLE_SPAN
- memoryHandle = new MemoryHandle(null, pointer, handle);
- }
- else if (_object is T[] array)
- {
- var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
-#if FEATURE_PORTABLE_SPAN
- void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
-#else
- void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
-#endif // FEATURE_PORTABLE_SPAN
- memoryHandle = new MemoryHandle(null, pointer, handle);
- }
- }
- else
- {
- if (_index < 0)
- {
- ((OwnedMemory<T>)_object).Retain();
- memoryHandle = new MemoryHandle((OwnedMemory<T>)_object);
- }
- }
- return memoryHandle;
- }
-
/// <summary>
/// Copies the contents from the memory into a new array. This heap
/// allocates, so should generally be avoided, however it is sometimes
diff --git a/src/Common/src/CoreLib/System/MemoryExtensions.Fast.cs b/src/Common/src/CoreLib/System/MemoryExtensions.Fast.cs
index d9e3af8804..d256887a9f 100644
--- a/src/Common/src/CoreLib/System/MemoryExtensions.Fast.cs
+++ b/src/Common/src/CoreLib/System/MemoryExtensions.Fast.cs
@@ -359,6 +359,7 @@ namespace System
/// <summary>
/// Creates a new span over the portion of the target array.
/// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this T[] array, int start)
{
if (array == null)
@@ -380,6 +381,7 @@ namespace System
/// </summary>
/// <param name="text">The target string.</param>
/// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan<char> AsSpan(this string text)
{
if (text == null)
@@ -397,6 +399,7 @@ namespace System
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;text.Length).
/// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan<char> AsSpan(this string text, int start)
{
if (text == null)
@@ -422,6 +425,7 @@ namespace System
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
/// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan<char> AsSpan(this string text, int start, int length)
{
if (text == null)
diff --git a/src/Common/src/CoreLib/System/MemoryExtensions.cs b/src/Common/src/CoreLib/System/MemoryExtensions.cs
index 1a3b33acc7..c3e1cd51fa 100644
--- a/src/Common/src/CoreLib/System/MemoryExtensions.cs
+++ b/src/Common/src/CoreLib/System/MemoryExtensions.cs
@@ -68,7 +68,6 @@ namespace System
/// </summary>
/// <param name="span">The source span from which the character is removed.</param>
/// <param name="trimChar">The specified character to look for and remove.</param>
- //[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span, char trimChar)
{
return span.TrimStart(trimChar).TrimEnd(trimChar);
@@ -79,7 +78,6 @@ namespace System
/// </summary>
/// <param name="span">The source span from which the character is removed.</param>
/// <param name="trimChar">The specified character to look for and remove.</param>
- //[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ReadOnlySpan<char> TrimStart(this ReadOnlySpan<char> span, char trimChar)
{
int start = 0;
@@ -1204,7 +1202,7 @@ namespace System
/// no larger element, the bitwise complement of <see cref="Span{T}.Length"/>.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
+ /// <paramref name = "comparable" /> is <see langword="null"/> .
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int BinarySearch<T>(
@@ -1228,7 +1226,7 @@ namespace System
/// no larger element, the bitwise complement of <see cref="Span{T}.Length"/>.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
+ /// <paramref name = "comparable" /> is <see langword="null"/> .
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int BinarySearch<T, TComparable>(
@@ -1278,7 +1276,7 @@ namespace System
/// no larger element, the bitwise complement of <see cref="ReadOnlySpan{T}.Length"/>.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
+ /// <paramref name = "comparable" /> is <see langword="null"/> .
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int BinarySearch<T>(
@@ -1302,7 +1300,7 @@ namespace System
/// no larger element, the bitwise complement of <see cref="ReadOnlySpan{T}.Length"/>.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
+ /// <paramref name = "comparable" /> is <see langword="null"/> .
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int BinarySearch<T, TComparable>(
diff --git a/src/Common/src/CoreLib/System/ReadOnlyMemory.cs b/src/Common/src/CoreLib/System/ReadOnlyMemory.cs
index 5385ceca76..c92f842062 100644
--- a/src/Common/src/CoreLib/System/ReadOnlyMemory.cs
+++ b/src/Common/src/CoreLib/System/ReadOnlyMemory.cs
@@ -28,13 +28,15 @@ namespace System
// as code uses Unsafe.As to cast between them.
// The highest order bit of _index is used to discern whether _object is an array/string or an owned memory
- // if (_index >> 31) == 1, _object is an OwnedMemory<T>
- // else, _object is a T[] or string
+ // if (_index >> 31) == 1, _object is an MemoryManager<T>
+ // else, _object is a T[] or string.
+ // if (_length >> 31) == 1, _object is a pre-pinned array, so Pin() will not allocate a new GCHandle
+ // else, Pin() needs to allocate a new GCHandle to pin the object.
private readonly object _object;
private readonly int _index;
private readonly int _length;
- internal const int RemoveOwnedFlagBitMask = 0x7FFFFFFF;
+ internal const int RemoveFlagsBitMask = 0x7FFFFFFF;
/// <summary>
/// Creates a new memory over the entirety of the target array.
@@ -117,12 +119,12 @@ namespace System
/// <summary>
/// The number of items in the memory.
/// </summary>
- public int Length => _length;
+ public int Length => _length & RemoveFlagsBitMask;
/// <summary>
/// Returns true if Length is 0.
/// </summary>
- public bool IsEmpty => _length == 0;
+ public bool IsEmpty => (_length & RemoveFlagsBitMask) == 0;
/// <summary>
/// For <see cref="ReadOnlyMemory{Char}"/>, returns a new instance of string that represents the characters pointed to by the memory.
@@ -132,9 +134,9 @@ namespace System
{
if (typeof(T) == typeof(char))
{
- return (_object is string str) ? str.Substring(_index, _length) : Span.ToString();
+ return (_object is string str) ? str.Substring(_index, _length & RemoveFlagsBitMask) : Span.ToString();
}
- return string.Format("System.ReadOnlyMemory<{0}>[{1}]", typeof(T).Name, _length);
+ return string.Format("System.ReadOnlyMemory<{0}>[{1}]", typeof(T).Name, _length & RemoveFlagsBitMask);
}
/// <summary>
@@ -147,12 +149,13 @@ namespace System
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlyMemory<T> Slice(int start)
{
- if ((uint)start > (uint)_length)
+ int actualLength = _length & RemoveFlagsBitMask;
+ if ((uint)start > (uint)actualLength)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
}
- return new ReadOnlyMemory<T>(_object, _index + start, _length - start);
+ return new ReadOnlyMemory<T>(_object, _index + start, actualLength - start);
}
/// <summary>
@@ -166,7 +169,8 @@ namespace System
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlyMemory<T> Slice(int start, int length)
{
- if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
+ int actualLength = _length & RemoveFlagsBitMask;
+ if ((uint)start > (uint)actualLength || (uint)length > (uint)(actualLength - start))
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
}
@@ -184,10 +188,12 @@ namespace System
{
if (_index < 0)
{
- return ((OwnedMemory<T>)_object).Span.Slice(_index & RemoveOwnedFlagBitMask, _length);
+ Debug.Assert(_length >= 0);
+ return ((MemoryManager<T>)_object).GetSpan().Slice(_index & RemoveFlagsBitMask, _length);
}
else if (typeof(T) == typeof(char) && _object is string s)
{
+ Debug.Assert(_length >= 0);
#if FEATURE_PORTABLE_SPAN
return new ReadOnlySpan<T>(Unsafe.As<Pinnable<T>>(s), MemoryExtensions.StringAdjustment, s.Length).Slice(_index, _length);
#else
@@ -196,7 +202,7 @@ namespace System
}
else if (_object != null)
{
- return new ReadOnlySpan<T>((T[])_object, _index, _length);
+ return new ReadOnlySpan<T>((T[])_object, _index, _length & RemoveFlagsBitMask);
}
else
{
@@ -237,7 +243,7 @@ namespace System
{
if (_index < 0)
{
- return ((OwnedMemory<T>)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf<T>());
+ return ((MemoryManager<T>)_object).Pin((_index & RemoveFlagsBitMask));
}
else if (typeof(T) == typeof(char) && _object is string s)
{
@@ -247,67 +253,21 @@ namespace System
#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
#endif // FEATURE_PORTABLE_SPAN
- return new MemoryHandle(null, pointer, handle);
+ return new MemoryHandle(pointer, handle);
}
else if (_object is T[] array)
{
- var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+ GCHandle handle = _length < 0 ? default : GCHandle.Alloc(array, GCHandleType.Pinned);
#if FEATURE_PORTABLE_SPAN
void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
#else
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
#endif // FEATURE_PORTABLE_SPAN
- return new MemoryHandle(null, pointer, handle);
+ return new MemoryHandle(pointer, handle);
}
return default;
}
- /// <summary>[Obsolete, use Pin()] Creates a handle for the memory.</summary>
- /// <param name="pin">
- /// If pin is true, the GC will not move the array until the returned <see cref="MemoryHandle"/>
- /// is disposed, enabling taking and using the memory's address.
- /// </param>
- public unsafe MemoryHandle Retain(bool pin = false)
- {
- MemoryHandle memoryHandle = default;
- if (pin)
- {
- if (_index < 0)
- {
- memoryHandle = ((OwnedMemory<T>)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf<T>());
- }
- else if (typeof(T) == typeof(char) && _object is string s)
- {
- GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
-#if FEATURE_PORTABLE_SPAN
- void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
-#else
- void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
-#endif // FEATURE_PORTABLE_SPAN
- memoryHandle = new MemoryHandle(null, pointer, handle);
- }
- else if (_object is T[] array)
- {
- var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
-#if FEATURE_PORTABLE_SPAN
- void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
-#else
- void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
-#endif // FEATURE_PORTABLE_SPAN
- memoryHandle = new MemoryHandle(null, pointer, handle);
- }
- }
- else
- {
- if (_index < 0)
- {
- ((OwnedMemory<T>)_object).Retain();
- memoryHandle = new MemoryHandle((OwnedMemory<T>)_object);
- }
- }
- return memoryHandle;
- }
-
/// <summary>
/// Copies the contents from the memory into a new array. This heap
/// allocates, so should generally be avoided, however it is sometimes
diff --git a/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs b/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs
index b4b17b0370..073dd76cdc 100644
--- a/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs
+++ b/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs
@@ -5,6 +5,7 @@
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Collections.Generic;
+using System.Diagnostics;
#if !netstandard
using Internal.Runtime.CompilerServices;
@@ -27,19 +28,20 @@ namespace System.Runtime.InteropServices
object obj = memory.GetObjectStartLength(out int index, out int length);
if (index < 0)
{
- if (((OwnedMemory<T>)obj).TryGetArray(out ArraySegment<T> arraySegment))
+ Debug.Assert(length >= 0);
+ if (((MemoryManager<T>)obj).TryGetArray(out ArraySegment<T> arraySegment))
{
- segment = new ArraySegment<T>(arraySegment.Array, arraySegment.Offset + (index & ReadOnlyMemory<T>.RemoveOwnedFlagBitMask), length);
+ segment = new ArraySegment<T>(arraySegment.Array, arraySegment.Offset + (index & ReadOnlyMemory<T>.RemoveFlagsBitMask), length);
return true;
}
}
else if (obj is T[] arr)
{
- segment = new ArraySegment<T>(arr, index, length);
+ segment = new ArraySegment<T>(arr, index, length & ReadOnlyMemory<T>.RemoveFlagsBitMask);
return true;
}
- if (length == 0)
+ if ((length & ReadOnlyMemory<T>.RemoveFlagsBitMask) == 0)
{
#if FEATURE_PORTABLE_SPAN
segment = new ArraySegment<T>(SpanHelpers.PerTypeValues<T>.EmptyArray);
@@ -54,40 +56,49 @@ namespace System.Runtime.InteropServices
}
/// <summary>
- /// Gets an <see cref="OwnedMemory{T}"/> from the underlying read-only memory.
- /// If unable to get the <typeparamref name="TOwner"/> type, returns false.
+ /// Gets an <see cref="MemoryManager{T}"/> from the underlying read-only memory.
+ /// If unable to get the <typeparamref name="TManager"/> type, returns false.
/// </summary>
/// <typeparam name="T">The element type of the <paramref name="memory" />.</typeparam>
- /// <typeparam name="TOwner">The type of <see cref="OwnedMemory{T}"/> to try and retrive.</typeparam>
- /// <param name="memory">The memory to get the owner for.</param>
- /// <param name="owner">The returned owner of the <see cref="ReadOnlyMemory{T}"/>.</param>
+ /// <typeparam name="TManager">The type of <see cref="MemoryManager{T}"/> to try and retrive.</typeparam>
+ /// <param name="memory">The memory to get the manager for.</param>
+ /// <param name="manager">The returned manager of the <see cref="ReadOnlyMemory{T}"/>.</param>
/// <returns>A <see cref="bool"/> indicating if it was successful.</returns>
- public static bool TryGetOwnedMemory<T, TOwner>(ReadOnlyMemory<T> memory, out TOwner owner)
- where TOwner : OwnedMemory<T>
+ public static bool TryGetMemoryManager<T, TManager>(ReadOnlyMemory<T> memory, out TManager manager)
+ where TManager : MemoryManager<T>
{
- TOwner localOwner; // Use register for null comparison rather than byref
- owner = localOwner = memory.GetObjectStartLength(out int index, out int length) as TOwner;
- return !ReferenceEquals(owner, null);
+ TManager localManager; // Use register for null comparison rather than byref
+ manager = localManager = memory.GetObjectStartLength(out _, out _) as TManager;
+ return !ReferenceEquals(manager, null);
}
/// <summary>
- /// Gets an <see cref="OwnedMemory{T}"/> and <paramref name="start" />, <paramref name="length" /> from the underlying read-only memory.
- /// If unable to get the <typeparamref name="TOwner"/> type, returns false.
+ /// Gets an <see cref="MemoryManager{T}"/> and <paramref name="start" />, <paramref name="length" /> from the underlying read-only memory.
+ /// If unable to get the <typeparamref name="TManager"/> type, returns false.
/// </summary>
/// <typeparam name="T">The element type of the <paramref name="memory" />.</typeparam>
- /// <typeparam name="TOwner">The type of <see cref="OwnedMemory{T}"/> to try and retrive.</typeparam>
- /// <param name="memory">The memory to get the owner for.</param>
- /// <param name="owner">The returned owner of the <see cref="ReadOnlyMemory{T}"/>.</param>
- /// <param name="start">The offset from the start of the <paramref name="owner" /> that the <paramref name="memory" /> represents.</param>
- /// <param name="length">The length of the <paramref name="owner" /> that the <paramref name="memory" /> represents.</param>
+ /// <typeparam name="TManager">The type of <see cref="MemoryManager{T}"/> to try and retrive.</typeparam>
+ /// <param name="memory">The memory to get the manager for.</param>
+ /// <param name="manager">The returned manager of the <see cref="ReadOnlyMemory{T}"/>.</param>
+ /// <param name="start">The offset from the start of the <paramref name="manager" /> that the <paramref name="memory" /> represents.</param>
+ /// <param name="length">The length of the <paramref name="manager" /> that the <paramref name="memory" /> represents.</param>
/// <returns>A <see cref="bool"/> indicating if it was successful.</returns>
- public static bool TryGetOwnedMemory<T, TOwner>(ReadOnlyMemory<T> memory, out TOwner owner, out int start, out int length)
- where TOwner : OwnedMemory<T>
+ public static bool TryGetMemoryManager<T, TManager>(ReadOnlyMemory<T> memory, out TManager manager, out int start, out int length)
+ where TManager : MemoryManager<T>
{
- TOwner localOwner; // Use register for null comparison rather than byref
- owner = localOwner = memory.GetObjectStartLength(out start, out length) as TOwner;
- start &= ReadOnlyMemory<T>.RemoveOwnedFlagBitMask;
- return !ReferenceEquals(owner, null);
+ TManager localManager; // Use register for null comparison rather than byref
+ manager = localManager = memory.GetObjectStartLength(out start, out length) as TManager;
+ start &= ReadOnlyMemory<T>.RemoveFlagsBitMask;
+
+ Debug.Assert(length >= 0);
+
+ if (ReferenceEquals(manager, null))
+ {
+ start = default;
+ length = default;
+ return false;
+ }
+ return true;
}
/// <summary>
@@ -113,6 +124,8 @@ namespace System.Runtime.InteropServices
{
if (memory.GetObjectStartLength(out int offset, out int count) is string s)
{
+ Debug.Assert(offset >= 0);
+ Debug.Assert(count >= 0);
text = s;
start = offset;
length = count;
diff --git a/src/Common/src/CoreLib/System/SpanHelpers.Char.cs b/src/Common/src/CoreLib/System/SpanHelpers.Char.cs
index 2033d8b906..47e83b7b26 100644
--- a/src/Common/src/CoreLib/System/SpanHelpers.Char.cs
+++ b/src/Common/src/CoreLib/System/SpanHelpers.Char.cs
@@ -84,79 +84,87 @@ namespace System
{
Debug.Assert(length >= 0);
- uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr nLength = (IntPtr)length;
-#if !netstandard11
- if (Vector.IsHardwareAccelerated && length >= Vector<ushort>.Count * 2)
+ fixed (char* pChars = &searchSpace)
{
- const int elementsPerByte = sizeof(ushort) / sizeof(byte);
- int unaligned = ((int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1)) / elementsPerByte;
- nLength = (IntPtr)((Vector<ushort>.Count - unaligned) & (Vector<ushort>.Count - 1));
- }
- SequentialScan:
+ char* pCh = pChars;
+ char* pEndCh = pCh + length;
+
+#if !netstandard11
+ if (Vector.IsHardwareAccelerated && length >= Vector<ushort>.Count * 2)
+ {
+ const int elementsPerByte = sizeof(ushort) / sizeof(byte);
+ int unaligned = ((int)pCh & (Unsafe.SizeOf<Vector<ushort>>() - 1)) / elementsPerByte;
+ length = ((Vector<ushort>.Count - unaligned) & (Vector<ushort>.Count - 1));
+ }
+ SequentialScan:
#endif
- while ((byte*)nLength >= (byte*)4)
- {
- nLength -= 4;
-
- if (uValue == Unsafe.Add(ref searchSpace, index))
- goto Found;
- if (uValue == Unsafe.Add(ref searchSpace, index + 1))
- goto Found1;
- if (uValue == Unsafe.Add(ref searchSpace, index + 2))
- goto Found2;
- if (uValue == Unsafe.Add(ref searchSpace, index + 3))
- goto Found3;
-
- index += 4;
- }
+ while (length >= 4)
+ {
+ length -= 4;
+
+ if (*pCh == value)
+ goto Found;
+ if (*(pCh + 1) == value)
+ goto Found1;
+ if (*(pCh + 2) == value)
+ goto Found2;
+ if (*(pCh + 3) == value)
+ goto Found3;
+
+ pCh += 4;
+ }
- while ((byte*)nLength > (byte*)0)
- {
- nLength -= 1;
+ while (length > 0)
+ {
+ length -= 1;
- if (uValue == Unsafe.Add(ref searchSpace, index))
- goto Found;
+ if (*pCh == value)
+ goto Found;
- index += 1;
- }
+ pCh += 1;
+ }
#if !netstandard11
- if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length))
- {
- nLength = (IntPtr)((length - (int)(byte*)index) & ~(Vector<ushort>.Count - 1));
+ // We get past SequentialScan only if IsHardwareAccelerated is true. However, we still have the redundant check to allow
+ // the JIT to see that the code is unreachable and eliminate it when the platform does not have hardware accelerated.
+ if (Vector.IsHardwareAccelerated && pCh < pEndCh)
+ {
+ length = (int)((pEndCh - pCh) & ~(Vector<ushort>.Count - 1));
- // Get comparison Vector
- Vector<ushort> vComparison = new Vector<ushort>(value);
+ // Get comparison Vector
+ Vector<ushort> vComparison = new Vector<ushort>(value);
- while ((byte*)nLength > (byte*)index)
- {
- var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned<Vector<ushort>>(ref Unsafe.As<char, byte>(ref Unsafe.Add(ref searchSpace, index))));
- if (Vector<ushort>.Zero.Equals(vMatches))
+ while (length > 0)
{
- index += Vector<ushort>.Count;
- continue;
+ // Using Unsafe.Read instead of ReadUnaligned since the search space is pinned and pCh is always vector aligned
+ Debug.Assert(((int)pCh & (Unsafe.SizeOf<Vector<ushort>>() - 1)) == 0);
+ Vector<ushort> vMatches = Vector.Equals(vComparison, Unsafe.Read<Vector<ushort>>(pCh));
+ if (Vector<ushort>.Zero.Equals(vMatches))
+ {
+ pCh += Vector<ushort>.Count;
+ length -= Vector<ushort>.Count;
+ continue;
+ }
+ // Find offset of first match
+ return (int)(pCh - pChars) + LocateFirstFoundChar(vMatches);
}
- // Find offset of first match
- return (int)(byte*)index + LocateFirstFoundChar(vMatches);
- }
- if ((int)(byte*)index < length)
- {
- nLength = (IntPtr)(length - (int)(byte*)index);
- goto SequentialScan;
+ if (pCh < pEndCh)
+ {
+ length = (int)(pEndCh - pCh);
+ goto SequentialScan;
+ }
}
- }
#endif
- return -1;
- Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
- return (int)(byte*)index;
- Found1:
- return (int)(byte*)(index + 1);
- Found2:
- return (int)(byte*)(index + 2);
- Found3:
- return (int)(byte*)(index + 3);
+ return -1;
+ Found3:
+ pCh++;
+ Found2:
+ pCh++;
+ Found1:
+ pCh++;
+ Found:
+ return (int)(pCh - pChars);
+ }
}
#if !netstandard11
diff --git a/src/Common/src/CoreLib/System/String.Searching.cs b/src/Common/src/CoreLib/System/String.Searching.cs
index cc6e218d8d..a4e5bbb62e 100644
--- a/src/Common/src/CoreLib/System/String.Searching.cs
+++ b/src/Common/src/CoreLib/System/String.Searching.cs
@@ -35,10 +35,7 @@ namespace System
// Returns the index of the first occurrence of a specified character in the current instance.
// The search starts at startIndex and runs thorough the next count characters.
//
- public int IndexOf(char value)
- {
- return IndexOf(value, 0, this.Length);
- }
+ public int IndexOf(char value) => SpanHelpers.IndexOf(ref _firstChar, value, Length);
public int IndexOf(char value, int startIndex)
{
@@ -74,122 +71,19 @@ namespace System
public unsafe int IndexOf(char value, int startIndex, int count)
{
+ // These bounds checks are redundant since AsSpan does them already, but are required
+ // so that the correct parameter name is thrown as part of the exception.
if ((uint)startIndex > (uint)Length)
throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
if ((uint)count > (uint)(Length - startIndex))
throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
- fixed (char* pChars = &_firstChar)
- {
- char* pCh = pChars + startIndex;
- char* pEndCh = pCh + count;
-
- if (Vector.IsHardwareAccelerated && count >= Vector<ushort>.Count * 2)
- {
- unchecked
- {
- const int elementsPerByte = sizeof(ushort) / sizeof(byte);
- int unaligned = ((int)pCh & (Vector<byte>.Count - 1)) / elementsPerByte;
- count = ((Vector<ushort>.Count - unaligned) & (Vector<ushort>.Count - 1));
- }
- }
- SequentialScan:
- while (count >= 4)
- {
- if (*pCh == value) goto ReturnIndex;
- if (*(pCh + 1) == value) goto ReturnIndex1;
- if (*(pCh + 2) == value) goto ReturnIndex2;
- if (*(pCh + 3) == value) goto ReturnIndex3;
-
- count -= 4;
- pCh += 4;
- }
-
- while (count > 0)
- {
- if (*pCh == value)
- goto ReturnIndex;
-
- count--;
- pCh++;
- }
-
- if (pCh < pEndCh)
- {
- count = (int)((pEndCh - pCh) & ~(Vector<ushort>.Count - 1));
- // Get comparison Vector
- Vector<ushort> vComparison = new Vector<ushort>(value);
- while (count > 0)
- {
- var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned<Vector<ushort>>(pCh));
- if (Vector<ushort>.Zero.Equals(vMatches))
- {
- pCh += Vector<ushort>.Count;
- count -= Vector<ushort>.Count;
- continue;
- }
- // Find offset of first match
- return (int)(pCh - pChars) + LocateFirstFoundChar(vMatches);
- }
-
- if (pCh < pEndCh)
- {
- unchecked
- {
- count = (int)(pEndCh - pCh);
- }
- goto SequentialScan;
- }
- }
-
- return -1;
+ int result = SpanHelpers.IndexOf(ref Unsafe.Add(ref _firstChar, startIndex), value, count);
- ReturnIndex3: pCh++;
- ReturnIndex2: pCh++;
- ReturnIndex1: pCh++;
- ReturnIndex:
- return (int)(pCh - pChars);
- }
+ return result == -1 ? result : result + startIndex;
}
- // Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int LocateFirstFoundChar(Vector<ushort> match)
- {
- var vector64 = Vector.AsVectorUInt64(match);
- ulong candidate = 0;
- int i = 0;
- // Pattern unrolled by jit https://github.com/dotnet/coreclr/pull/8001
- for (; i < Vector<ulong>.Count; i++)
- {
- candidate = vector64[i];
- if (candidate != 0)
- {
- break;
- }
- }
-
- // Single LEA instruction with jitted const (using function result)
- return i * 4 + LocateFirstFoundChar(candidate);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int LocateFirstFoundChar(ulong match)
- {
- unchecked
- {
- // Flag least significant power of two bit
- var powerOfTwoFlag = match ^ (match - 1);
- // Shift all powers of two into the high byte and extract
- return (int)((powerOfTwoFlag * XorPowerOfTwoToHighChar) >> 49);
- }
- }
-
- private const ulong XorPowerOfTwoToHighChar = (0x03ul |
- 0x02ul << 16 |
- 0x01ul << 32) + 1;
-
// Returns the index of the first occurrence of any specified character in the current instance.
// The search starts at startIndex and runs to startIndex + count - 1.
//
diff --git a/src/Common/src/CoreLib/System/String.cs b/src/Common/src/CoreLib/System/String.cs
index a1251d6be0..42d21ba068 100644
--- a/src/Common/src/CoreLib/System/String.cs
+++ b/src/Common/src/CoreLib/System/String.cs
@@ -360,6 +360,7 @@ namespace System
return result;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlySpan<char>(string value) =>
value != null ? new ReadOnlySpan<char>(ref value.GetRawStringData(), value.Length) : default;
diff --git a/src/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs b/src/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs
index 5f6c576883..ab3200b333 100644
--- a/src/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs
+++ b/src/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs
@@ -161,6 +161,8 @@ internal static partial class Interop
internal enum CurlSslVersion
{
CURL_SSLVERSION_TLSv1 = 1, /* TLS 1.x */
+ CURL_SSLVERSION_SSLv2 = 2, /* SSL 2 */
+ CURL_SSLVERSION_SSLv3 = 3, /* SSL 3 */
CURL_SSLVERSION_TLSv1_0 = 4, /* TLS 1.0 */
CURL_SSLVERSION_TLSv1_1 = 5, /* TLS 1.1 */
CURL_SSLVERSION_TLSv1_2 = 6, /* TLS 1.2 */
diff --git a/src/Common/src/Interop/Windows/SChannel/Interop.SchProtocols.cs b/src/Common/src/Interop/Windows/SChannel/Interop.SchProtocols.cs
index a5185d3feb..c94bd92383 100644
--- a/src/Common/src/Interop/Windows/SChannel/Interop.SchProtocols.cs
+++ b/src/Common/src/Interop/Windows/SChannel/Interop.SchProtocols.cs
@@ -9,8 +9,6 @@ internal static partial class Interop
// Most constants below are taken from schannel.h; those that are not are
// called out explicitly.
- // IMPORTANT: SSL2 and SSL3 definitions are required for System.Net.Primitives enum definitions only.
- // These values should NOT be used in Schannel setup.
public const int SP_PROT_SSL2_SERVER = 0x00000004;
public const int SP_PROT_SSL2_CLIENT = 0x00000008;
public const int SP_PROT_SSL2 = (SP_PROT_SSL2_SERVER | SP_PROT_SSL2_CLIENT);
@@ -34,7 +32,7 @@ internal static partial class Interop
public const int SP_PROT_NONE = 0;
// These two constants are not taken from schannel.h.
- public const int ClientProtocolMask = (SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT);
- public const int ServerProtocolMask = (SP_PROT_TLS1_0_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_2_SERVER);
+ public const int ClientProtocolMask = (SP_PROT_SSL2_CLIENT | SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT);
+ public const int ServerProtocolMask = (SP_PROT_SSL2_SERVER | SP_PROT_SSL3_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_2_SERVER);
}
}
diff --git a/src/Common/src/System/Collections/Concurrent/ConcurrentQueue_Segment.cs b/src/Common/src/System/Collections/Concurrent/ConcurrentQueue_Segment.cs
new file mode 100644
index 0000000000..a85817776c
--- /dev/null
+++ b/src/Common/src/System/Collections/Concurrent/ConcurrentQueue_Segment.cs
@@ -0,0 +1,335 @@
+// 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.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace System.Collections.Concurrent
+{
+ partial class ConcurrentQueue<T>
+ {
+ /// <summary>
+ /// Provides a multi-producer, multi-consumer thread-safe bounded segment. When the queue is full,
+ /// enqueues fail and return false. When the queue is empty, dequeues fail and return null.
+ /// These segments are linked together to form the unbounded <see cref="ConcurrentQueue{T}"/>.
+ /// </summary>
+ [DebuggerDisplay("Capacity = {Capacity}")]
+ internal sealed class Segment
+ {
+ // Segment design is inspired by the algorithm outlined at:
+ // http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
+
+ /// <summary>The array of items in this queue. Each slot contains the item in that slot and its "sequence number".</summary>
+ internal readonly Slot[] _slots;
+ /// <summary>Mask for quickly accessing a position within the queue's array.</summary>
+ internal readonly int _slotsMask;
+ /// <summary>The head and tail positions, with padding to help avoid false sharing contention.</summary>
+ /// <remarks>Dequeuing happens from the head, enqueuing happens at the tail.</remarks>
+ internal PaddedHeadAndTail _headAndTail; // mutable struct: do not make this readonly
+
+ /// <summary>Indicates whether the segment has been marked such that dequeues don't overwrite the removed data.</summary>
+ internal bool _preservedForObservation;
+ /// <summary>Indicates whether the segment has been marked such that no additional items may be enqueued.</summary>
+ internal bool _frozenForEnqueues;
+#pragma warning disable 0649 // some builds don't assign to this field
+ /// <summary>The segment following this one in the queue, or null if this segment is the last in the queue.</summary>
+ internal Segment _nextSegment;
+#pragma warning restore 0649
+
+ /// <summary>Creates the segment.</summary>
+ /// <param name="boundedLength">
+ /// The maximum number of elements the segment can contain. Must be a power of 2.
+ /// </param>
+ public Segment(int boundedLength)
+ {
+ // Validate the length
+ Debug.Assert(boundedLength >= 2, $"Must be >= 2, got {boundedLength}");
+ Debug.Assert((boundedLength & (boundedLength - 1)) == 0, $"Must be a power of 2, got {boundedLength}");
+
+ // Initialize the slots and the mask. The mask is used as a way of quickly doing "% _slots.Length",
+ // instead letting us do "& _slotsMask".
+ _slots = new Slot[boundedLength];
+ _slotsMask = boundedLength - 1;
+
+ // Initialize the sequence number for each slot. The sequence number provides a ticket that
+ // allows dequeuers to know whether they can dequeue and enqueuers to know whether they can
+ // enqueue. An enqueuer at position N can enqueue when the sequence number is N, and a dequeuer
+ // for position N can dequeue when the sequence number is N + 1. When an enqueuer is done writing
+ // at position N, it sets the sequence number to N + 1 so that a dequeuer will be able to dequeue,
+ // and when a dequeuer is done dequeueing at position N, it sets the sequence number to N + _slots.Length,
+ // so that when an enqueuer loops around the slots, it'll find that the sequence number at
+ // position N is N. This also means that when an enqueuer finds that at position N the sequence
+ // number is < N, there is still a value in that slot, i.e. the segment is full, and when a
+ // dequeuer finds that the value in a slot is < N + 1, there is nothing currently available to
+ // dequeue. (It is possible for multiple enqueuers to enqueue concurrently, writing into
+ // subsequent slots, and to have the first enqueuer take longer, so that the slots for 1, 2, 3, etc.
+ // may have values, but the 0th slot may still be being filled... in that case, TryDequeue will
+ // return false.)
+ for (int i = 0; i < _slots.Length; i++)
+ {
+ _slots[i].SequenceNumber = i;
+ }
+ }
+
+ /// <summary>Round the specified value up to the next power of 2, if it isn't one already.</summary>
+ internal static int RoundUpToPowerOf2(int i)
+ {
+ // Based on https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+ --i;
+ i |= i >> 1;
+ i |= i >> 2;
+ i |= i >> 4;
+ i |= i >> 8;
+ i |= i >> 16;
+ return i + 1;
+ }
+
+ /// <summary>Gets the number of elements this segment can store.</summary>
+ internal int Capacity => _slots.Length;
+
+ /// <summary>Gets the "freeze offset" for this segment.</summary>
+ internal int FreezeOffset => _slots.Length * 2;
+
+ /// <summary>
+ /// Ensures that the segment will not accept any subsequent enqueues that aren't already underway.
+ /// </summary>
+ /// <remarks>
+ /// When we mark a segment as being frozen for additional enqueues,
+ /// we set the <see cref="_frozenForEnqueues"/> bool, but that's mostly
+ /// as a small helper to avoid marking it twice. The real marking comes
+ /// by modifying the Tail for the segment, increasing it by this
+ /// <see cref="FreezeOffset"/>. This effectively knocks it off the
+ /// sequence expected by future enqueuers, such that any additional enqueuer
+ /// will be unable to enqueue due to it not lining up with the expected
+ /// sequence numbers. This value is chosen specially so that Tail will grow
+ /// to a value that maps to the same slot but that won't be confused with
+ /// any other enqueue/dequeue sequence number.
+ /// </remarks>
+ internal void EnsureFrozenForEnqueues() // must only be called while queue's segment lock is held
+ {
+ if (!_frozenForEnqueues) // flag used to ensure we don't increase the Tail more than once if frozen more than once
+ {
+ _frozenForEnqueues = true;
+
+ // Increase the tail by FreezeOffset, spinning until we're successful in doing so.
+ var spinner = new SpinWait();
+ while (true)
+ {
+ int tail = Volatile.Read(ref _headAndTail.Tail);
+ if (Interlocked.CompareExchange(ref _headAndTail.Tail, tail + FreezeOffset, tail) == tail)
+ {
+ break;
+ }
+ spinner.SpinOnce();
+ }
+ }
+ }
+
+ /// <summary>Tries to dequeue an element from the queue.</summary>
+ public bool TryDequeue(out T item)
+ {
+ // Loop in case of contention...
+ var spinner = new SpinWait();
+ while (true)
+ {
+ // Get the head at which to try to dequeue.
+ int currentHead = Volatile.Read(ref _headAndTail.Head);
+ int slotsIndex = currentHead & _slotsMask;
+
+ // Read the sequence number for the head position.
+ int sequenceNumber = Volatile.Read(ref _slots[slotsIndex].SequenceNumber);
+
+ // We can dequeue from this slot if it's been filled by an enqueuer, which
+ // would have left the sequence number at pos+1.
+ int diff = sequenceNumber - (currentHead + 1);
+ if (diff == 0)
+ {
+ // We may be racing with other dequeuers. Try to reserve the slot by incrementing
+ // the head. Once we've done that, no one else will be able to read from this slot,
+ // and no enqueuer will be able to read from this slot until we've written the new
+ // sequence number. WARNING: The next few lines are not reliable on a runtime that
+ // supports thread aborts. If a thread abort were to sneak in after the CompareExchange
+ // but before the Volatile.Write, enqueuers trying to enqueue into this slot would
+ // spin indefinitely. If this implementation is ever used on such a platform, this
+ // if block should be wrapped in a finally / prepared region.
+ if (Interlocked.CompareExchange(ref _headAndTail.Head, currentHead + 1, currentHead) == currentHead)
+ {
+ // Successfully reserved the slot. Note that after the above CompareExchange, other threads
+ // trying to dequeue from this slot will end up spinning until we do the subsequent Write.
+ item = _slots[slotsIndex].Item;
+ if (!Volatile.Read(ref _preservedForObservation))
+ {
+ // If we're preserving, though, we don't zero out the slot, as we need it for
+ // enumerations, peeking, ToArray, etc. And we don't update the sequence number,
+ // so that an enqueuer will see it as full and be forced to move to a new segment.
+ _slots[slotsIndex].Item = default(T);
+ Volatile.Write(ref _slots[slotsIndex].SequenceNumber, currentHead + _slots.Length);
+ }
+ return true;
+ }
+ }
+ else if (diff < 0)
+ {
+ // The sequence number was less than what we needed, which means this slot doesn't
+ // yet contain a value we can dequeue, i.e. the segment is empty. Technically it's
+ // possible that multiple enqueuers could have written concurrently, with those
+ // getting later slots actually finishing first, so there could be elements after
+ // this one that are available, but we need to dequeue in order. So before declaring
+ // failure and that the segment is empty, we check the tail to see if we're actually
+ // empty or if we're just waiting for items in flight or after this one to become available.
+ bool frozen = _frozenForEnqueues;
+ int currentTail = Volatile.Read(ref _headAndTail.Tail);
+ if (currentTail - currentHead <= 0 || (frozen && (currentTail - FreezeOffset - currentHead <= 0)))
+ {
+ item = default(T);
+ return false;
+ }
+
+ // It's possible it could have become frozen after we checked _frozenForEnqueues
+ // and before reading the tail. That's ok: in that rare race condition, we just
+ // loop around again.
+ }
+
+ // Lost a race. Spin a bit, then try again.
+ spinner.SpinOnce();
+ }
+ }
+
+ /// <summary>Tries to peek at an element from the queue, without removing it.</summary>
+ public bool TryPeek(out T result, bool resultUsed)
+ {
+ if (resultUsed)
+ {
+ // In order to ensure we don't get a torn read on the value, we mark the segment
+ // as preserving for observation. Additional items can still be enqueued to this
+ // segment, but no space will be freed during dequeues, such that the segment will
+ // no longer be reusable.
+ _preservedForObservation = true;
+ Interlocked.MemoryBarrier();
+ }
+
+ // Loop in case of contention...
+ var spinner = new SpinWait();
+ while (true)
+ {
+ // Get the head at which to try to peek.
+ int currentHead = Volatile.Read(ref _headAndTail.Head);
+ int slotsIndex = currentHead & _slotsMask;
+
+ // Read the sequence number for the head position.
+ int sequenceNumber = Volatile.Read(ref _slots[slotsIndex].SequenceNumber);
+
+ // We can peek from this slot if it's been filled by an enqueuer, which
+ // would have left the sequence number at pos+1.
+ int diff = sequenceNumber - (currentHead + 1);
+ if (diff == 0)
+ {
+ result = resultUsed ? _slots[slotsIndex].Item : default(T);
+ return true;
+ }
+ else if (diff < 0)
+ {
+ // The sequence number was less than what we needed, which means this slot doesn't
+ // yet contain a value we can peek, i.e. the segment is empty. Technically it's
+ // possible that multiple enqueuers could have written concurrently, with those
+ // getting later slots actually finishing first, so there could be elements after
+ // this one that are available, but we need to peek in order. So before declaring
+ // failure and that the segment is empty, we check the tail to see if we're actually
+ // empty or if we're just waiting for items in flight or after this one to become available.
+ bool frozen = _frozenForEnqueues;
+ int currentTail = Volatile.Read(ref _headAndTail.Tail);
+ if (currentTail - currentHead <= 0 || (frozen && (currentTail - FreezeOffset - currentHead <= 0)))
+ {
+ result = default(T);
+ return false;
+ }
+
+ // It's possible it could have become frozen after we checked _frozenForEnqueues
+ // and before reading the tail. That's ok: in that rare race condition, we just
+ // loop around again.
+ }
+
+ // Lost a race. Spin a bit, then try again.
+ spinner.SpinOnce();
+ }
+ }
+
+ /// <summary>
+ /// Attempts to enqueue the item. If successful, the item will be stored
+ /// in the queue and true will be returned; otherwise, the item won't be stored, and false
+ /// will be returned.
+ /// </summary>
+ public bool TryEnqueue(T item)
+ {
+ // Loop in case of contention...
+ var spinner = new SpinWait();
+ while (true)
+ {
+ // Get the tail at which to try to return.
+ int currentTail = Volatile.Read(ref _headAndTail.Tail);
+ int slotsIndex = currentTail & _slotsMask;
+
+ // Read the sequence number for the tail position.
+ int sequenceNumber = Volatile.Read(ref _slots[slotsIndex].SequenceNumber);
+
+ // The slot is empty and ready for us to enqueue into it if its sequence
+ // number matches the slot.
+ int diff = sequenceNumber - currentTail;
+ if (diff == 0)
+ {
+ // We may be racing with other enqueuers. Try to reserve the slot by incrementing
+ // the tail. Once we've done that, no one else will be able to write to this slot,
+ // and no dequeuer will be able to read from this slot until we've written the new
+ // sequence number. WARNING: The next few lines are not reliable on a runtime that
+ // supports thread aborts. If a thread abort were to sneak in after the CompareExchange
+ // but before the Volatile.Write, other threads will spin trying to access this slot.
+ // If this implementation is ever used on such a platform, this if block should be
+ // wrapped in a finally / prepared region.
+ if (Interlocked.CompareExchange(ref _headAndTail.Tail, currentTail + 1, currentTail) == currentTail)
+ {
+ // Successfully reserved the slot. Note that after the above CompareExchange, other threads
+ // trying to return will end up spinning until we do the subsequent Write.
+ _slots[slotsIndex].Item = item;
+ Volatile.Write(ref _slots[slotsIndex].SequenceNumber, currentTail + 1);
+ return true;
+ }
+ }
+ else if (diff < 0)
+ {
+ // The sequence number was less than what we needed, which means this slot still
+ // contains a value, i.e. the segment is full. Technically it's possible that multiple
+ // dequeuers could have read concurrently, with those getting later slots actually
+ // finishing first, so there could be spaces after this one that are available, but
+ // we need to enqueue in order.
+ return false;
+ }
+
+ // Lost a race. Spin a bit, then try again.
+ spinner.SpinOnce();
+ }
+ }
+
+ /// <summary>Represents a slot in the queue.</summary>
+ [StructLayout(LayoutKind.Auto)]
+ [DebuggerDisplay("Item = {Item}, SequenceNumber = {SequenceNumber}")]
+ internal struct Slot
+ {
+ /// <summary>The item.</summary>
+ public T Item;
+ /// <summary>The sequence number for this slot, used to synchronize between enqueuers and dequeuers.</summary>
+ public int SequenceNumber;
+ }
+ }
+ }
+
+ /// <summary>Padded head and tail indices, to avoid false sharing between producers and consumers.</summary>
+ [DebuggerDisplay("Head = {Head}, Tail = {Tail}")]
+ [StructLayout(LayoutKind.Explicit, Size = 384)] // padding before/between/after fields based on worst case cache line size of 128
+ internal struct PaddedHeadAndTail
+ {
+ [FieldOffset(128)] public int Head;
+ [FieldOffset(256)] public int Tail;
+ }
+}
diff --git a/src/Common/src/System/Net/SecurityProtocol.cs b/src/Common/src/System/Net/SecurityProtocol.cs
index beeba086ea..7d9565d92c 100644
--- a/src/Common/src/System/Net/SecurityProtocol.cs
+++ b/src/Common/src/System/Net/SecurityProtocol.cs
@@ -8,21 +8,8 @@ namespace System.Net
{
internal static class SecurityProtocol
{
- // SSLv2 and SSLv3 are considered insecure and will not be supported by the underlying implementations.
- public const SslProtocols AllowedSecurityProtocols =
- SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
-
- public const SslProtocols DefaultSecurityProtocols =
- SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
+ public const SslProtocols DefaultSecurityProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
public const SslProtocols SystemDefaultSecurityProtocols = SslProtocols.None;
-
- public static void ThrowOnNotAllowed(SslProtocols protocols, bool allowNone = true)
- {
- if ((!allowNone && (protocols == SslProtocols.None)) || ((protocols & ~AllowedSecurityProtocols) != 0))
- {
- throw new NotSupportedException(SR.net_securityprotocolnotsupported);
- }
- }
}
}
diff --git a/src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs b/src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs
index 69cbd29dac..492c8cb63f 100644
--- a/src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs
+++ b/src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs
@@ -31,13 +31,11 @@ namespace System.Net.WebSockets
/// <param name="isServer">true if this is the server-side of the connection; false if this is the client-side of the connection.</param>
/// <param name="subprotocol">The agreed upon subprotocol for the connection.</param>
/// <param name="keepAliveInterval">The interval to use for keep-alive pings.</param>
- /// <param name="receiveBufferSize">The buffer size to use for received data.</param>
- /// <param name="receiveBuffer">Optional buffer to use for receives.</param>
/// <returns>The created <see cref="ManagedWebSocket"/> instance.</returns>
public static ManagedWebSocket CreateFromConnectedStream(
- Stream stream, bool isServer, string subprotocol, TimeSpan keepAliveInterval, Memory<byte> buffer)
+ Stream stream, bool isServer, string subprotocol, TimeSpan keepAliveInterval)
{
- return new ManagedWebSocket(stream, isServer, subprotocol, keepAliveInterval, buffer);
+ return new ManagedWebSocket(stream, isServer, subprotocol, keepAliveInterval);
}
/// <summary>Thread-safe random number generator used to generate masks for each send.</summary>
@@ -159,9 +157,7 @@ namespace System.Net.WebSockets
/// <param name="isServer">true if this is the server-side of the connection; false if this is the client-side of the connection.</param>
/// <param name="subprotocol">The agreed upon subprotocol for the connection.</param>
/// <param name="keepAliveInterval">The interval to use for keep-alive pings.</param>
- /// <param name="receiveBufferSize">The buffer size to use for received data.</param>
- /// <param name="buffer">Optional buffer to use for receives</param>
- private ManagedWebSocket(Stream stream, bool isServer, string subprotocol, TimeSpan keepAliveInterval, Memory<byte> buffer)
+ private ManagedWebSocket(Stream stream, bool isServer, string subprotocol, TimeSpan keepAliveInterval)
{
Debug.Assert(StateUpdateLock != null, $"Expected {nameof(StateUpdateLock)} to be non-null");
Debug.Assert(ReceiveAsyncLock != null, $"Expected {nameof(ReceiveAsyncLock)} to be non-null");
@@ -176,17 +172,11 @@ namespace System.Net.WebSockets
_isServer = isServer;
_subprotocol = subprotocol;
- // If we were provided with a buffer to use, use it as long as it's big enough for our needs.
- // If it doesn't meet our criteria, just create a new one. If we need to create a new one,
- // we avoid using the pool because often many web sockets will be used concurrently, and if each web
- // socket rents a similarly sized buffer from the pool for its duration, we'll end up draining
- // the pool, such that other web sockets will allocate anyway, as will anyone else in the process using the
- // pool. If someone wants to pool, they can do so by passing in the buffer they want to use, and they can
- // get it from whatever pool they like. If we create our own buffer, it's small, large enough for message
- // headers and control payloads, but data for other message payloads is read directly into the buffers
- // passed into ReceiveAsync.
+ // Create a buffer just large enough to handle received packet headers (at most 14 bytes) and
+ // control payloads (at most 125 bytes). Message payloads are read directly into the buffer
+ // supplied to ReceiveAsync.
const int ReceiveBufferMinLength = MaxControlPayloadLength;
- _receiveBuffer = buffer.Length >= ReceiveBufferMinLength ? buffer : new byte[ReceiveBufferMinLength];
+ _receiveBuffer = new byte[ReceiveBufferMinLength];
// Set up the abort source so that if it's triggered, we transition the instance appropriately.
_abortSource.Token.Register(s =>
diff --git a/src/Common/tests/System/Buffers/NativeOwnedMemory.cs b/src/Common/tests/System/Buffers/NativeMemoryManager.cs
index 9e2c501cbf..e198eec977 100644
--- a/src/Common/tests/System/Buffers/NativeOwnedMemory.cs
+++ b/src/Common/tests/System/Buffers/NativeMemoryManager.cs
@@ -8,26 +8,26 @@ using System.Runtime.InteropServices;
namespace System.Buffers
{
- internal sealed class NativeOwnedMemory : OwnedMemory<byte>
+ internal sealed class NativeMemoryManager : MemoryManager<byte>
{
private readonly int _length;
private IntPtr _ptr;
private int _retainedCount;
private bool _disposed;
- public NativeOwnedMemory(int length)
+ public NativeMemoryManager(int length)
{
_length = length;
_ptr = Marshal.AllocHGlobal(length);
}
- ~NativeOwnedMemory()
+ ~NativeMemoryManager()
{
- Debug.WriteLine($"{nameof(NativeOwnedMemory)} being finalized");
+ Debug.WriteLine($"{nameof(NativeMemoryManager)} being finalized");
Dispose(false);
}
- public override bool IsDisposed
+ public bool IsDisposed
{
get
{
@@ -40,7 +40,7 @@ namespace System.Buffers
public override int Length => _length;
- protected override bool IsRetained
+ public bool IsRetained
{
get
{
@@ -51,16 +51,26 @@ namespace System.Buffers
}
}
- public override unsafe Span<byte> Span => new Span<byte>((void*)_ptr, _length);
+ public override unsafe Span<byte> GetSpan() => new Span<byte>((void*)_ptr, _length);
- public override unsafe MemoryHandle Pin(int byteOffset = 0)
+ public override unsafe MemoryHandle Pin(int elementIndex = 0)
{
- if (byteOffset < 0 || byteOffset > _length) throw new ArgumentOutOfRangeException(nameof(byteOffset));
- void* pointer = (void*)((byte*)_ptr + byteOffset);
- return new MemoryHandle(this, pointer);
+ if (elementIndex < 0 || elementIndex > _length) throw new ArgumentOutOfRangeException(nameof(elementIndex));
+
+ lock (this)
+ {
+ if (_retainedCount == 0 && _disposed)
+ {
+ throw new Exception();
+ }
+ _retainedCount++;
+ }
+
+ void* pointer = (void*)((byte*)_ptr + elementIndex); // T = byte
+ return new MemoryHandle(pointer, default, this);
}
- public override bool Release()
+ public override void Unpin()
{
lock (this)
{
@@ -74,23 +84,9 @@ namespace System.Buffers
Marshal.FreeHGlobal(_ptr);
_ptr = IntPtr.Zero;
}
- return true;
}
}
}
- return false;
- }
-
- public override void Retain()
- {
- lock (this)
- {
- if (_retainedCount == 0 && _disposed)
- {
- throw new Exception();
- }
- _retainedCount++;
- }
}
protected override void Dispose(bool disposing)
@@ -105,11 +101,5 @@ namespace System.Buffers
}
}
}
-
- protected override bool TryGetArray(out ArraySegment<byte> segment)
- {
- segment = default(ArraySegment<byte>);
- return false;
- }
}
}
diff --git a/src/Common/tests/System/Net/SslProtocolSupport.cs b/src/Common/tests/System/Net/SslProtocolSupport.cs
index fb3b51028b..180ae00c28 100644
--- a/src/Common/tests/System/Net/SslProtocolSupport.cs
+++ b/src/Common/tests/System/Net/SslProtocolSupport.cs
@@ -4,6 +4,7 @@
using System.Collections;
using System.Collections.Generic;
+using System.Runtime.InteropServices;
using System.Security.Authentication;
namespace System.Net.Test.Common
@@ -12,53 +13,37 @@ namespace System.Net.Test.Common
{
public const SslProtocols DefaultSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;
- public const SslProtocols SupportedSslProtocols =
- SslProtocols.Tls
- | SslProtocols.Tls11
- | SslProtocols.Tls12;
-
-#pragma warning disable 0618
- public const SslProtocols UnsupportedSslProtocols =
- SslProtocols.Ssl2
- | SslProtocols.Ssl3;
-#pragma warning restore 0618
-
- public class SupportedSslProtocolsTestData : IEnumerable<object[]>
+ public static SslProtocols SupportedSslProtocols
{
- public IEnumerator<object[]> GetEnumerator()
+ get
{
- foreach (SslProtocols protocol in Enum.GetValues(typeof(SslProtocols)))
+ SslProtocols supported = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
+#pragma warning disable 0618 // SSL2/3 are deprecated
+ if (PlatformDetection.IsWindows ||
+ PlatformDetection.IsOSX ||
+ (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && PlatformDetection.OpenSslVersion < new Version(1, 0, 2) && !PlatformDetection.IsDebian))
{
- if (protocol != 0 && (protocol & SupportedSslProtocols) == protocol)
- {
- yield return new object[] { protocol };
- }
+ supported |= SslProtocols.Ssl3;
}
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
+#pragma warning restore 0618
+ return supported;
}
}
- public class UnsupportedSslProtocolsTestData : IEnumerable<object[]>
+ public class SupportedSslProtocolsTestData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
foreach (SslProtocols protocol in Enum.GetValues(typeof(SslProtocols)))
{
- if (protocol != 0 && (protocol & UnsupportedSslProtocols) == protocol)
+ if (protocol != 0 && (protocol & SupportedSslProtocols) == protocol)
{
yield return new object[] { protocol };
}
}
}
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
}
diff --git a/src/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs b/src/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs
index b82c3946d9..e34ffd7f4b 100644
--- a/src/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs
+++ b/src/Common/tests/System/Net/VirtualNetwork/VirtualNetwork.cs
@@ -10,16 +10,29 @@ namespace System.Net.Test.Common
{
public class VirtualNetwork
{
+ public class VirtualNetworkConnectionBroken : Exception
+ {
+ public VirtualNetworkConnectionBroken() : base("Connection broken") { }
+ }
+
private readonly int WaitForReadDataTimeoutMilliseconds = 30 * 1000;
-
+
private readonly ConcurrentQueue<byte[]> _clientWriteQueue = new ConcurrentQueue<byte[]>();
private readonly ConcurrentQueue<byte[]> _serverWriteQueue = new ConcurrentQueue<byte[]>();
private readonly SemaphoreSlim _clientDataAvailable = new SemaphoreSlim(0);
private readonly SemaphoreSlim _serverDataAvailable = new SemaphoreSlim(0);
+ public bool DisableConnectionBreaking { get; set; } = false;
+ private bool _connectionBroken = false;
+
public void ReadFrame(bool server, out byte[] buffer)
{
+ if (_connectionBroken)
+ {
+ throw new VirtualNetworkConnectionBroken();
+ }
+
SemaphoreSlim semaphore;
ConcurrentQueue<byte[]> packetQueue;
@@ -39,6 +52,11 @@ namespace System.Net.Test.Common
throw new TimeoutException("VirtualNetwork: Timeout reading the next frame.");
}
+ if (_connectionBroken)
+ {
+ throw new VirtualNetworkConnectionBroken();
+ }
+
bool dequeueSucceeded = false;
int remainingTries = 3;
int backOffDelayMilliseconds = 2;
@@ -62,6 +80,11 @@ namespace System.Net.Test.Common
public void WriteFrame(bool server, byte[] buffer)
{
+ if (_connectionBroken)
+ {
+ throw new VirtualNetworkConnectionBroken();
+ }
+
SemaphoreSlim semaphore;
ConcurrentQueue<byte[]> packetQueue;
@@ -82,5 +105,15 @@ namespace System.Net.Test.Common
packetQueue.Enqueue(innerBuffer);
semaphore.Release();
}
+
+ public void BreakConnection()
+ {
+ if (!DisableConnectionBreaking)
+ {
+ _connectionBroken = true;
+ _serverDataAvailable.Release(1_000_000);
+ _clientDataAvailable.Release(1_000_000);
+ }
+ }
}
}
diff --git a/src/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs b/src/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs
index e04eb54ace..d019c101ad 100644
--- a/src/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs
+++ b/src/Common/tests/System/Net/VirtualNetwork/VirtualNetworkStream.cs
@@ -156,5 +156,15 @@ namespace System.Net.Test.Common
public override void EndWrite(IAsyncResult asyncResult) =>
TaskToApm.End(asyncResult);
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _network.BreakConnection();
+ }
+
+ base.Dispose(disposing);
+ }
}
}
diff --git a/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs b/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs
index ac039bd592..bf8331cd6f 100644
--- a/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs
+++ b/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs
@@ -20,7 +20,7 @@ namespace System.Diagnostics
public const int SuccessExitCode = 42;
/// <summary>The name of the test console app.</summary>
- protected static readonly string TestConsoleApp = "RemoteExecutorConsoleApp.exe";
+ protected static readonly string TestConsoleApp = Path.GetFullPath("RemoteExecutorConsoleApp.exe");
/// <summary>Invokes the method from this assembly in another process using the specified arguments.</summary>
/// <param name="method">The method to invoke.</param>
diff --git a/src/Microsoft.VisualBasic/src/MatchingRefApiCompatBaseline.netstandard.txt b/src/Microsoft.VisualBasic/src/MatchingRefApiCompatBaseline.netstandard.txt
index 11a2bf0209..33bf1c3233 100644
--- a/src/Microsoft.VisualBasic/src/MatchingRefApiCompatBaseline.netstandard.txt
+++ b/src/Microsoft.VisualBasic/src/MatchingRefApiCompatBaseline.netstandard.txt
@@ -1,16 +1,7 @@
Compat issues with assembly Microsoft.VisualBasic:
-TypesMustExist : Type 'Microsoft.VisualBasic.ControlChars' does not exist in the implementation but it does exist in the contract.
-CannotSealType : Type 'Microsoft.VisualBasic.HideModuleNameAttribute' is sealed in the implementation but not sealed in the contract.
-TypesMustExist : Type 'Microsoft.VisualBasic.Interaction' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'Microsoft.VisualBasic.Strings.Left(System.String, System.Int32)' does not exist in the implementation but it does exist in the contract.
+
+# Loaded via reflection so needs to be public in the implementation but we don't want to expose them publicly in the ref assembly:
MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Conversions.FallbackUserDefinedConversion(System.Object, System.Type)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Conversions.GetCultureInfo()' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Conversions.IsHexOrOctValue(System.String, System.Int64)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Conversions.IsHexOrOctValue(System.String, System.UInt64)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Conversions.ToHalfwidthNumbers(System.String, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract.
-CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.DesignerGeneratedAttribute' is sealed in the implementation but not sealed in the contract.
-CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.IncompleteInitialization' is sealed in the implementation but not sealed in the contract.
-TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.InternalErrorException' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackCall(System.Object, System.String, System.Object[], System.String[], System.Boolean)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackGet(System.Object, System.String, System.Object[], System.String[])' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackIndexSet(System.Object, System.Object[], System.String[])' does not exist in the implementation but it does exist in the contract.
@@ -20,12 +11,8 @@ MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding
MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackSet(System.Object, System.String, System.Object[])' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackSetComplex(System.Object, System.String, System.Object[], System.Boolean, System.Boolean)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateCallInvokeDefault(System.Object, System.Object[], System.String[], System.Boolean)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateCanEvaluate(System.Object, System.Type, System.String, System.Object[], System.Boolean, System.Boolean)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGetInvokeDefault(System.Object, System.Object[], System.String[], System.Boolean)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Operators.CompareObject(System.Object, System.Object, System.Boolean)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Operators.FallbackInvokeUserDefinedOperator(System.Object, System.Object[])' does not exist in the implementation but it does exist in the contract.
-CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.OptionCompareAttribute' is sealed in the implementation but not sealed in the contract.
-CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.OptionTextAttribute' is sealed in the implementation but not sealed in the contract.
TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate0' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate1' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate2' does not exist in the implementation but it does exist in the contract.
@@ -34,8 +21,3 @@ TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate4' doe
TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate5' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate6' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate7' does not exist in the implementation but it does exist in the contract.
-CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute' is sealed in the implementation but not sealed in the contract.
-CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.StaticLocalInitFlag' is sealed in the implementation but not sealed in the contract.
-MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Utils.GetResourceString(System.String, System.String[])' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Utils.MethodToString(System.Reflection.MethodBase)' does not exist in the implementation but it does exist in the contract.
-Total Issues: 39
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Conversions.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Conversions.vb
index 462ab72f67..8aba342f87 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Conversions.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Conversions.vb
@@ -919,13 +919,13 @@ MisMatch:
Public Shared Shadows Function ToString(value As Char) As String
Return value.ToString()
End Function
- Public Shared Function GetCultureInfo() As Global.System.Globalization.CultureInfo
+ Friend Shared Function GetCultureInfo() As Global.System.Globalization.CultureInfo
Return Global.System.Globalization.CultureInfo.CurrentCulture
End Function
- Public Shared Function ToHalfwidthNumbers(s As String, culture As Global.System.Globalization.CultureInfo) As String
+ Friend Shared Function ToHalfwidthNumbers(s As String, culture As Global.System.Globalization.CultureInfo) As String
Return s
End Function
- Public Shared Function IsHexOrOctValue(value As String, ByRef i64Value As Global.System.Int64) As Boolean
+ Friend Shared Function IsHexOrOctValue(value As String, ByRef i64Value As Global.System.Int64) As Boolean
Dim ch As Char
Dim length As Integer
Dim firstNonspace As Integer
@@ -955,7 +955,7 @@ GetSpecialValue:
Return True
End Function
<Global.System.CLSCompliant(False)>
- Public Shared Function IsHexOrOctValue(value As String, ByRef ui64Value As Global.System.UInt64) As Boolean
+ Friend Shared Function IsHexOrOctValue(value As String, ByRef ui64Value As Global.System.UInt64) As Boolean
Dim ch As Char
Dim length As Integer
Dim firstNonspace As Integer
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/DesignerGeneratedAttribute.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/DesignerGeneratedAttribute.vb
index d49ffce83e..26b43aac1c 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/DesignerGeneratedAttribute.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/DesignerGeneratedAttribute.vb
@@ -5,7 +5,7 @@
Namespace Global.Microsoft.VisualBasic.CompilerServices
<Global.System.AttributeUsage(Global.System.AttributeTargets.Class, Inherited:=False)>
<Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Never)>
- Public Class DesignerGeneratedAttribute
+ Public NotInheritable Class DesignerGeneratedAttribute
Inherits Global.System.Attribute
End Class
End Namespace
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/ExceptionUtils.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/ExceptionUtils.vb
index 9e1a658cc5..eb5f7e7f3c 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/ExceptionUtils.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/ExceptionUtils.vb
@@ -58,7 +58,7 @@ Namespace Microsoft.VisualBasic.CompilerServices
End Class
- Public NotInheritable Class InternalErrorException
+ Friend NotInheritable Class InternalErrorException
Inherits System.Exception
Public Sub New(ByVal message As String)
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/IncompleteInitialization.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/IncompleteInitialization.vb
index 52f2af042c..cbb88b3a6b 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/IncompleteInitialization.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/IncompleteInitialization.vb
@@ -5,7 +5,7 @@
Namespace Global.Microsoft.VisualBasic.CompilerServices
<Global.System.Diagnostics.DebuggerNonUserCode()>
<Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Never)>
- Public Class IncompleteInitialization
+ Public NotInheritable Class IncompleteInitialization
Inherits Global.System.Exception
Public Sub New()
MyBase.New()
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/NewLateBinding.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/NewLateBinding.vb
index effcd30367..20ae0ccb1a 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/NewLateBinding.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/NewLateBinding.vb
@@ -30,7 +30,7 @@ Namespace Microsoft.VisualBasic.CompilerServices
End Sub
<DebuggerHiddenAttribute()> <DebuggerStepThroughAttribute()>
- Public Shared Function LateCanEvaluate(
+ Friend Shared Function LateCanEvaluate(
ByVal instance As Object,
ByVal type As System.Type,
ByVal memberName As String,
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Operators.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Operators.vb
index 1d68abcb79..d26866c792 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Operators.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Operators.vb
@@ -350,7 +350,7 @@ Namespace Microsoft.VisualBasic.CompilerServices
End Select
End Function
- Public Shared Function CompareObject(ByVal left As Object, ByVal right As Object, ByVal textCompare As Boolean) As Integer
+ Friend Shared Function CompareObject(ByVal left As Object, ByVal right As Object, ByVal textCompare As Boolean) As Integer
Dim comparison As CompareClass = CompareObject2(left, right, textCompare)
Select Case comparison
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/OptionCompareAttribute.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/OptionCompareAttribute.vb
index b3b601a0cb..ebe8a31dec 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/OptionCompareAttribute.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/OptionCompareAttribute.vb
@@ -5,7 +5,7 @@
Namespace Global.Microsoft.VisualBasic.CompilerServices
<Global.System.AttributeUsage(Global.System.AttributeTargets.Parameter, Inherited:=False)>
<Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Never)>
- Public Class OptionCompareAttribute
+ Public NotInheritable Class OptionCompareAttribute
Inherits Global.System.Attribute
End Class
End Namespace
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/OptionTextAttribute.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/OptionTextAttribute.vb
index 2b275ddc9a..e564f11314 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/OptionTextAttribute.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/OptionTextAttribute.vb
@@ -5,7 +5,7 @@
Namespace Global.Microsoft.VisualBasic.CompilerServices
<Global.System.AttributeUsage(Global.System.AttributeTargets.Class, Inherited:=False)>
<Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Never)>
- Public Class OptionTextAttribute
+ Public NotInheritable Class OptionTextAttribute
Inherits Global.System.Attribute
End Class
End Namespace
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/StandardModuleAttribute.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/StandardModuleAttribute.vb
index 0e2fc0e45a..f333352b4f 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/StandardModuleAttribute.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/StandardModuleAttribute.vb
@@ -5,7 +5,7 @@
Namespace Global.Microsoft.VisualBasic.CompilerServices
<Global.System.AttributeUsage(Global.System.AttributeTargets.Class, Inherited:=False)>
<Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Never)>
- Public Class StandardModuleAttribute
+ Public NotInheritable Class StandardModuleAttribute
Inherits Global.System.Attribute
End Class
End Namespace
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/StaticLocalInitFlag.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/StaticLocalInitFlag.vb
index 4805db4aa2..e98b8cf3c2 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/StaticLocalInitFlag.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/StaticLocalInitFlag.vb
@@ -5,7 +5,7 @@
Namespace Global.Microsoft.VisualBasic.CompilerServices
<Global.System.Diagnostics.DebuggerNonUserCode()>
<Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Never)>
- Public Class StaticLocalInitFlag
+ Public NotInheritable Class StaticLocalInitFlag
Public State As Short
End Class
End Namespace
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Utils.LateBinder.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Utils.LateBinder.vb
index 00dc926510..adab60aebf 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Utils.LateBinder.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/CompilerServices/Utils.LateBinder.vb
@@ -79,7 +79,7 @@ Namespace Microsoft.VisualBasic.CompilerServices
' Param: Args - An array of params used to replace placeholders.
'Returns: The resource string if found or an error message string
'*****************************************************************************
- Public Shared Function GetResourceString(ByVal resourceKey As String, ByVal ParamArray args() As String) As String
+ Friend Shared Function GetResourceString(ByVal resourceKey As String, ByVal ParamArray args() As String) As String
Return SR.Format(resourceKey, args)
End Function
@@ -388,7 +388,7 @@ GetSpecialValue:
Return resultString
End Function
- Public Shared Function MethodToString(ByVal method As Reflection.MethodBase) As String
+ Friend Shared Function MethodToString(ByVal method As Reflection.MethodBase) As String
Dim returnType As System.Type = Nothing
Dim first As Boolean
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/ControlChars.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/ControlChars.vb
index 205461bb4b..88bfd165f4 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/ControlChars.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/ControlChars.vb
@@ -4,7 +4,7 @@
Namespace Microsoft.VisualBasic
' Contants for the Control Characters
- Public NotInheritable Class ControlChars
+ Friend NotInheritable Class ControlChars
Public Const CrLf As String = ChrW(13) & ChrW(10)
Public Const NewLine As String = ChrW(13) & ChrW(10)
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/HideModuleNameAttribute.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/HideModuleNameAttribute.vb
index 3cc0fe8fb6..55d700ea05 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/HideModuleNameAttribute.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/HideModuleNameAttribute.vb
@@ -5,7 +5,7 @@
Namespace Global.Microsoft.VisualBasic
<Global.System.AttributeUsage(Global.System.AttributeTargets.Class, Inherited:=False)>
<Global.System.ComponentModel.EditorBrowsable(Global.System.ComponentModel.EditorBrowsableState.Never)>
- Public Class HideModuleNameAttribute
+ Public NotInheritable Class HideModuleNameAttribute
Inherits Global.System.Attribute
End Class
End Namespace
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/Interaction.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/Interaction.vb
index 2dca6e194a..e68edca47c 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/Interaction.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/Interaction.vb
@@ -4,7 +4,7 @@
Namespace Microsoft.VisualBasic
- Public Module Interaction
+ Friend Module Interaction
Friend Function IIf(Of T)(ByVal condition As Boolean, ByVal truePart As T, ByVal falsePart As T) As T
If condition Then
diff --git a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/Strings.vb b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/Strings.vb
index eb660c2507..cc94d835d7 100644
--- a/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/Strings.vb
+++ b/src/Microsoft.VisualBasic/src/Microsoft/VisualBasic/Strings.vb
@@ -28,7 +28,7 @@ Namespace Global.Microsoft.VisualBasic
'============================================================================
' Left/Right/Mid/Trim functions.
'============================================================================
- Public Function Left(ByVal [str] As String, ByVal length As Integer) As String
+ Friend Function Left(ByVal [str] As String, ByVal length As Integer) As String
'-------------------------------------------------------------
' lLen < 0 throws InvalidArgument exception
' lLen > Len([str]) let lLen = Len([str])
diff --git a/src/Native/Unix/System.Net.Http.Native/pal_easy.cpp b/src/Native/Unix/System.Net.Http.Native/pal_easy.cpp
index 4ccbd8f661..f68c793e02 100644
--- a/src/Native/Unix/System.Net.Http.Native/pal_easy.cpp
+++ b/src/Native/Unix/System.Net.Http.Native/pal_easy.cpp
@@ -74,6 +74,8 @@ static_assert(PAL_CURL_HTTP_VERSION_1_1 == CURL_HTTP_VERSION_1_1, "");
static_assert(PAL_CURL_HTTP_VERSION_2TLS == CURL_HTTP_VERSION_2TLS, "");
#endif
+static_assert(PAL_CURL_SSLVERSION_SSLv2 == CURL_SSLVERSION_SSLv2, "");
+static_assert(PAL_CURL_SSLVERSION_SSLv3 == CURL_SSLVERSION_SSLv3, "");
static_assert(PAL_CURL_SSLVERSION_TLSv1 == CURL_SSLVERSION_TLSv1, "");
#if HAVE_CURL_SSLVERSION_TLSv1_012
static_assert(PAL_CURL_SSLVERSION_TLSv1_0 == CURL_SSLVERSION_TLSv1_0, "");
diff --git a/src/Native/Unix/System.Net.Http.Native/pal_easy.h b/src/Native/Unix/System.Net.Http.Native/pal_easy.h
index 18298c1532..62f49c2d33 100644
--- a/src/Native/Unix/System.Net.Http.Native/pal_easy.h
+++ b/src/Native/Unix/System.Net.Http.Native/pal_easy.h
@@ -100,6 +100,8 @@ enum PAL_CURL_HTTP_VERSION
enum PAL_CURL_SSLVERSION
{
PAL_CURL_SSLVERSION_TLSv1 = 1,
+ PAL_CURL_SSLVERSION_SSLv2 = 2,
+ PAL_CURL_SSLVERSION_SSLv3 = 3,
PAL_CURL_SSLVERSION_TLSv1_0 = 4,
PAL_CURL_SSLVERSION_TLSv1_1 = 5,
PAL_CURL_SSLVERSION_TLSv1_2 = 6,
diff --git a/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509chain.cpp b/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509chain.cpp
index 6db3d53e9f..4bed8b8940 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509chain.cpp
+++ b/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_x509chain.cpp
@@ -154,7 +154,8 @@ static void MergeStatusCodes(CFTypeRef key, CFTypeRef value, void* context)
CFStringRef keyString = reinterpret_cast<CFStringRef>(key);
if (CFEqual(keyString, CFSTR("NotValidBefore")) || CFEqual(keyString, CFSTR("ValidLeaf")) ||
- CFEqual(keyString, CFSTR("ValidIntermediates")) || CFEqual(keyString, CFSTR("ValidRoot")))
+ CFEqual(keyString, CFSTR("ValidIntermediates")) || CFEqual(keyString, CFSTR("ValidRoot")) ||
+ CFEqual(keyString, CFSTR("TemporalValidity")))
*pStatus |= PAL_X509ChainNotTimeValid;
else if (CFEqual(keyString, CFSTR("Revocation")))
*pStatus |= PAL_X509ChainRevoked;
@@ -168,8 +169,10 @@ static void MergeStatusCodes(CFTypeRef key, CFTypeRef value, void* context)
*pStatus |= PAL_X509ChainExplicitDistrust;
else if (CFEqual(keyString, CFSTR("RevocationResponseRequired")))
*pStatus |= PAL_X509ChainRevocationStatusUnknown;
+ else if (CFEqual(keyString, CFSTR("MissingIntermediate")))
+ *pStatus |= PAL_X509ChainPartialChain;
else if (CFEqual(keyString, CFSTR("WeakLeaf")) || CFEqual(keyString, CFSTR("WeakIntermediates")) ||
- CFEqual(keyString, CFSTR("WeakRoot")))
+ CFEqual(keyString, CFSTR("WeakRoot")) || CFEqual(keyString, CFSTR("WeakKeySize")))
{
// Because we won't report this out of a chain built by .NET on Windows,
// don't report it here.
diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp
index 7489aff1a0..5b6ce02160 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp
+++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp
@@ -80,13 +80,8 @@ extern "C" void CryptoNative_SetProtocolOptions(SSL_CTX* ctx, SslProtocols proto
{
protocolOptions |= SSL_OP_NO_SSLv2;
}
-#ifndef OPENSSL_NO_SSL3
if ((protocols & PAL_SSL_SSL3) != PAL_SSL_SSL3)
-#endif
{
- // If OPENSSL_NO_SSL3 is defined, then ensure we always include
- // SSL_OP_NO_SSLv3 in case we end up running against a binary
- // which had SSLv3 enabled (we don't want to use SSLv3 in that case).
protocolOptions |= SSL_OP_NO_SSLv3;
}
if ((protocols & PAL_SSL_TLS) != PAL_SSL_TLS)
diff --git a/src/System.Collections.Concurrent/src/System.Collections.Concurrent.csproj b/src/System.Collections.Concurrent/src/System.Collections.Concurrent.csproj
index e8c7b2cd6a..4f7e2de607 100644
--- a/src/System.Collections.Concurrent/src/System.Collections.Concurrent.csproj
+++ b/src/System.Collections.Concurrent/src/System.Collections.Concurrent.csproj
@@ -22,6 +22,9 @@
<Compile Include="System\Collections\Concurrent\Partitioner.cs" />
<Compile Include="System\Collections\Concurrent\PartitionerStatic.cs" />
<Compile Include="System\Collections\Concurrent\PlatformHelper.cs" />
+ <Compile Include="$(CommonPath)\System\Collections\Concurrent\ConcurrentQueue_Segment.cs">
+ <Link>Common\System\Collections\Concurrent\ConcurrentQueue_Segment.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="System.Collections" />
diff --git a/src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentQueue.cs b/src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentQueue.cs
index c4202e1a2c..3f78e24527 100644
--- a/src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentQueue.cs
+++ b/src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentQueue.cs
@@ -21,7 +21,7 @@ namespace System.Collections.Concurrent
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(IProducerConsumerCollectionDebugView<>))]
[Serializable]
- public class ConcurrentQueue<T> : IProducerConsumerCollection<T>, IReadOnlyCollection<T>
+ public partial class ConcurrentQueue<T> : IProducerConsumerCollection<T>, IReadOnlyCollection<T>
{
// This implementation provides an unbounded, multi-producer multi-consumer queue
// that supports the standard Enqueue/TryDequeue operations, as well as support for
@@ -88,7 +88,7 @@ namespace System.Collections.Concurrent
int count = c.Count;
if (count > length)
{
- length = Math.Min(RoundUpToPowerOf2(count), MaxSegmentLength);
+ length = Math.Min(Segment.RoundUpToPowerOf2(count), MaxSegmentLength);
}
}
@@ -589,18 +589,6 @@ namespace System.Collections.Concurrent
}
}
- /// <summary>Round the specified value up to the next power of 2, if it isn't one already.</summary>
- private static int RoundUpToPowerOf2(int i)
- {
- --i;
- i |= i >> 1;
- i |= i >> 2;
- i |= i >> 4;
- i |= i >> 8;
- i |= i >> 16;
- return i + 1;
- }
-
/// <summary>Adds an object to the end of the <see cref="ConcurrentQueue{T}"/>.</summary>
/// <param name="item">
/// The object to add to the end of the <see cref="ConcurrentQueue{T}"/>.
@@ -812,312 +800,5 @@ namespace System.Collections.Concurrent
_tail = _head = new Segment(InitialSegmentLength);
}
}
-
- /// <summary>
- /// Provides a multi-producer, multi-consumer thread-safe bounded segment. When the queue is full,
- /// enqueues fail and return false. When the queue is empty, dequeues fail and return null.
- /// These segments are linked together to form the unbounded <see cref="ConcurrentQueue{T}"/>.
- /// </summary>
- [DebuggerDisplay("Capacity = {Capacity}")]
- private sealed class Segment
- {
- // Segment design is inspired by the algorithm outlined at:
- // http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
-
- /// <summary>The array of items in this queue. Each slot contains the item in that slot and its "sequence number".</summary>
- internal readonly Slot[] _slots;
- /// <summary>Mask for quickly accessing a position within the queue's array.</summary>
- internal readonly int _slotsMask;
- /// <summary>The head and tail positions, with padding to help avoid false sharing contention.</summary>
- /// <remarks>Dequeuing happens from the head, enqueuing happens at the tail.</remarks>
- internal PaddedHeadAndTail _headAndTail; // mutable struct: do not make this readonly
-
- /// <summary>Indicates whether the segment has been marked such that dequeues don't overwrite the removed data.</summary>
- internal bool _preservedForObservation;
- /// <summary>Indicates whether the segment has been marked such that no additional items may be enqueued.</summary>
- internal bool _frozenForEnqueues;
- /// <summary>The segment following this one in the queue, or null if this segment is the last in the queue.</summary>
- internal Segment _nextSegment;
-
- /// <summary>Creates the segment.</summary>
- /// <param name="boundedLength">
- /// The maximum number of elements the segment can contain. Must be a power of 2.
- /// </param>
- public Segment(int boundedLength)
- {
- // Validate the length
- Debug.Assert(boundedLength >= 2, $"Must be >= 2, got {boundedLength}");
- Debug.Assert((boundedLength & (boundedLength - 1)) == 0, $"Must be a power of 2, got {boundedLength}");
-
- // Initialize the slots and the mask. The mask is used as a way of quickly doing "% _slots.Length",
- // instead letting us do "& _slotsMask".
- _slots = new Slot[boundedLength];
- _slotsMask = boundedLength - 1;
-
- // Initialize the sequence number for each slot. The sequence number provides a ticket that
- // allows dequeuers to know whether they can dequeue and enqueuers to know whether they can
- // enqueue. An enqueuer at position N can enqueue when the sequence number is N, and a dequeuer
- // for position N can dequeue when the sequence number is N + 1. When an enqueuer is done writing
- // at position N, it sets the sequence number to N + 1 so that a dequeuer will be able to dequeue,
- // and when a dequeuer is done dequeueing at position N, it sets the sequence number to N + _slots.Length,
- // so that when an enqueuer loops around the slots, it'll find that the sequence number at
- // position N is N. This also means that when an enqueuer finds that at position N the sequence
- // number is < N, there is still a value in that slot, i.e. the segment is full, and when a
- // dequeuer finds that the value in a slot is < N + 1, there is nothing currently available to
- // dequeue. (It is possible for multiple enqueuers to enqueue concurrently, writing into
- // subsequent slots, and to have the first enqueuer take longer, so that the slots for 1, 2, 3, etc.
- // may have values, but the 0th slot may still be being filled... in that case, TryDequeue will
- // return false.)
- for (int i = 0; i < _slots.Length; i++)
- {
- _slots[i].SequenceNumber = i;
- }
- }
-
- /// <summary>Gets the number of elements this segment can store.</summary>
- internal int Capacity => _slots.Length;
-
- /// <summary>Gets the "freeze offset" for this segment.</summary>
- internal int FreezeOffset => _slots.Length * 2;
-
- /// <summary>
- /// Ensures that the segment will not accept any subsequent enqueues that aren't already underway.
- /// </summary>
- /// <remarks>
- /// When we mark a segment as being frozen for additional enqueues,
- /// we set the <see cref="_frozenForEnqueues"/> bool, but that's mostly
- /// as a small helper to avoid marking it twice. The real marking comes
- /// by modifying the Tail for the segment, increasing it by this
- /// <see cref="FreezeOffset"/>. This effectively knocks it off the
- /// sequence expected by future enqueuers, such that any additional enqueuer
- /// will be unable to enqueue due to it not lining up with the expected
- /// sequence numbers. This value is chosen specially so that Tail will grow
- /// to a value that maps to the same slot but that won't be confused with
- /// any other enqueue/dequeue sequence number.
- /// </remarks>
- internal void EnsureFrozenForEnqueues() // must only be called while queue's segment lock is held
- {
- if (!_frozenForEnqueues) // flag used to ensure we don't increase the Tail more than once if frozen more than once
- {
- _frozenForEnqueues = true;
-
- // Increase the tail by FreezeOffset, spinning until we're successful in doing so.
- var spinner = new SpinWait();
- while (true)
- {
- int tail = Volatile.Read(ref _headAndTail.Tail);
- if (Interlocked.CompareExchange(ref _headAndTail.Tail, tail + FreezeOffset, tail) == tail)
- {
- break;
- }
- spinner.SpinOnce();
- }
- }
- }
-
- /// <summary>Tries to dequeue an element from the queue.</summary>
- public bool TryDequeue(out T item)
- {
- // Loop in case of contention...
- var spinner = new SpinWait();
- while (true)
- {
- // Get the head at which to try to dequeue.
- int currentHead = Volatile.Read(ref _headAndTail.Head);
- int slotsIndex = currentHead & _slotsMask;
-
- // Read the sequence number for the head position.
- int sequenceNumber = Volatile.Read(ref _slots[slotsIndex].SequenceNumber);
-
- // We can dequeue from this slot if it's been filled by an enqueuer, which
- // would have left the sequence number at pos+1.
- int diff = sequenceNumber - (currentHead + 1);
- if (diff == 0)
- {
- // We may be racing with other dequeuers. Try to reserve the slot by incrementing
- // the head. Once we've done that, no one else will be able to read from this slot,
- // and no enqueuer will be able to read from this slot until we've written the new
- // sequence number. WARNING: The next few lines are not reliable on a runtime that
- // supports thread aborts. If a thread abort were to sneak in after the CompareExchange
- // but before the Volatile.Write, enqueuers trying to enqueue into this slot would
- // spin indefinitely. If this implementation is ever used on such a platform, this
- // if block should be wrapped in a finally / prepared region.
- if (Interlocked.CompareExchange(ref _headAndTail.Head, currentHead + 1, currentHead) == currentHead)
- {
- // Successfully reserved the slot. Note that after the above CompareExchange, other threads
- // trying to dequeue from this slot will end up spinning until we do the subsequent Write.
- item = _slots[slotsIndex].Item;
- if (!Volatile.Read(ref _preservedForObservation))
- {
- // If we're preserving, though, we don't zero out the slot, as we need it for
- // enumerations, peeking, ToArray, etc. And we don't update the sequence number,
- // so that an enqueuer will see it as full and be forced to move to a new segment.
- _slots[slotsIndex].Item = default(T);
- Volatile.Write(ref _slots[slotsIndex].SequenceNumber, currentHead + _slots.Length);
- }
- return true;
- }
- }
- else if (diff < 0)
- {
- // The sequence number was less than what we needed, which means this slot doesn't
- // yet contain a value we can dequeue, i.e. the segment is empty. Technically it's
- // possible that multiple enqueuers could have written concurrently, with those
- // getting later slots actually finishing first, so there could be elements after
- // this one that are available, but we need to dequeue in order. So before declaring
- // failure and that the segment is empty, we check the tail to see if we're actually
- // empty or if we're just waiting for items in flight or after this one to become available.
- bool frozen = _frozenForEnqueues;
- int currentTail = Volatile.Read(ref _headAndTail.Tail);
- if (currentTail - currentHead <= 0 || (frozen && (currentTail - FreezeOffset - currentHead <= 0)))
- {
- item = default(T);
- return false;
- }
-
- // It's possible it could have become frozen after we checked _frozenForEnqueues
- // and before reading the tail. That's ok: in that rare race condition, we just
- // loop around again.
- }
-
- // Lost a race. Spin a bit, then try again.
- spinner.SpinOnce();
- }
- }
-
- /// <summary>Tries to peek at an element from the queue, without removing it.</summary>
- public bool TryPeek(out T result, bool resultUsed)
- {
- if (resultUsed)
- {
- // In order to ensure we don't get a torn read on the value, we mark the segment
- // as preserving for observation. Additional items can still be enqueued to this
- // segment, but no space will be freed during dequeues, such that the segment will
- // no longer be reusable.
- _preservedForObservation = true;
- Interlocked.MemoryBarrier();
- }
-
- // Loop in case of contention...
- var spinner = new SpinWait();
- while (true)
- {
- // Get the head at which to try to peek.
- int currentHead = Volatile.Read(ref _headAndTail.Head);
- int slotsIndex = currentHead & _slotsMask;
-
- // Read the sequence number for the head position.
- int sequenceNumber = Volatile.Read(ref _slots[slotsIndex].SequenceNumber);
-
- // We can peek from this slot if it's been filled by an enqueuer, which
- // would have left the sequence number at pos+1.
- int diff = sequenceNumber - (currentHead + 1);
- if (diff == 0)
- {
- result = resultUsed ? _slots[slotsIndex].Item : default(T);
- return true;
- }
- else if (diff < 0)
- {
- // The sequence number was less than what we needed, which means this slot doesn't
- // yet contain a value we can peek, i.e. the segment is empty. Technically it's
- // possible that multiple enqueuers could have written concurrently, with those
- // getting later slots actually finishing first, so there could be elements after
- // this one that are available, but we need to peek in order. So before declaring
- // failure and that the segment is empty, we check the tail to see if we're actually
- // empty or if we're just waiting for items in flight or after this one to become available.
- bool frozen = _frozenForEnqueues;
- int currentTail = Volatile.Read(ref _headAndTail.Tail);
- if (currentTail - currentHead <= 0 || (frozen && (currentTail - FreezeOffset - currentHead <= 0)))
- {
- result = default(T);
- return false;
- }
-
- // It's possible it could have become frozen after we checked _frozenForEnqueues
- // and before reading the tail. That's ok: in that rare race condition, we just
- // loop around again.
- }
-
- // Lost a race. Spin a bit, then try again.
- spinner.SpinOnce();
- }
- }
-
- /// <summary>
- /// Attempts to enqueue the item. If successful, the item will be stored
- /// in the queue and true will be returned; otherwise, the item won't be stored, and false
- /// will be returned.
- /// </summary>
- public bool TryEnqueue(T item)
- {
- // Loop in case of contention...
- var spinner = new SpinWait();
- while (true)
- {
- // Get the tail at which to try to return.
- int currentTail = Volatile.Read(ref _headAndTail.Tail);
- int slotsIndex = currentTail & _slotsMask;
-
- // Read the sequence number for the tail position.
- int sequenceNumber = Volatile.Read(ref _slots[slotsIndex].SequenceNumber);
-
- // The slot is empty and ready for us to enqueue into it if its sequence
- // number matches the slot.
- int diff = sequenceNumber - currentTail;
- if (diff == 0)
- {
- // We may be racing with other enqueuers. Try to reserve the slot by incrementing
- // the tail. Once we've done that, no one else will be able to write to this slot,
- // and no dequeuer will be able to read from this slot until we've written the new
- // sequence number. WARNING: The next few lines are not reliable on a runtime that
- // supports thread aborts. If a thread abort were to sneak in after the CompareExchange
- // but before the Volatile.Write, other threads will spin trying to access this slot.
- // If this implementation is ever used on such a platform, this if block should be
- // wrapped in a finally / prepared region.
- if (Interlocked.CompareExchange(ref _headAndTail.Tail, currentTail + 1, currentTail) == currentTail)
- {
- // Successfully reserved the slot. Note that after the above CompareExchange, other threads
- // trying to return will end up spinning until we do the subsequent Write.
- _slots[slotsIndex].Item = item;
- Volatile.Write(ref _slots[slotsIndex].SequenceNumber, currentTail + 1);
- return true;
- }
- }
- else if (diff < 0)
- {
- // The sequence number was less than what we needed, which means this slot still
- // contains a value, i.e. the segment is full. Technically it's possible that multiple
- // dequeuers could have read concurrently, with those getting later slots actually
- // finishing first, so there could be spaces after this one that are available, but
- // we need to enqueue in order.
- return false;
- }
-
- // Lost a race. Spin a bit, then try again.
- spinner.SpinOnce();
- }
- }
-
- /// <summary>Represents a slot in the queue.</summary>
- [StructLayout(LayoutKind.Auto)]
- [DebuggerDisplay("Item = {Item}, SequenceNumber = {SequenceNumber}")]
- internal struct Slot
- {
- /// <summary>The item.</summary>
- public T Item;
- /// <summary>The sequence number for this slot, used to synchronize between enqueuers and dequeuers.</summary>
- public int SequenceNumber;
- }
- }
- }
-
- /// <summary>Padded head and tail indices, to avoid false sharing between producers and consumers.</summary>
- [DebuggerDisplay("Head = {Head}, Tail = {Tail}")]
- [StructLayout(LayoutKind.Explicit, Size = 384)] // padding before/between/after fields based on worst case cache line size of 128
- internal struct PaddedHeadAndTail
- {
- [FieldOffset(128)] public int Head;
- [FieldOffset(256)] public int Tail;
}
}
diff --git a/src/System.Data.SqlClient/dir.props b/src/System.Data.SqlClient/dir.props
index fbff37a79f..2e27354ae7 100644
--- a/src/System.Data.SqlClient/dir.props
+++ b/src/System.Data.SqlClient/dir.props
@@ -2,7 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
- <AssemblyVersion>4.3.1.0</AssemblyVersion>
+ <AssemblyVersion>4.4.0.0</AssemblyVersion>
<AssemblyKey>MSFT</AssemblyKey>
<IsUAP>true</IsUAP>
</PropertyGroup>
diff --git a/src/System.Data.SqlClient/pkg/System.Data.SqlClient.pkgproj b/src/System.Data.SqlClient/pkg/System.Data.SqlClient.pkgproj
index d44c77ed26..66578cc337 100644
--- a/src/System.Data.SqlClient/pkg/System.Data.SqlClient.pkgproj
+++ b/src/System.Data.SqlClient/pkg/System.Data.SqlClient.pkgproj
@@ -3,13 +3,9 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Data.SqlClient.csproj">
- <SupportedFramework>net461;netcoreapp2.0;$(UAPvNextTFM);$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>net461;netcoreapp2.0;uap10.0.16299;$(UAPvNextTFM);$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Data.SqlClient.csproj" />
- <InboxOnTargetFramework Include="uap10.0.16299" />
- <File Include="$(PlaceHolderFile)">
- <TargetPath>runtimes/win/lib/uap10.0.16299</TargetPath>
- </File>
<HarvestIncludePaths Include="ref/net451;lib/net451;runtimes/win/lib/net451" />
<HarvestIncludePaths Include="ref/net46;lib/net46;runtimes/win/lib/net46" />
<HarvestIncludePaths Include="ref/netstandard1.2">
@@ -19,6 +15,15 @@
<SupportedFramework>net46;netcoreapp1.0</SupportedFramework>
</HarvestIncludePaths>
<HarvestIncludePaths Include="runtimes/unix/lib/netstandard1.3;runtimes/win/lib/netstandard1.3" />
+
+ <!-- Since UAP and .NETCoreApp are package based we still want to enable
+ OOBing libraries that happen to overlap with their framework package.
+ This avoids us having to lock the API in our NuGet packages just
+ to match what shipped inbox: since we can provide a new library
+ we can update it to add API without raising the netstandard version. -->
+ <ValidatePackageSuppression Include="TreatAsOutOfBox">
+ <Value>.NETCoreApp;UAP</Value>
+ </ValidatePackageSuppression>
</ItemGroup>
<ItemGroup>
<InboxOnTargetFramework Include="$(AllXamarinFrameworks)" />
diff --git a/src/System.Data.SqlClient/ref/Configurations.props b/src/System.Data.SqlClient/ref/Configurations.props
index d9777d8275..c994e0a316 100644
--- a/src/System.Data.SqlClient/ref/Configurations.props
+++ b/src/System.Data.SqlClient/ref/Configurations.props
@@ -4,6 +4,7 @@
<BuildConfigurations>
netstandard;
netfx;
+ netcoreapp;
</BuildConfigurations>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/System.Data.SqlClient/ref/System.Data.SqlClient.NetCoreApp.cs b/src/System.Data.SqlClient/ref/System.Data.SqlClient.NetCoreApp.cs
new file mode 100644
index 0000000000..967da8d258
--- /dev/null
+++ b/src/System.Data.SqlClient/ref/System.Data.SqlClient.NetCoreApp.cs
@@ -0,0 +1,14 @@
+// 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.
+// ------------------------------------------------------------------------------
+// Changes to this file must follow the http://aka.ms/api-review process.
+// ------------------------------------------------------------------------------
+
+namespace System.Data.SqlClient
+{
+ public partial class SqlDataReader : System.Data.Common.IDbColumnSchemaGenerator
+ {
+ public System.Collections.ObjectModel.ReadOnlyCollection<System.Data.Common.DbColumn> GetColumnSchema() { throw null; }
+ }
+}
diff --git a/src/System.Data.SqlClient/ref/System.Data.SqlClient.cs b/src/System.Data.SqlClient/ref/System.Data.SqlClient.cs
index ffe8d62b62..be6f1cf754 100644
--- a/src/System.Data.SqlClient/ref/System.Data.SqlClient.cs
+++ b/src/System.Data.SqlClient/ref/System.Data.SqlClient.cs
@@ -158,6 +158,7 @@ namespace Microsoft.SqlServer.Server
public SqlMetaData(string name, System.Data.SqlDbType dbType, long maxLength, long locale, System.Data.SqlTypes.SqlCompareOptions compareOptions, bool useServerDefault, bool isUniqueKey, System.Data.SqlClient.SortOrder columnSortOrder, int sortOrdinal) { }
public SqlMetaData(string name, System.Data.SqlDbType dbType, string database, string owningSchema, string objectName) { }
public SqlMetaData(string name, System.Data.SqlDbType dbType, string database, string owningSchema, string objectName, bool useServerDefault, bool isUniqueKey, System.Data.SqlClient.SortOrder columnSortOrder, int sortOrdinal) { }
+ public SqlMetaData(string name, System.Data.SqlDbType dbType, System.Type userDefinedType) { }
public SqlMetaData(string name, System.Data.SqlDbType dbType, System.Type userDefinedType, string serverTypeName) { }
public SqlMetaData(string name, System.Data.SqlDbType dbType, System.Type userDefinedType, string serverTypeName, bool useServerDefault, bool isUniqueKey, System.Data.SqlClient.SortOrder columnSortOrder, int sortOrdinal) { }
diff --git a/src/System.Data.SqlClient/ref/System.Data.SqlClient.csproj b/src/System.Data.SqlClient/ref/System.Data.SqlClient.csproj
index 4388a63c5a..e43848066d 100644
--- a/src/System.Data.SqlClient/ref/System.Data.SqlClient.csproj
+++ b/src/System.Data.SqlClient/ref/System.Data.SqlClient.csproj
@@ -4,24 +4,35 @@
<PropertyGroup>
<ProjectGuid>{D58E8D2B-3331-4660-8DFB-512D66F8EC63}</ProjectGuid>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
- <!-- Must match version supported by frameworks which support 4.3.* inbox.
- Can be removed when API is added and this assembly is versioned to 4.4.* -->
- <AssemblyVersion Condition="'$(TargetsNetFx)' != 'true'">4.3.1.0</AssemblyVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<ItemGroup>
- <SuppressPackageTargetFrameworkCompatibility Include="$(UAPvNextTFM)" />
+ <SuppressPackageTargetFrameworkCompatibility Include="$(UAPvNextTFM);uap10.0.16299" />
<Compile Include="System.Data.SqlClient.cs" />
<Compile Include="System.Data.SqlClient.Manual.cs" />
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
+ <Compile Include="System.Data.SqlClient.NetCoreApp.cs" />
+ </ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
+ <ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
+ <ProjectReference Include="..\..\System.Runtime.Extensions\ref\System.Runtime.Extensions.csproj" />
+ <ProjectReference Include="..\..\System.Data.Common\ref\System.Data.Common.csproj" />
+ <ProjectReference Include="..\..\System.Collections.NonGeneric\ref\System.Collections.NonGeneric.csproj" />
+ <ProjectReference Include="..\..\System.ComponentModel.Primitives\ref\System.ComponentModel.Primitives.csproj" />
+ <ProjectReference Include="..\..\System.Xml.ReaderWriter\ref\System.Xml.ReaderWriter.csproj" />
+ <ProjectReference Include="..\..\System.Runtime.InteropServices\ref\System.Runtime.InteropServices.csproj" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Data.SqlClient/src/Configurations.props b/src/System.Data.SqlClient/src/Configurations.props
index abd5922776..3be4b316f4 100644
--- a/src/System.Data.SqlClient/src/Configurations.props
+++ b/src/System.Data.SqlClient/src/Configurations.props
@@ -8,10 +8,14 @@
netstandard1.3;
netstandard;
netfx-Windows_NT;
+ netcoreapp;
+ netcoreapp-Unix;
+ netcoreapp-Windows_NT;
+ uap10.0.16299-Windows_NT;
+ uap-Windows_NT;
</PackageConfigurations>
<BuildConfigurations>
$(PackageConfigurations)
- uap-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt b/src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt
index 94d2d3a69f..3cd7225c50 100644
--- a/src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt
+++ b/src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt
@@ -1,5 +1,10 @@
+#
+# netstandard dll has been shipped with IDbColumnSchemaGenerator inherited and SqlDataReader.GetColumnScheme() implemented in source, but not exposed in ref contract.
+# Removing SqlDataReader.GetColumnScheme() from netstandard implementation potentially breaks existing customer source code
+# that utilizes SqlDataReader.GetColumnScheme() indirectly by casting SqlDataReader to IDbColumnSchemaGenerator type.
+# In order to prevent it, the API needs to be kept in public, and following 2 error message should be remaining in this baseline file.
+#
Compat issues with assembly System.Data.SqlClient:
-MembersMustExist : Member 'Microsoft.SqlServer.Server.SqlMetaData..ctor(System.String, System.Data.SqlDbType, System.Type)' does not exist in the implementation but it does exist in the contract.
CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlClient.SqlDataReader' does not implement interface 'System.Data.Common.IDbColumnSchemaGenerator' in the implementation but it does in the contract.
MembersMustExist : Member 'System.Data.SqlClient.SqlDataReader.GetColumnSchema()' does not exist in the implementation but it does exist in the contract.
-Total Issues: 3
+Total Issues: 2
diff --git a/src/System.Data.SqlClient/src/PinvokeAnalyzerExceptionList.analyzerdata.netcoreapp b/src/System.Data.SqlClient/src/PinvokeAnalyzerExceptionList.analyzerdata.netcoreapp
new file mode 100644
index 0000000000..5c0648966d
--- /dev/null
+++ b/src/System.Data.SqlClient/src/PinvokeAnalyzerExceptionList.analyzerdata.netcoreapp
@@ -0,0 +1,44 @@
+<!-- Not a bug. sni.dll is a native component that ships as part of the package. -->
+kernel32.dll!LoadLibraryExW
+sni.dll!GetSniMaxComposedSpnLength
+sni.dll!SNIAddProviderWrapper
+sni.dll!SNICheckConnectionWrapper
+sni.dll!SNICloseWrapper
+sni.dll!SNIGetInfoWrapper
+sni.dll!SNIGetLastError
+sni.dll!SNIInitialize
+sni.dll!SNIOpenSyncExWrapper
+sni.dll!SNIOpenWrapper
+sni.dll!SNIPacketAllocateWrapper
+sni.dll!SNIPacketGetDataWrapper
+sni.dll!SNIPacketRelease
+sni.dll!SNIPacketResetWrapper
+sni.dll!SNIPacketSetData
+sni.dll!SNIQueryInfo
+sni.dll!SNIReadAsyncWrapper
+sni.dll!SNIReadSyncOverAsync
+sni.dll!SNIRemoveProviderWrapper
+sni.dll!SNISecGenClientContextWrapper
+sni.dll!SNISecInitPackage
+sni.dll!SNISetInfoWrapper
+sni.dll!SNITerminate
+sni.dll!SNIWaitForSSLHandshakeToCompleteWrapper
+sni.dll!SNIWriteAsyncWrapper
+sni.dll!SNIWriteSyncOverAsync
+sni.dll!UnmanagedIsTokenRestricted
+sspicli.dll!AcceptSecurityContext
+sspicli.dll!AcquireCredentialsHandleW
+sspicli.dll!ApplyControlToken
+sspicli.dll!CompleteAuthToken
+sspicli.dll!DecryptMessage
+sspicli.dll!DeleteSecurityContext
+sspicli.dll!EncryptMessage
+sspicli.dll!EnumerateSecurityPackagesW
+sspicli.dll!FreeContextBuffer
+sspicli.dll!FreeCredentialsHandle
+sspicli.dll!InitializeSecurityContextW
+sspicli.dll!QueryContextAttributesW
+sspicli.dll!QuerySecurityContextToken
+sspicli.dll!SetContextAttributesW
+sspicli.dll!SspiEncodeStringsAsAuthIdentity
+sspicli.dll!SspiFreeAuthIdentity \ No newline at end of file
diff --git a/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj b/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj
index 7e2717d7ac..00cd509c4e 100644
--- a/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj
+++ b/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj
@@ -6,6 +6,7 @@
<AssemblyName>System.Data.SqlClient</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
+ <IsUAPAssembly Condition="'$(TargetGroup)' == 'uap' OR '$(TargetGroup)' == 'uap10.0.16299'">true</IsUAPAssembly>
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(OSGroup)' == 'AnyOS'">SR.PlatformNotSupported_DataSqlClient</GeneratePlatformNotSupportedAssemblyMessage>
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.2'">4.0.0.0</AssemblyVersion>
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.3'">4.1.0.0</AssemblyVersion>
@@ -14,6 +15,8 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Unix-Debug|AnyCPU'" />
@@ -24,7 +27,13 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.2-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Release|AnyCPU'" />
- <ItemGroup Condition="'$(TargetGroup)' == 'netstandard' OR '$(TargetGroup)' == 'uap' ">
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <ItemGroup Condition="'$(TargetGroup)' == 'netstandard' OR '$(TargetGroup)' == 'netcoreapp' OR '$(IsUAPAssembly)' == 'true' ">
<Compile Include="System.Data.SqlClient.TypeForwards.cs" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(OSGroup)' != 'AnyOS'">
@@ -221,10 +230,10 @@
<Compile Include="System\Data\SqlClient\SqlCredential.cs" />
</ItemGroup>
<!-- Manage the SNI toggle for Windows netstandard and UWP -->
- <ItemGroup Condition="'$(TargetGroup)' == 'netstandard' AND '$(TargetsWindows)' == 'true'">
+ <ItemGroup Condition="('$(TargetGroup)' == 'netstandard' OR '$(TargetGroup)' == 'netcoreapp') AND '$(TargetsWindows)' == 'true'">
<Compile Include="System\Data\SqlClient\TdsParserStateObjectFactory.Windows.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'uap'">
+ <ItemGroup Condition="'$(IsUAPAssembly)' == 'true'">
<Compile Include="System\Data\SqlClient\TdsParserStateObjectFactory.Managed.cs" />
<Compile Include="System\Data\SqlClient\LocalDBAPI.uap.cs" />
<Compile Include="System\Data\SqlClient\SNI\LocalDB.uap.cs" />
@@ -232,7 +241,7 @@
<Compile Include="System\Data\SqlClient\TdsParser.Unix.cs" />
</ItemGroup>
<!-- Assets needed on Windows but should be avoided on UAP to avoid sni.dll -->
- <ItemGroup Condition=" '$(TargetsWindows)' == 'true' And '$(IsPartialFacadeAssembly)' != 'true' and '$(TargetGroup)' != 'uap' ">
+ <ItemGroup Condition=" '$(TargetsWindows)' == 'true' And '$(IsPartialFacadeAssembly)' != 'true' and '$(IsUAPAssembly)' != 'true'">
<Compile Include="System\Data\SqlClient\TdsParserStateObjectNative.cs" />
<Compile Include="Interop\SNINativeMethodWrapper.Windows.cs" />
<Compile Include="System\Data\SqlClient\TdsParserSafeHandles.cs" />
@@ -427,7 +436,7 @@
<Compile Include="System\Data\SqlClient\LocalDBAPI.Unix.cs" />
<Compile Include="System\Data\SqlClient\SNI\LocalDB.Unix.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetsWindows)' == 'true' And '$(IsPartialFacadeAssembly)' != 'true' and '$(TargetGroup)' != 'uap'">
+ <ItemGroup Condition="'$(TargetsWindows)' == 'true' And '$(IsPartialFacadeAssembly)' != 'true' and '$(IsUAPAssembly)' != 'true'">
<Reference Include="Microsoft.Win32.Registry" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
@@ -472,7 +481,7 @@
<Reference Include="System.Net.NameResolution" />
<Reference Include="System.Diagnostics.Tracing" />
</ItemGroup>
- <ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'uap'">
+ <ItemGroup Condition="('$(OSGroup)' != 'AnyOS' AND '$(IsUAPAssembly)' == 'true') OR '$(TargetGroup)' == 'netcoreapp'">
<Reference Include="System.Transactions.Local" />
<Reference Include="System.Collections.NonGeneric" />
</ItemGroup>
@@ -485,6 +494,13 @@
<LogicalName>System.Data.SqlClient.SqlMetaData.xml</LogicalName>
</EmbeddedResource>
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
+ <Reference Include="System.Runtime.Extensions" />
+ <Reference Include="System.Data.Common" />
+ <Reference Include="System.ComponentModel.Primitives" />
+ <Reference Include="System.Xml.ReaderWriter" />
+ <Reference Include="System.Runtime.InteropServices" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
<Import Project=".\GenerateThisAssemblyCs.targets" Condition="'$(IsPartialFacadeAssembly)' != 'true'" />
</Project> \ No newline at end of file
diff --git a/src/System.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs b/src/System.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs
index 91716293e9..27758ef22a 100644
--- a/src/System.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs
+++ b/src/System.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs
@@ -2,12 +2,9 @@
// 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.Generic;
using System.Data.Common;
-using System.Diagnostics;
using System.Reflection;
using System.Security;
-using System.Threading;
using Xunit;
namespace System.Data.SqlClient.Tests
@@ -107,35 +104,6 @@ namespace System.Data.SqlClient.Tests
Assert.Equal(expected, conn.WorkstationId);
}
- [Fact]
- public void ConnectionTimeoutTestWithThread()
- {
- int timeoutSec = 5;
- string connStrNotAvailable = $"Server=tcp:fakeServer,1433;uid=fakeuser;pwd=fakepwd;Connection Timeout={timeoutSec}";
-
- List<ConnectionWorker> list = new List<ConnectionWorker>();
- for (int i = 0; i < 10; ++i)
- {
- list.Add(new ConnectionWorker(connStrNotAvailable));
- }
-
- ConnectionWorker.Start();
- ConnectionWorker.Stop();
-
- double theMax = 0;
- foreach (ConnectionWorker w in list)
- {
- if (theMax < w.MaxTimeElapsed)
- {
- theMax = w.MaxTimeElapsed;
- }
- }
-
- int threshold = (timeoutSec + 1) * 1000;
-
- Console.WriteLine($"ConnectionTimeoutTestWithThread: Elapsed Time {theMax} and threshold {threshold}");
- }
-
[OuterLoop("Can take up to 4 seconds")]
[Fact]
public void ExceptionsWithMinPoolSizeCanBeHandled()
@@ -195,69 +163,5 @@ namespace System.Data.SqlClient.Tests
Assert.Equal(sqlCredential, conn.Credential);
}
-
- public class ConnectionWorker
- {
- private static ManualResetEventSlim startEvent = new ManualResetEventSlim(false);
- private static List<ConnectionWorker> workerList = new List<ConnectionWorker>();
- private ManualResetEventSlim doneEvent = new ManualResetEventSlim(false);
- private double maxTimeElapsed;
- private Thread thread;
- private string connectionString;
-
- public ConnectionWorker(string connectionString)
- {
- workerList.Add(this);
- this.connectionString = connectionString;
- thread = new Thread(new ThreadStart(SqlConnectionOpen));
- thread.Start();
- }
-
- public double MaxTimeElapsed
- {
- get
- {
- return maxTimeElapsed;
- }
- }
-
- public static void Start()
- {
- startEvent.Set();
- }
-
- public static void Stop()
- {
- foreach (ConnectionWorker w in workerList)
- {
- w.doneEvent.Wait();
- }
- }
-
- public void SqlConnectionOpen()
- {
- startEvent.Wait();
-
- Stopwatch sw = new Stopwatch();
- using (SqlConnection con = new SqlConnection(connectionString))
- {
- sw.Start();
- try
- {
- con.Open();
- }
- catch { }
- sw.Stop();
- }
-
- double elapsed = sw.Elapsed.TotalMilliseconds;
- if (maxTimeElapsed < elapsed)
- {
- maxTimeElapsed = elapsed;
- }
-
- doneEvent.Set();
- }
- }
}
}
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs
index 94569a4800..7d2a176f3c 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs
@@ -2,6 +2,9 @@
// 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.Generic;
+using System.Diagnostics;
+using System.Threading;
using Xunit;
namespace System.Data.SqlClient.ManualTesting.Tests
@@ -45,5 +48,102 @@ namespace System.Data.SqlClient.ManualTesting.Tests
}
Assert.True(false, "No non-empty hostname found for the application");
}
+
+ [CheckConnStrSetupFact]
+ public static void ConnectionTimeoutTestWithThread()
+ {
+ const int timeoutSec = 5;
+ const int numOfTry = 2;
+ const int numOfThreads = 5;
+
+ SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(DataTestUtility.TcpConnStr);
+ builder.DataSource = "invalidhost";
+ builder.ConnectTimeout = timeoutSec;
+ string connStrNotAvailable = builder.ConnectionString;
+
+ for (int i = 0; i < numOfThreads; ++i)
+ {
+ new ConnectionWorker(connStrNotAvailable, numOfTry);
+ }
+
+ ConnectionWorker.Start();
+ ConnectionWorker.Stop();
+
+ double timeTotal = 0;
+ double timeElapsed = 0;
+
+ foreach (ConnectionWorker w in ConnectionWorker.WorkerList)
+ {
+ timeTotal += w.TimeElapsed;
+ }
+ timeElapsed = timeTotal / Convert.ToDouble(ConnectionWorker.WorkerList.Count);
+
+ int threshold = timeoutSec * numOfTry * 2 * 1000;
+
+ Assert.True(timeElapsed < threshold);
+ }
+
+ public class ConnectionWorker
+ {
+ private static List<ConnectionWorker> workerList = new List<ConnectionWorker>();
+ private ManualResetEventSlim _doneEvent = new ManualResetEventSlim(false);
+ private double _timeElapsed;
+ private Thread _thread;
+ private string _connectionString;
+ private int _numOfTry;
+
+ public ConnectionWorker(string connectionString, int numOfTry)
+ {
+ workerList.Add(this);
+ _connectionString = connectionString;
+ _numOfTry = numOfTry;
+ _thread = new Thread(new ThreadStart(SqlConnectionOpen));
+ }
+
+ public static List<ConnectionWorker> WorkerList => workerList;
+
+ public double TimeElapsed => _timeElapsed;
+
+ public static void Start()
+ {
+ foreach (ConnectionWorker w in workerList)
+ {
+ w._thread.Start();
+ }
+ }
+
+ public static void Stop()
+ {
+ foreach (ConnectionWorker w in workerList)
+ {
+ w._doneEvent.Wait();
+ }
+ }
+
+ public void SqlConnectionOpen()
+ {
+ Stopwatch sw = new Stopwatch();
+ double totalTime = 0;
+ for (int i = 0; i < _numOfTry; ++i)
+ {
+ using (SqlConnection con = new SqlConnection(_connectionString))
+ {
+ sw.Start();
+ try
+ {
+ con.Open();
+ }
+ catch { }
+ sw.Stop();
+ }
+ totalTime += sw.Elapsed.TotalMilliseconds;
+ sw.Reset();
+ }
+
+ _timeElapsed = totalTime / Convert.ToDouble(_numOfTry);
+
+ _doneEvent.Set();
+ }
+ }
}
}
diff --git a/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs b/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs
index ac99b1825d..5f6db29e67 100644
--- a/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs
+++ b/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs
@@ -343,28 +343,21 @@ namespace System.Diagnostics.Tests
}
[Fact]
- public void TestWorkingDirectoryProperty()
+ public void TestWorkingDirectoryPropertyDefaultCase()
{
CreateDefaultProcess();
// check defaults
Assert.Equal(string.Empty, _process.StartInfo.WorkingDirectory);
+ }
- Process p = CreateProcessLong();
- p.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory();
-
- try
- {
- p.Start();
- Assert.Equal(Directory.GetCurrentDirectory(), p.StartInfo.WorkingDirectory);
- }
- finally
- {
- if (!p.HasExited)
- p.Kill();
-
- Assert.True(p.WaitForExit(WaitInMS));
- }
+ [Fact]
+ public void TestWorkingDirectoryPropertyInChildProcess()
+ {
+ string workingDirectory = string.IsNullOrEmpty(Environment.SystemDirectory) ? TestDirectory : Environment.SystemDirectory ;
+ Assert.NotEqual(workingDirectory, Directory.GetCurrentDirectory());
+ var psi = new ProcessStartInfo { WorkingDirectory = workingDirectory };
+ RemoteInvoke(wd => { Assert.Equal(wd, Directory.GetCurrentDirectory()); return SuccessExitCode; }, workingDirectory, new RemoteInvokeOptions { StartInfo = psi }).Dispose();
}
[ActiveIssue(12696)]
diff --git a/src/System.Diagnostics.Process/tests/ProcessTests.cs b/src/System.Diagnostics.Process/tests/ProcessTests.cs
index aa94bfd54b..fd6641c935 100644
--- a/src/System.Diagnostics.Process/tests/ProcessTests.cs
+++ b/src/System.Diagnostics.Process/tests/ProcessTests.cs
@@ -1624,15 +1624,15 @@ namespace System.Diagnostics.Tests
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "Retrieving information about local processes is not supported on uap")]
public void Process_StartTest()
{
- string currentProcessName = GetCurrentProcessName();
+ string name = "xcopy.exe";
string userName = string.Empty;
string domain = "thisDomain";
SecureString password = AsSecureString("Value");
- using (Process p = Process.Start(currentProcessName, userName, password, domain)) // This writes junk to the Console but with this overload, we can't prevent that.
+ using (Process p = Process.Start(name, userName, password, domain)) // This writes junk to the Console but with this overload, we can't prevent that.
{
Assert.NotNull(p);
- Assert.Equal(currentProcessName, p.StartInfo.FileName);
+ Assert.Equal(name, p.StartInfo.FileName);
Assert.Equal(userName, p.StartInfo.UserName);
Assert.Same(password, p.StartInfo.Password);
Assert.Equal(domain, p.StartInfo.Domain);
diff --git a/src/System.Drawing.Common/src/System.Drawing.Common.csproj b/src/System.Drawing.Common/src/System.Drawing.Common.csproj
index 220c41fc08..24386b8700 100644
--- a/src/System.Drawing.Common/src/System.Drawing.Common.csproj
+++ b/src/System.Drawing.Common/src/System.Drawing.Common.csproj
@@ -214,6 +214,7 @@
<Compile Include="System\Drawing\Drawing2D\CustomLineCap.Windows.cs" />
<Compile Include="System\Drawing\Drawing2D\GraphicsPath.Windows.cs" />
<Compile Include="System\Drawing\Font.Windows.cs" />
+ <Compile Include="System\Drawing\FontFamily.Windows.cs" />
<Compile Include="System\Drawing\GdiplusNative.Windows.cs" />
<Compile Include="System\Drawing\Graphics.Windows.cs" />
<Compile Include="System\Drawing\GraphicsContext.cs" />
@@ -314,6 +315,7 @@
<Compile Include="System\Drawing\BufferedGraphicsContext.Unix.cs" />
<Compile Include="System\Drawing\macFunctions.cs" />
<Compile Include="System\Drawing\Font.Unix.cs" />
+ <Compile Include="System\Drawing\FontFamily.Unix.cs" />
<Compile Include="System\Drawing\GdiplusNative.Unix.cs" />
<Compile Include="System\Drawing\GdiPlusStreamHelper.Unix.cs" />
<Compile Include="System\Drawing\LibX11Functions.cs" />
diff --git a/src/System.Drawing.Common/src/System/Drawing/FontFamily.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/FontFamily.Unix.cs
new file mode 100644
index 0000000000..277da4cad1
--- /dev/null
+++ b/src/System.Drawing.Common/src/System/Drawing/FontFamily.Unix.cs
@@ -0,0 +1,30 @@
+// 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.
+
+namespace System.Drawing
+{
+ /// <summary>
+ /// Abstracts a group of type faces having a similar basic design but having certain variation in styles.
+ /// </summary>
+ public sealed partial class FontFamily : MarshalByRefObject, IDisposable
+ {
+ public override bool Equals(object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ // if obj = null then (obj is FontFamily) = false.
+ if (!(obj is FontFamily otherFamily))
+ {
+ return false;
+ }
+
+ // In unix FontFamily objects are not singleton so they don't share the same native pointer,
+ // the best we have to know if they are the same is FontFamily.Name which gets resolved from the native pointer.
+ return Name.Equals(otherFamily.Name, StringComparison.Ordinal);
+ }
+ }
+}
diff --git a/src/System.Drawing.Common/src/System/Drawing/FontFamily.Windows.cs b/src/System.Drawing.Common/src/System/Drawing/FontFamily.Windows.cs
new file mode 100644
index 0000000000..196f58c5d8
--- /dev/null
+++ b/src/System.Drawing.Common/src/System/Drawing/FontFamily.Windows.cs
@@ -0,0 +1,30 @@
+// 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.
+
+namespace System.Drawing
+{
+ /// <summary>
+ /// Abstracts a group of type faces having a similar basic design but having certain variation in styles.
+ /// </summary>
+ public sealed partial class FontFamily : MarshalByRefObject, IDisposable
+ {
+ public override bool Equals(object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ // if obj = null then (obj is FontFamily) = false.
+ if (!(obj is FontFamily otherFamily))
+ {
+ return false;
+ }
+
+ // We can safely use the ptr to the native GDI+ FontFamily because in windows it is common to
+ // all objects of the same family (singleton RO object).
+ return otherFamily.NativeFamily == NativeFamily;
+ }
+ }
+}
diff --git a/src/System.Drawing.Common/src/System/Drawing/FontFamily.cs b/src/System.Drawing.Common/src/System/Drawing/FontFamily.cs
index f77dce68a9..4228c63a36 100644
--- a/src/System.Drawing.Common/src/System/Drawing/FontFamily.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/FontFamily.cs
@@ -14,7 +14,7 @@ namespace System.Drawing
/// <summary>
/// Abstracts a group of type faces having a similar basic design but having certain variation in styles.
/// </summary>
- public sealed class FontFamily : MarshalByRefObject, IDisposable
+ public sealed partial class FontFamily : MarshalByRefObject, IDisposable
{
private const int NeutralLanguage = 0;
private IntPtr _nativeFamily;
@@ -132,23 +132,6 @@ namespace System.Drawing
internal IntPtr NativeFamily => _nativeFamily;
- public override bool Equals(object obj)
- {
- if (obj == this)
- {
- return true;
- }
-
- if (!(obj is FontFamily otherFamily))
- {
- return false;
- }
-
- // We can safely use the ptr to the native GDI+ FontFamily because it is common to
- // all objects of the same family (singleton RO object).
- return otherFamily.NativeFamily == NativeFamily;
- }
-
/// <summary>
/// Converts this <see cref='FontFamily'/> to a human-readable string.
/// </summary>
diff --git a/src/System.Drawing.Common/tests/FontTests.cs b/src/System.Drawing.Common/tests/FontTests.cs
index da541f5297..5a7b2a3810 100644
--- a/src/System.Drawing.Common/tests/FontTests.cs
+++ b/src/System.Drawing.Common/tests/FontTests.cs
@@ -16,6 +16,51 @@ namespace System.Drawing.Tests
yield return new object[] { FontFamily.GenericSerif, float.MaxValue };
}
+ public static IEnumerable<object[]> FontFamily_Equals_SameFamily_TestData()
+ {
+ yield return new object[] { FontFamily.GenericMonospace, 1 };
+ yield return new object[] { FontFamily.GenericSerif, float.MaxValue };
+ yield return new object[] { FontFamily.GenericSansSerif, 10 };
+ }
+
+ public static IEnumerable<object[]> FontFamily_Equals_DifferentFamily_TestData()
+ {
+ yield return new object[] { FontFamily.GenericMonospace, FontFamily.GenericSerif };
+ yield return new object[] { FontFamily.GenericSansSerif, FontFamily.GenericSerif };
+ yield return new object[] { FontFamily.GenericSansSerif, FontFamily.GenericMonospace };
+ }
+
+ [ConditionalTheory(Helpers.GdiplusIsAvailable)]
+ [MemberData(nameof(FontFamily_Equals_SameFamily_TestData))]
+ public void Font_Equals_SameFontFamily(FontFamily fontFamily, float size)
+ {
+ using (var font1 = new Font(fontFamily, size))
+ using (var font2 = new Font(fontFamily, size))
+ {
+ Assert.True(font1.Equals(font2));
+ }
+ }
+
+ [ConditionalTheory(Helpers.GdiplusIsAvailable)]
+ [MemberData(nameof(FontFamily_Equals_DifferentFamily_TestData))]
+ public void Font_Equals_DifferentFontFamily(FontFamily fontFamily1, FontFamily fontFamily2)
+ {
+ using (var font1 = new Font(fontFamily1, 9))
+ using (var font2 = new Font(fontFamily2, 9))
+ {
+ // In some Linux distros all the default fonts live under the same family (Fedora, Centos, Redhat)
+ if (font1.FontFamily.GetHashCode() != font2.FontFamily.GetHashCode())
+ Assert.False(font1.Equals(font2));
+ }
+ }
+
+ [ConditionalFact(Helpers.GdiplusIsAvailable)]
+ public void FontFamily_Equals_NullObject()
+ {
+ FontFamily nullFamily = null;
+ Assert.False(FontFamily.GenericMonospace.Equals(nullFamily));
+ }
+
[ActiveIssue(20884, TestPlatforms.AnyUnix)]
[ConditionalTheory(Helpers.GdiplusIsAvailable)]
[MemberData(nameof(Ctor_Family_Size_TestData))]
diff --git a/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs b/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs
index 69c914be7d..11a7d11247 100644
--- a/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs
+++ b/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs
@@ -91,8 +91,6 @@ namespace System.IO.Compression
internal unsafe void SetInput(ReadOnlyMemory<byte> inputBuffer)
{
Debug.Assert(NeedsInput(), "We have something left in previous input!");
- Debug.Assert(!_inputBufferHandle.HasPointer);
-
if (0 == inputBuffer.Length)
{
return;
@@ -111,7 +109,6 @@ namespace System.IO.Compression
{
Debug.Assert(NeedsInput(), "We have something left in previous input!");
Debug.Assert(inputBufferPtr != null);
- Debug.Assert(!_inputBufferHandle.HasPointer);
if (count == 0)
{
@@ -182,7 +179,6 @@ namespace System.IO.Compression
Debug.Assert(null != outputBuffer, "Can't pass in a null output buffer!");
Debug.Assert(outputBuffer.Length > 0, "Can't pass in an empty output buffer!");
Debug.Assert(NeedsInput(), "We have something left in previous input!");
- Debug.Assert(!_inputBufferHandle.HasPointer);
// Note: we require that NeedsInput() == true, i.e. that 0 == _zlibStream.AvailIn.
diff --git a/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Unix.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Unix.cs
index a1dde7fb2b..26f6d7f6f3 100644
--- a/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Unix.cs
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Unix.cs
@@ -107,60 +107,66 @@ namespace System.IO.Enumeration
if (_lastEntryFound)
return false;
- do
+ // If HAVE_READDIR_R is defined for the platform FindNextEntry depends on _entryBuffer being fixed since
+ // _entry will point to a string in the middle of the array. If the array is not fixed GC can move it after
+ // the native call and _entry will point to a bogus file name.
+ fixed (byte* _ = _entryBuffer)
{
- FindNextEntry();
- if (_lastEntryFound)
- return false;
+ do
+ {
+ FindNextEntry();
+ if (_lastEntryFound)
+ return false;
- FileAttributes attributes = FileSystemEntry.Initialize(
- ref entry, _entry, _currentPath, _rootDirectory, _originalRootDirectory, new Span<char>(_pathBuffer));
- bool isDirectory = (attributes & FileAttributes.Directory) != 0;
+ FileAttributes attributes = FileSystemEntry.Initialize(
+ ref entry, _entry, _currentPath, _rootDirectory, _originalRootDirectory, new Span<char>(_pathBuffer));
+ bool isDirectory = (attributes & FileAttributes.Directory) != 0;
- bool isSpecialDirectory = false;
- if (isDirectory)
- {
- // Subdirectory found
- if (_entry.Name[0] == '.' && (_entry.Name[1] == 0 || (_entry.Name[1] == '.' && _entry.Name[2] == 0)))
+ bool isSpecialDirectory = false;
+ if (isDirectory)
{
- // "." or "..", don't process unless the option is set
- if (!_options.ReturnSpecialDirectories)
- continue;
- isSpecialDirectory = true;
+ // Subdirectory found
+ if (_entry.Name[0] == '.' && (_entry.Name[1] == 0 || (_entry.Name[1] == '.' && _entry.Name[2] == 0)))
+ {
+ // "." or "..", don't process unless the option is set
+ if (!_options.ReturnSpecialDirectories)
+ continue;
+ isSpecialDirectory = true;
+ }
}
- }
- if (!isSpecialDirectory && _options.AttributesToSkip != 0)
- {
- if ((_options.AttributesToSkip & FileAttributes.ReadOnly) != 0)
+ if (!isSpecialDirectory && _options.AttributesToSkip != 0)
{
- // ReadOnly is the only attribute that requires hitting entry.Attributes (which hits the disk)
- attributes = entry.Attributes;
+ if ((_options.AttributesToSkip & FileAttributes.ReadOnly) != 0)
+ {
+ // ReadOnly is the only attribute that requires hitting entry.Attributes (which hits the disk)
+ attributes = entry.Attributes;
+ }
+
+ if ((_options.AttributesToSkip & attributes) != 0)
+ {
+ continue;
+ }
}
- if ((_options.AttributesToSkip & attributes) != 0)
+ if (isDirectory && !isSpecialDirectory)
{
- continue;
+ if (_options.RecurseSubdirectories && ShouldRecurseIntoEntry(ref entry))
+ {
+ // Recursion is on and the directory was accepted, Queue it
+ if (_pending == null)
+ _pending = new Queue<string>();
+ _pending.Enqueue(Path.Join(_currentPath, entry.FileName));
+ }
}
- }
- if (isDirectory && !isSpecialDirectory)
- {
- if (_options.RecurseSubdirectories && ShouldRecurseIntoEntry(ref entry))
+ if (ShouldIncludeEntry(ref entry))
{
- // Recursion is on and the directory was accepted, Queue it
- if (_pending == null)
- _pending = new Queue<string>();
- _pending.Enqueue(Path.Join(_currentPath, entry.FileName));
+ _current = TransformEntry(ref entry);
+ return true;
}
- }
-
- if (ShouldIncludeEntry(ref entry))
- {
- _current = TransformEntry(ref entry);
- return true;
- }
- } while (true);
+ } while (true);
+ }
}
}
diff --git a/src/System.IO.FileSystem/tests/FileStream/ReadWriteSpan.netcoreapp.cs b/src/System.IO.FileSystem/tests/FileStream/ReadWriteSpan.netcoreapp.cs
index 0b1898d1f5..187c7788be 100644
--- a/src/System.IO.FileSystem/tests/FileStream/ReadWriteSpan.netcoreapp.cs
+++ b/src/System.IO.FileSystem/tests/FileStream/ReadWriteSpan.netcoreapp.cs
@@ -189,13 +189,13 @@ namespace System.IO.Tests
}
[Fact]
- public async Task NonEmptyFile_CustomOwnedMemory_ReadAsync_GetsExpectedData()
+ public async Task NonEmptyFile_CustomMemoryManager_ReadAsync_GetsExpectedData()
{
string fileName = GetTestFilePath();
File.WriteAllBytes(fileName, TestBuffer);
using (var fs = CreateFileStream(fileName, FileMode.Open))
- using (var buffer = new NativeOwnedMemory(TestBuffer.Length))
+ using (var buffer = new NativeMemoryManager(TestBuffer.Length))
{
Assert.Equal(TestBuffer.Length, await fs.ReadAsync(buffer.Memory));
Assert.Equal<byte>(TestBuffer, buffer.Memory.ToArray());
@@ -255,9 +255,9 @@ namespace System.IO.Tests
}
[Fact]
- public async Task NonEmptyWriteAsync_CustomOwnedMemory_WritesExpectedData()
+ public async Task NonEmptyWriteAsync_CustomMemoryManager_WritesExpectedData()
{
- using (var mem = new NativeOwnedMemory(TestBuffer.Length))
+ using (var mem = new NativeMemoryManager(TestBuffer.Length))
using (var fs = CreateFileStream(GetTestFilePath(), FileMode.Create))
{
new Memory<byte>(TestBuffer).CopyTo(mem.Memory);
diff --git a/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj b/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj
index 7597996101..3a25873cb3 100644
--- a/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj
+++ b/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj
@@ -177,8 +177,8 @@
<Compile Include="FileInfo\AppendText.cs" />
<Compile Include="FileInfo\CopyTo.cs" />
<!-- Helpers -->
- <Compile Include="$(CommonTestPath)\System\Buffers\NativeOwnedMemory.cs">
- <Link>Common\System\Buffers\NativeOwnedMemory.cs</Link>
+ <Compile Include="$(CommonTestPath)\System\Buffers\NativeMemoryManager.cs">
+ <Link>Common\System\Buffers\NativeMemoryManager.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\IO\TempFile.cs">
<Link>Common\System\IO\TempFile.cs</Link>
diff --git a/src/System.IO.Pipelines/ref/System.IO.Pipelines.cs b/src/System.IO.Pipelines/ref/System.IO.Pipelines.cs
index 7f3b7704e1..ba3b46a707 100644
--- a/src/System.IO.Pipelines/ref/System.IO.Pipelines.cs
+++ b/src/System.IO.Pipelines/ref/System.IO.Pipelines.cs
@@ -29,7 +29,7 @@ namespace System.IO.Pipelines
}
public partial class PipeOptions
{
- public PipeOptions(System.Buffers.MemoryPool<byte> pool = null, System.IO.Pipelines.PipeScheduler readerScheduler = null, System.IO.Pipelines.PipeScheduler writerScheduler = null, long pauseWriterThreshold = (long)0, long resumeWriterThreshold = (long)0, int minimumSegmentSize = 2048, bool useSynchronizationContext = true) { }
+ public PipeOptions(System.Buffers.MemoryPool<byte> pool = null, System.IO.Pipelines.PipeScheduler readerScheduler = null, System.IO.Pipelines.PipeScheduler writerScheduler = null, long pauseWriterThreshold = (long)32768, long resumeWriterThreshold = (long)16384, int minimumSegmentSize = 2048, bool useSynchronizationContext = true) { }
public static System.IO.Pipelines.PipeOptions Default { get { throw null; } }
public int MinimumSegmentSize { get { throw null; } }
public long PauseWriterThreshold { get { throw null; } }
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs
index 511e327af0..659aa71638 100644
--- a/src/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs
@@ -9,7 +9,7 @@ namespace System.IO.Pipelines
{
internal sealed class BufferSegment : ReadOnlySequenceSegment<byte>
{
- private OwnedMemory<byte> _ownedMemory;
+ private IMemoryOwner<byte> _memoryOwner;
private BufferSegment _next;
private int _end;
@@ -53,16 +53,16 @@ namespace System.IO.Pipelines
}
}
- public void SetMemory(OwnedMemory<byte> buffer)
+ public void SetMemory(IMemoryOwner<byte> memoryOwner)
{
- SetMemory(buffer, 0, 0);
+ SetMemory(memoryOwner, 0, 0);
}
- public void SetMemory(OwnedMemory<byte> ownedMemory, int start, int end, bool readOnly = false)
+ public void SetMemory(IMemoryOwner<byte> memoryOwner, int start, int end, bool readOnly = false)
{
- _ownedMemory = ownedMemory;
+ _memoryOwner = memoryOwner;
- AvailableMemory = _ownedMemory.Memory;
+ AvailableMemory = _memoryOwner.Memory;
ReadOnly = readOnly;
RunningIndex = 0;
@@ -73,12 +73,12 @@ namespace System.IO.Pipelines
public void ResetMemory()
{
- _ownedMemory.Release();
- _ownedMemory = null;
+ _memoryOwner.Dispose();
+ _memoryOwner = null;
AvailableMemory = default;
}
- internal OwnedMemory<byte> OwnedMemory => _ownedMemory;
+ internal IMemoryOwner<byte> MemoryOwner => _memoryOwner;
public Memory<byte> AvailableMemory { get; private set; }
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs
index 107957c741..96aaefb967 100644
--- a/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs
@@ -224,12 +224,12 @@ namespace System.IO.Pipelines
}
}
- internal void CommitUnsynchronized()
+ internal bool CommitUnsynchronized()
{
if (_writingHead == null)
{
// Nothing written to commit
- return;
+ return true;
}
if (_readHead == null)
@@ -241,9 +241,10 @@ namespace System.IO.Pipelines
}
// Always move the commit head to the write head
+ var bytesWritten = _currentWriteLength;
_commitHead = _writingHead;
_commitHeadIndex = _writingHead.End;
- _length += _currentWriteLength;
+ _length += bytesWritten;
// Do not reset if reader is complete
if (_pauseWriterThreshold > 0 &&
@@ -256,6 +257,8 @@ namespace System.IO.Pipelines
// Clear the writing state
_writingHead = null;
_currentWriteLength = 0;
+
+ return bytesWritten == 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -296,12 +299,24 @@ namespace System.IO.Pipelines
ValueTask<FlushResult> result;
lock (_sync)
{
- CommitUnsynchronized();
+ var wasEmpty = CommitUnsynchronized();
// AttachToken before completing reader awaiter in case cancellationToken is already completed
cancellationTokenRegistration = _writerAwaitable.AttachToken(cancellationToken, s_signalWriterAwaitable, this);
- _readerAwaitable.Complete(out completionData);
+ // Complete reader only if new data was pushed into the pipe
+ if (!wasEmpty)
+ {
+ _readerAwaitable.Complete(out completionData);
+ }
+ else
+ {
+ completionData = default;
+ }
+
+ // I couldn't find a way for flush to induce backpressure deadlock
+ // if it always adds new data to pipe and wakes up the reader but assert anyway
+ Debug.Assert(_writerAwaitable.IsCompleted || _readerAwaitable.IsCompleted);
// If the writer is completed (which it will be most of the time) the return a completed ValueTask
if (_writerAwaitable.IsCompleted)
diff --git a/src/System.IO.Pipelines/tests/BackpressureTests.cs b/src/System.IO.Pipelines/tests/BackpressureTests.cs
index c35d01193b..a4e67f057d 100644
--- a/src/System.IO.Pipelines/tests/BackpressureTests.cs
+++ b/src/System.IO.Pipelines/tests/BackpressureTests.cs
@@ -9,10 +9,13 @@ namespace System.IO.Pipelines.Tests
{
public class BackpressureTests : IDisposable
{
+ private const int PauseWriterThreshold = 64;
+ private const int ResumeWriterThreshold = 32;
+
public BackpressureTests()
{
_pool = new TestMemoryPool();
- _pipe = new Pipe(new PipeOptions(_pool, resumeWriterThreshold: 32, pauseWriterThreshold: 64, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ _pipe = new Pipe(new PipeOptions(_pool, resumeWriterThreshold: ResumeWriterThreshold, pauseWriterThreshold: PauseWriterThreshold, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
}
public void Dispose()
@@ -29,7 +32,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void AdvanceThrowsIfFlushActiveAndNotConsumedPastThreshold()
{
- PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
Assert.False(flushAsync.IsCompleted);
@@ -41,9 +44,24 @@ namespace System.IO.Pipelines.Tests
}
[Fact]
+ public async Task AdvanceThrowsIfFlushActiveAndNotConsumedPastThresholdWhenFlushIsCanceled()
+ {
+ // Write over the threshold and cancel pending flush
+ _pipe.Writer.WriteEmpty(PauseWriterThreshold);
+ var task = _pipe.Writer.FlushAsync().AsTask();
+ _pipe.Writer.CancelPendingFlush();
+
+ await task;
+
+ // Examine to the end without releasing backpressure
+ var result = await _pipe.Reader.ReadAsync();
+ Assert.Throws<InvalidOperationException>(() => _pipe.Reader.AdvanceTo(result.Buffer.Start, result.Buffer.End));
+ }
+
+ [Fact]
public void FlushAsyncAwaitableCompletesWhenReaderAdvancesUnderLow()
{
- PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
Assert.False(flushAsync.IsCompleted);
@@ -60,13 +78,13 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void FlushAsyncAwaitableDoesNotCompletesWhenReaderAdvancesUnderHight()
{
- PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
Assert.False(flushAsync.IsCompleted);
ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
- SequencePosition consumed = result.Buffer.GetPosition(32);
+ SequencePosition consumed = result.Buffer.GetPosition(ResumeWriterThreshold);
_pipe.Reader.AdvanceTo(consumed, consumed);
Assert.False(flushAsync.IsCompleted);
@@ -75,7 +93,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void FlushAsyncAwaitableResetsOnCommit()
{
- PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
Assert.False(flushAsync.IsCompleted);
@@ -88,7 +106,7 @@ namespace System.IO.Pipelines.Tests
FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
Assert.False(flushResult.IsCompleted);
- writableBuffer = _pipe.Writer.WriteEmpty(64);
+ writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
flushAsync = writableBuffer.FlushAsync();
Assert.False(flushAsync.IsCompleted);
@@ -97,7 +115,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void FlushAsyncReturnsCompletedIfReaderCompletes()
{
- PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
Assert.False(flushAsync.IsCompleted);
@@ -108,7 +126,7 @@ namespace System.IO.Pipelines.Tests
FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
Assert.True(flushResult.IsCompleted);
- writableBuffer = _pipe.Writer.WriteEmpty(64);
+ writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
flushAsync = writableBuffer.FlushAsync();
flushResult = flushAsync.GetAwaiter().GetResult();
@@ -119,7 +137,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task FlushAsyncReturnsCompletedIfReaderCompletesWithoutAdvance()
{
- PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
Assert.False(flushAsync.IsCompleted);
@@ -131,7 +149,7 @@ namespace System.IO.Pipelines.Tests
FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
Assert.True(flushResult.IsCompleted);
- writableBuffer = _pipe.Writer.WriteEmpty(64);
+ writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
flushAsync = writableBuffer.FlushAsync();
flushResult = flushAsync.GetAwaiter().GetResult();
@@ -142,7 +160,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void FlushAsyncReturnsCompletedTaskWhenSizeLessThenLimit()
{
- PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(32);
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(ResumeWriterThreshold);
ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
Assert.True(flushAsync.IsCompleted);
FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
@@ -152,7 +170,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public void FlushAsyncReturnsNonCompletedSizeWhenCommitOverTheLimit()
{
- PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
Assert.False(flushAsync.IsCompleted);
}
@@ -162,7 +180,7 @@ namespace System.IO.Pipelines.Tests
{
_pipe.Reader.Complete(new InvalidOperationException("Reader failed"));
- PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(PauseWriterThreshold);
InvalidOperationException invalidOperationException =
await Assert.ThrowsAsync<InvalidOperationException>(async () => await writableBuffer.FlushAsync());
Assert.Equal("Reader failed", invalidOperationException.Message);
diff --git a/src/System.IO.Pipelines/tests/PipePoolTests.cs b/src/System.IO.Pipelines/tests/PipePoolTests.cs
index 8e8779accc..f4faa4bd86 100644
--- a/src/System.IO.Pipelines/tests/PipePoolTests.cs
+++ b/src/System.IO.Pipelines/tests/PipePoolTests.cs
@@ -12,28 +12,25 @@ namespace System.IO.Pipelines.Tests
{
private class DisposeTrackingBufferPool : TestMemoryPool
{
- public int ReturnedBlocks { get; set; }
public int DisposedBlocks { get; set; }
public int CurrentlyRentedBlocks { get; set; }
- public override OwnedMemory<byte> Rent(int size)
+ public override IMemoryOwner<byte> Rent(int size)
{
- return new DisposeTrackingOwnedMemory(new byte[size], this);
+ return new DisposeTrackingMemoryManager(new byte[size], this);
}
protected override void Dispose(bool disposing)
{
}
- private class DisposeTrackingOwnedMemory : OwnedMemory<byte>
+ private class DisposeTrackingMemoryManager : MemoryManager<byte>
{
private byte[] _array;
private readonly DisposeTrackingBufferPool _bufferPool;
- private int _refCount = 1;
-
- public DisposeTrackingOwnedMemory(byte[] array, DisposeTrackingBufferPool bufferPool)
+ public DisposeTrackingMemoryManager(byte[] array, DisposeTrackingBufferPool bufferPool)
{
_array = array;
_bufferPool = bufferPool;
@@ -42,21 +39,14 @@ namespace System.IO.Pipelines.Tests
public override int Length => _array.Length;
- public override Span<byte> Span
+ public bool IsDisposed => _array == null;
+
+ public override MemoryHandle Pin(int elementIndex = 0)
{
- get
- {
- if (IsDisposed)
- throw new ObjectDisposedException(nameof(DisposeTrackingBufferPool));
- return _array;
- }
+ throw new NotImplementedException();
}
- public override bool IsDisposed => _array == null;
-
- protected override bool IsRetained => _refCount > 0;
-
- public override MemoryHandle Pin(int byteOffset = 0)
+ public override void Unpin()
{
throw new NotImplementedException();
}
@@ -71,26 +61,17 @@ namespace System.IO.Pipelines.Tests
protected override void Dispose(bool disposing)
{
- if (IsRetained)
- {
- throw new InvalidOperationException();
- }
_bufferPool.DisposedBlocks++;
+ _bufferPool.CurrentlyRentedBlocks--;
_array = null;
}
- public override bool Release()
+ public override Span<byte> GetSpan()
{
- _bufferPool.ReturnedBlocks++;
- _bufferPool.CurrentlyRentedBlocks--;
- _refCount--;
- return IsRetained;
- }
-
- public override void Retain()
- {
- _refCount++;
+ if (IsDisposed)
+ throw new ObjectDisposedException(nameof(DisposeTrackingBufferPool));
+ return _array;
}
}
}
@@ -113,8 +94,7 @@ namespace System.IO.Pipelines.Tests
pipe.Reader.AdvanceTo(readResult.Buffer.End);
Assert.Equal(0, pool.CurrentlyRentedBlocks);
- Assert.Equal(0, pool.DisposedBlocks);
- Assert.Equal(3, pool.ReturnedBlocks);
+ Assert.Equal(3, pool.DisposedBlocks);
}
[Fact]
@@ -143,8 +123,7 @@ namespace System.IO.Pipelines.Tests
await pipe.Writer.WriteAsync(new byte[writeSize]);
Assert.Equal(1, pool.CurrentlyRentedBlocks);
- Assert.Equal(0, pool.DisposedBlocks);
- Assert.Equal(2, pool.ReturnedBlocks);
+ Assert.Equal(2, pool.DisposedBlocks);
}
[Fact]
@@ -157,13 +136,11 @@ namespace System.IO.Pipelines.Tests
readerWriter.Writer.Complete();
readerWriter.Reader.Complete();
- Assert.Equal(1, pool.ReturnedBlocks);
- Assert.Equal(0, pool.DisposedBlocks);
+ Assert.Equal(1, pool.DisposedBlocks);
readerWriter.Writer.Complete();
readerWriter.Reader.Complete();
- Assert.Equal(1, pool.ReturnedBlocks);
- Assert.Equal(0, pool.DisposedBlocks);
+ Assert.Equal(1, pool.DisposedBlocks);
}
[Fact]
@@ -198,8 +175,7 @@ namespace System.IO.Pipelines.Tests
pipe.Reader.Complete();
pipe.Writer.Complete();
Assert.Equal(0, pool.CurrentlyRentedBlocks);
- Assert.Equal(1, pool.ReturnedBlocks);
- Assert.Equal(0, pool.DisposedBlocks);
+ Assert.Equal(1, pool.DisposedBlocks);
}
[Fact]
@@ -213,8 +189,7 @@ namespace System.IO.Pipelines.Tests
pipe.Reader.Complete();
pipe.Writer.Complete();
Assert.Equal(0, pool.CurrentlyRentedBlocks);
- Assert.Equal(2, pool.ReturnedBlocks);
- Assert.Equal(0, pool.DisposedBlocks);
+ Assert.Equal(2, pool.DisposedBlocks);
}
[Fact]
diff --git a/src/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs b/src/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs
index 6010fd5b1f..f25f08b2a2 100644
--- a/src/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs
+++ b/src/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs
@@ -35,7 +35,7 @@ namespace System.IO.Pipelines.Tests
private readonly TestMemoryPool _pool;
[Fact]
- public async Task AdvanceEmptyBufferAfterWritingResetsAwaitable()
+ public async Task CanReadAndWrite()
{
byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
@@ -50,14 +50,6 @@ namespace System.IO.Pipelines.Tests
Assert.Equal("Hello World", Encoding.ASCII.GetString(array));
_pipe.Reader.AdvanceTo(buffer.End);
-
- // Now write 0 and advance 0
- await _pipe.Writer.WriteAsync(new byte[] { });
- result = await _pipe.Reader.ReadAsync();
- _pipe.Reader.AdvanceTo(result.Buffer.End);
-
- ValueTask<ReadResult> awaitable = _pipe.Reader.ReadAsync();
- Assert.False(awaitable.IsCompleted);
}
[Fact]
@@ -75,8 +67,7 @@ namespace System.IO.Pipelines.Tests
ValueTask<ReadResult> awaitable = _pipe.Reader.ReadAsync();
Assert.False(awaitable.IsCompleted);
- // Unblock without writing anything
- _pipe.Writer.GetMemory();
+ _pipe.Writer.Write(new byte[1]);
await _pipe.Writer.FlushAsync();
Assert.True(awaitable.IsCompleted);
@@ -153,7 +144,7 @@ namespace System.IO.Pipelines.Tests
[Fact]
public async Task CompleteReaderAfterFlushWithoutAdvancingDoesNotThrow()
{
- await _pipe.Writer.FlushAsync();
+ await _pipe.Writer.WriteAsync(new byte[10]);
ReadResult result = await _pipe.Reader.ReadAsync();
ReadOnlySequence<byte> buffer = result.Buffer;
@@ -178,20 +169,20 @@ namespace System.IO.Pipelines.Tests
var startSegment = (BufferSegment)start;
var endSegment = (BufferSegment)end;
- Assert.NotNull(startSegment.OwnedMemory);
- Assert.NotNull(endSegment.OwnedMemory);
+ Assert.NotNull(startSegment.MemoryOwner);
+ Assert.NotNull(endSegment.MemoryOwner);
_pipe.Reader.Complete();
// Nothing cleaned up
- Assert.NotNull(startSegment.OwnedMemory);
- Assert.NotNull(endSegment.OwnedMemory);
+ Assert.NotNull(startSegment.MemoryOwner);
+ Assert.NotNull(endSegment.MemoryOwner);
_pipe.Writer.Complete();
// Should be cleaned up now
- Assert.Null(startSegment.OwnedMemory);
- Assert.Null(endSegment.OwnedMemory);
+ Assert.Null(startSegment.MemoryOwner);
+ Assert.Null(endSegment.MemoryOwner);
_pipe.Reset();
}
@@ -210,33 +201,6 @@ namespace System.IO.Pipelines.Tests
}
[Fact]
- public async Task EmptyBufferStartCrossingSegmentBoundaryIsTreatedLikeAndEnd()
- {
- Memory<byte> memory = _pipe.Writer.GetMemory();
- // Append one full segment to a pipe
- _pipe.Writer.Write(memory.Span);
- await _pipe.Writer.FlushAsync();
-
- // Consume entire segment
- ReadResult result = await _pipe.Reader.ReadAsync();
- _pipe.Reader.AdvanceTo(result.Buffer.End);
-
- // Append empty segment
- _pipe.Writer.GetMemory(1);
- await _pipe.Writer.FlushAsync();
-
- result = await _pipe.Reader.ReadAsync();
-
- Assert.True(result.Buffer.IsEmpty);
- Assert.Equal(result.Buffer.Start, result.Buffer.End);
-
- _pipe.Writer.GetMemory();
- _pipe.Reader.AdvanceTo(result.Buffer.Start);
- ValueTask<ReadResult> awaitable = _pipe.Reader.ReadAsync();
- Assert.False(awaitable.IsCompleted);
- }
-
- [Fact]
public void FlushAsync_ReturnsCompletedTaskWhenMaxSizeIfZero()
{
PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(1);
@@ -808,6 +772,30 @@ namespace System.IO.Pipelines.Tests
Assert.True(IsTaskWithResult(task));
}
+ [Fact]
+ public void EmptyFlushAsyncDoesntWakeUpReader()
+ {
+ ValueTask<ReadResult> task = _pipe.Reader.ReadAsync();
+ _pipe.Writer.FlushAsync();
+
+ Assert.False(task.IsCompleted);
+ }
+
+ [Fact]
+ public async Task EmptyFlushAsyncDoesntWakeUpReaderAfterAdvance()
+ {
+ await _pipe.Writer.WriteAsync(new byte[10]);
+
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ _pipe.Reader.AdvanceTo(result.Buffer.Start, result.Buffer.End);
+
+ ValueTask<ReadResult> task = _pipe.Reader.ReadAsync();
+
+ await _pipe.Writer.FlushAsync();
+
+ Assert.False(task.IsCompleted);
+ }
+
private bool IsTaskWithResult<T>(ValueTask<T> task)
{
return task == new ValueTask<T>(task.Result);
diff --git a/src/System.IO.Pipelines/tests/PipeWriterTests.cs b/src/System.IO.Pipelines/tests/PipeWriterTests.cs
index 4ac05668b7..d60841d673 100644
--- a/src/System.IO.Pipelines/tests/PipeWriterTests.cs
+++ b/src/System.IO.Pipelines/tests/PipeWriterTests.cs
@@ -77,18 +77,6 @@ namespace System.IO.Pipelines.Tests
}
[Fact]
- public void CanWriteEmpty()
- {
- PipeWriter writer = Pipe.Writer;
- var array = new byte[] { };
-
- writer.Write(array);
- writer.Write(new Span<byte>(array, 0, array.Length));
-
- Assert.Equal(array, Read());
- }
-
- [Fact]
public void CanWriteIntoHeadlessBuffer()
{
PipeWriter writer = Pipe.Writer;
@@ -130,6 +118,8 @@ namespace System.IO.Pipelines.Tests
var span = writer.GetSpan(10);
Assert.True(span.Length >= 10);
+ // 0 byte Flush would not complete the reader so we complete.
+ Pipe.Writer.Complete();
Assert.Equal(new byte[] { }, Read());
}
diff --git a/src/System.IO.Pipelines/tests/TestMemoryPool.cs b/src/System.IO.Pipelines/tests/TestMemoryPool.cs
index 0736c37876..3b01df3ca3 100644
--- a/src/System.IO.Pipelines/tests/TestMemoryPool.cs
+++ b/src/System.IO.Pipelines/tests/TestMemoryPool.cs
@@ -15,10 +15,10 @@ namespace System.IO.Pipelines
private bool _disposed;
- public override OwnedMemory<byte> Rent(int minBufferSize = -1)
+ public override IMemoryOwner<byte> Rent(int minBufferSize = -1)
{
CheckDisposed();
- return new PooledMemory(_pool.Rent(minBufferSize), this);
+ return new PooledMemory((MemoryManager<byte>)_pool.Rent(minBufferSize), this);
}
protected override void Dispose(bool disposing)
@@ -36,9 +36,9 @@ namespace System.IO.Pipelines
}
}
- private class PooledMemory : OwnedMemory<byte>
+ private class PooledMemory : MemoryManager<byte>
{
- private OwnedMemory<byte> _ownedMemory;
+ private MemoryManager<byte> _manager;
private readonly TestMemoryPool _pool;
@@ -48,9 +48,9 @@ namespace System.IO.Pipelines
private string _leaser;
- public PooledMemory(OwnedMemory<byte> ownedMemory, TestMemoryPool pool)
+ public PooledMemory(MemoryManager<byte> manager, TestMemoryPool pool)
{
- _ownedMemory = ownedMemory;
+ _manager = manager;
_pool = pool;
_leaser = Environment.StackTrace;
_referenceCount = 1;
@@ -64,26 +64,19 @@ namespace System.IO.Pipelines
protected override void Dispose(bool disposing)
{
_pool.CheckDisposed();
- _ownedMemory.Dispose();
}
- public override MemoryHandle Pin(int byteOffset = 0)
+ public override MemoryHandle Pin(int elementIndex = 0)
{
_pool.CheckDisposed();
- return _ownedMemory.Pin(byteOffset);
- }
-
- public override void Retain()
- {
- _pool.CheckDisposed();
- _ownedMemory.Retain();
Interlocked.Increment(ref _referenceCount);
+ return _manager.Pin(elementIndex);
}
- public override bool Release()
+ public override void Unpin()
{
_pool.CheckDisposed();
- _ownedMemory.Release();
+ _manager.Unpin();
int newRefCount = Interlocked.Decrement(ref _referenceCount);
@@ -93,33 +86,13 @@ namespace System.IO.Pipelines
if (newRefCount == 0)
{
_returned = true;
- return false;
}
- return true;
}
protected override bool TryGetArray(out ArraySegment<byte> segment)
{
_pool.CheckDisposed();
- return MemoryMarshal.TryGetArray(_ownedMemory.Memory, out segment);
- }
-
- public override bool IsDisposed
- {
- get
- {
- _pool.CheckDisposed();
- return _ownedMemory.IsDisposed;
- }
- }
-
- protected override bool IsRetained
- {
- get
- {
- _pool.CheckDisposed();
- return !_returned;
- }
+ return MemoryMarshal.TryGetArray(_manager.Memory, out segment);
}
public override int Length
@@ -127,17 +100,14 @@ namespace System.IO.Pipelines
get
{
_pool.CheckDisposed();
- return _ownedMemory.Length;
+ return _manager.Length;
}
}
- public override Span<byte> Span
+ public override Span<byte> GetSpan()
{
- get
- {
- _pool.CheckDisposed();
- return _ownedMemory.Span;
- }
+ _pool.CheckDisposed();
+ return _manager.GetSpan();
}
}
}
diff --git a/src/System.IO/tests/Stream/Stream.ReadWriteSpan.netcoreapp.cs b/src/System.IO/tests/Stream/Stream.ReadWriteSpan.netcoreapp.cs
index 6bdea544b0..c25418c06f 100644
--- a/src/System.IO/tests/Stream/Stream.ReadWriteSpan.netcoreapp.cs
+++ b/src/System.IO/tests/Stream/Stream.ReadWriteSpan.netcoreapp.cs
@@ -115,7 +115,7 @@ namespace System.IO.Tests
return Task.FromResult(10);
});
- using (var totalNativeMemory = new NativeOwnedMemory(30))
+ using (var totalNativeMemory = new NativeMemoryManager(30))
{
Memory<byte> totalMemory = totalNativeMemory.Memory;
Memory<byte> targetMemory = totalMemory.Slice(5, 20);
@@ -174,7 +174,7 @@ namespace System.IO.Tests
return Task.CompletedTask;
});
- using (var nativeMemory = new NativeOwnedMemory(10))
+ using (var nativeMemory = new NativeMemoryManager(10))
{
Memory<byte> memory = nativeMemory.Memory;
memory.Span[2] = 0;
diff --git a/src/System.IO/tests/System.IO.Tests.csproj b/src/System.IO/tests/System.IO.Tests.csproj
index 52cf08256d..a1a7f7cc49 100644
--- a/src/System.IO/tests/System.IO.Tests.csproj
+++ b/src/System.IO/tests/System.IO.Tests.csproj
@@ -57,8 +57,8 @@
<Compile Include="StringReader\StringReader.CtorTests.cs" />
<Compile Include="StringWriter\StringWriterTests.netcoreapp.cs" Condition="'$(TargetGroup)' == 'netcoreapp'" />
<Compile Include="StringWriter\StringWriterTests.cs" />
- <Compile Include="$(CommonTestPath)\System\Buffers\NativeOwnedMemory.cs" Condition="'$(TargetGroup)' == 'netcoreapp'">
- <Link>Common\System\Buffers\NativeOwnedMemory.cs</Link>
+ <Compile Include="$(CommonTestPath)\System\Buffers\NativeMemoryManager.cs" Condition="'$(TargetGroup)' == 'netcoreapp'">
+ <Link>Common\System\Buffers\NativeMemoryManager.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\IO\CallTrackingStream.cs">
<Link>Common\System\IO\CallTrackingStream.cs</Link>
diff --git a/src/System.Memory/ref/System.Memory.cs b/src/System.Memory/ref/System.Memory.cs
index 9775637231..9f750abd53 100644
--- a/src/System.Memory/ref/System.Memory.cs
+++ b/src/System.Memory/ref/System.Memory.cs
@@ -9,15 +9,15 @@ namespace System
{
public static partial class MemoryExtensions
{
+ public static System.ReadOnlyMemory<char> AsMemory(this string text) { throw null; }
+ public static System.ReadOnlyMemory<char> AsMemory(this string text, int start) { throw null; }
+ public static System.ReadOnlyMemory<char> AsMemory(this string text, int start, int length) { throw null; }
public static System.Memory<T> AsMemory<T>(this System.ArraySegment<T> segment) { throw null; }
public static System.Memory<T> AsMemory<T>(this System.ArraySegment<T> segment, int start) { throw null; }
public static System.Memory<T> AsMemory<T>(this System.ArraySegment<T> segment, int start, int length) { throw null; }
public static System.Memory<T> AsMemory<T>(this T[] array) { throw null; }
public static System.Memory<T> AsMemory<T>(this T[] array, int start) { throw null; }
public static System.Memory<T> AsMemory<T>(this T[] array, int start, int length) { throw null; }
- public static System.ReadOnlyMemory<char> AsMemory(this string text) { throw null; }
- public static System.ReadOnlyMemory<char> AsMemory(this string text, int start) { throw null; }
- public static System.ReadOnlyMemory<char> AsMemory(this string text, int start, int length) { throw null; }
public static System.ReadOnlySpan<char> AsSpan(this string text) { throw null; }
public static System.ReadOnlySpan<char> AsSpan(this string text, int start) { throw null; }
public static System.ReadOnlySpan<char> AsSpan(this string text, int start, int length) { throw null; }
@@ -92,6 +92,7 @@ namespace System
public readonly partial struct Memory<T>
{
private readonly object _dummy;
+ public Memory(System.Buffers.MemoryManager<T> manager, int start, int length) { throw null; }
public Memory(T[] array) { throw null; }
public Memory(T[] array, int start, int length) { throw null; }
public static System.Memory<T> Empty { get { throw null; } }
@@ -99,6 +100,8 @@ namespace System
public int Length { get { throw null; } }
public System.Span<T> Span { get { throw null; } }
public void CopyTo(System.Memory<T> destination) { }
+ [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
+ public static System.Memory<T> CreateFromPinnedArray(T[] array, int start, int length) { throw null; }
public bool Equals(System.Memory<T> other) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public override bool Equals(object obj) { throw null; }
@@ -108,7 +111,6 @@ namespace System
public static implicit operator System.ReadOnlyMemory<T> (System.Memory<T> memory) { throw null; }
public static implicit operator System.Memory<T> (T[] array) { throw null; }
public System.Buffers.MemoryHandle Pin() { throw null; }
- public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.Memory<T> Slice(int start) { throw null; }
public System.Memory<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
@@ -133,7 +135,6 @@ namespace System
public static implicit operator System.ReadOnlyMemory<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (T[] array) { throw null; }
public System.Buffers.MemoryHandle Pin() { throw null; }
- public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
@@ -178,18 +179,18 @@ namespace System
public readonly partial struct SequencePosition : System.IEquatable<System.SequencePosition>
{
private readonly object _dummy;
- public SequencePosition(object segment, int index) { throw null; }
- [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
- public int GetInteger() { throw null; }
- [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
- public object GetObject() { throw null; }
+ public SequencePosition(object @object, int integer) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public override bool Equals(object obj) { throw null; }
public bool Equals(System.SequencePosition other) { throw null; }
+ [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public override int GetHashCode() { throw null; }
+ [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
+ public int GetInteger() { throw null; }
+ [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
+ public object GetObject() { throw null; }
public static bool operator ==(System.SequencePosition left, System.SequencePosition right) { throw null; }
public static bool operator !=(System.SequencePosition left, System.SequencePosition right) { throw null; }
- public override string ToString() { throw null; }
}
public readonly ref partial struct Span<T>
{
@@ -232,33 +233,49 @@ namespace System
}
namespace System.Buffers
{
+ public static partial class BuffersExtensions
+ {
+ public static void CopyTo<T>(this in System.Buffers.ReadOnlySequence<T> source, System.Span<T> destination) { }
+ public static System.Nullable<System.SequencePosition> PositionOf<T>(this in System.Buffers.ReadOnlySequence<T> source, T value) where T : System.IEquatable<T> { throw null; }
+ public static T[] ToArray<T>(this in System.Buffers.ReadOnlySequence<T> sequence) { throw null; }
+ public static void Write<T>(this System.Buffers.IBufferWriter<T> writer, System.ReadOnlySpan<T> value) { }
+ }
public partial interface IBufferWriter<T>
{
void Advance(int count);
System.Memory<T> GetMemory(int sizeHint = 0);
System.Span<T> GetSpan(int sizeHint = 0);
}
- public abstract partial class ReadOnlySequenceSegment<T>
+ public partial interface IMemoryOwner<T> : System.IDisposable
{
- public System.ReadOnlyMemory<T> Memory { get; protected set; }
- public System.Buffers.ReadOnlySequenceSegment<T> Next { get; protected set; }
- public long RunningIndex { get; protected set; }
+ System.Memory<T> Memory { get; }
}
- public partial interface IRetainable
+ public partial interface IPinnable
{
- bool Release();
- void Retain();
+ System.Buffers.MemoryHandle Pin(int elementIndex);
+ void Unpin();
}
public partial struct MemoryHandle : System.IDisposable
{
private object _dummy;
[System.CLSCompliantAttribute(false)]
- public unsafe MemoryHandle(System.Buffers.IRetainable retainable, void* pointer = null, System.Runtime.InteropServices.GCHandle handle = default(System.Runtime.InteropServices.GCHandle)) { throw null; }
- public bool HasPointer { get { throw null; } }
+ public unsafe MemoryHandle(void* pointer, System.Runtime.InteropServices.GCHandle handle = default(System.Runtime.InteropServices.GCHandle), System.Buffers.IPinnable pinnable = null) { throw null; }
[System.CLSCompliantAttribute(false)]
public unsafe void* Pointer { get { throw null; } }
public void Dispose() { }
}
+ public abstract partial class MemoryManager<T> : System.Buffers.IMemoryOwner<T>, System.Buffers.IPinnable, System.IDisposable
+ {
+ protected MemoryManager() { }
+ public virtual int Length { get { throw null; } }
+ public virtual System.Memory<T> Memory { get { throw null; } }
+ protected abstract void Dispose(bool disposing);
+ public abstract System.Span<T> GetSpan();
+ public abstract System.Buffers.MemoryHandle Pin(int elementIndex = 0);
+ void System.IDisposable.Dispose() { }
+ protected internal virtual bool TryGetArray(out System.ArraySegment<T> segment) { throw null; }
+ public abstract void Unpin();
+ }
public abstract partial class MemoryPool<T> : System.IDisposable
{
protected MemoryPool() { }
@@ -266,7 +283,7 @@ namespace System.Buffers
public static System.Buffers.MemoryPool<T> Shared { get { throw null; } }
public void Dispose() { }
protected abstract void Dispose(bool disposing);
- public abstract System.Buffers.OwnedMemory<T> Rent(int minBufferSize = -1);
+ public abstract System.Buffers.IMemoryOwner<T> Rent(int minBufferSize = -1);
}
public enum OperationStatus
{
@@ -275,38 +292,21 @@ namespace System.Buffers
InvalidData = 3,
NeedMoreData = 2,
}
- public abstract partial class OwnedMemory<T> : System.Buffers.IRetainable, System.IDisposable
- {
- protected OwnedMemory() { }
- public abstract bool IsDisposed { get; }
- protected abstract bool IsRetained { get; }
- public abstract int Length { get; }
- public System.Memory<T> Memory { get { throw null; } }
- public abstract System.Span<T> Span { get; }
- public void Dispose() { }
- protected abstract void Dispose(bool disposing);
- public abstract System.Buffers.MemoryHandle Pin(int byteOffset = 0);
- public abstract bool Release();
- public abstract void Retain();
- protected internal abstract bool TryGetArray(out System.ArraySegment<T> segment);
- }
- public static partial class BuffersExtensions
+ public abstract partial class ReadOnlySequenceSegment<T>
{
- public static void CopyTo<T>(in this System.Buffers.ReadOnlySequence<T> source, System.Span<T> destination) { }
- public static System.Nullable<System.SequencePosition> PositionOf<T>(in this System.Buffers.ReadOnlySequence<T> source, T value) where T : System.IEquatable<T> { throw null; }
- public static T[] ToArray<T>(in this System.Buffers.ReadOnlySequence<T> sequence) { throw null; }
- public static void Write<T>(this System.Buffers.IBufferWriter<T> writer, ReadOnlySpan<T> value) { }
+ protected ReadOnlySequenceSegment() { }
+ public System.ReadOnlyMemory<T> Memory { get { throw null; } protected set { } }
+ public System.Buffers.ReadOnlySequenceSegment<T> Next { get { throw null; } protected set { } }
+ public long RunningIndex { get { throw null; } protected set { } }
}
public readonly partial struct ReadOnlySequence<T>
{
private readonly object _dummy;
public static readonly System.Buffers.ReadOnlySequence<T> Empty;
public ReadOnlySequence(System.Buffers.ReadOnlySequenceSegment<T> startSegment, int startIndex, System.Buffers.ReadOnlySequenceSegment<T> endSegment, int endIndex) { throw null; }
+ public ReadOnlySequence(System.ReadOnlyMemory<T> memory) { throw null; }
public ReadOnlySequence(T[] array) { throw null; }
public ReadOnlySequence(T[] array, int start, int length) { throw null; }
- public ReadOnlySequence(System.ReadOnlyMemory<T> memory) { throw null; }
- public ReadOnlySequence(System.Buffers.OwnedMemory<T> memory) { throw null; }
- public ReadOnlySequence(System.Buffers.OwnedMemory<T> memory, int start, int length) { throw null; }
public System.SequencePosition End { get { throw null; } }
public System.ReadOnlyMemory<T> First { get { throw null; } }
public bool IsEmpty { get { throw null; } }
@@ -522,21 +522,18 @@ namespace System.Runtime.InteropServices
public static T Read<T>(System.ReadOnlySpan<byte> source) where T : struct { throw null; }
public static System.Collections.Generic.IEnumerable<T> ToEnumerable<T>(System.ReadOnlyMemory<T> memory) { throw null; }
public static bool TryGetArray<T>(System.ReadOnlyMemory<T> memory, out System.ArraySegment<T> segment) { throw null; }
- public static bool TryGetOwnedMemory<T, TOwner>(ReadOnlyMemory<T> memory, out TOwner owner)
- where TOwner : System.Buffers.OwnedMemory<T> { throw null; }
- public static bool TryGetOwnedMemory<T, TOwner>(ReadOnlyMemory<T> memory, out TOwner owner, out int start, out int length)
- where TOwner : System.Buffers.OwnedMemory<T> { throw null; }
+ public static bool TryGetMemoryManager<T, TManager>(System.ReadOnlyMemory<T> memory, out TManager manager) where TManager : System.Buffers.MemoryManager<T> { throw null; }
+ public static bool TryGetMemoryManager<T, TManager>(System.ReadOnlyMemory<T> memory, out TManager manager, out int start, out int length) where TManager : System.Buffers.MemoryManager<T> { throw null; }
public static bool TryGetString(System.ReadOnlyMemory<char> memory, out string text, out int start, out int length) { throw null; }
public static bool TryRead<T>(System.ReadOnlySpan<byte> source, out T value) where T : struct { throw null; }
public static bool TryWrite<T>(System.Span<byte> destination, ref T value) where T : struct { throw null; }
public static void Write<T>(System.Span<byte> destination, ref T value) where T : struct { }
}
-
public static partial class SequenceMarshal
{
public static bool TryGetArray<T>(System.Buffers.ReadOnlySequence<T> sequence, out System.ArraySegment<T> segment) { throw null; }
- public static bool TryGetReadOnlySequenceSegment<T>(System.Buffers.ReadOnlySequence<T> sequence, out System.Buffers.ReadOnlySequenceSegment<T> startSegment, out int startIndex, out System.Buffers.ReadOnlySequenceSegment<T> endSegment, out int endIndex) { throw null; }
- public static bool TryGetOwnedMemory<T>(System.Buffers.ReadOnlySequence<T> sequence, out System.Buffers.OwnedMemory<T> ownedMemory, out int start, out int length) { throw null; }
+ public static bool TryGetMemoryManager<T>(System.Buffers.ReadOnlySequence<T> sequence, out System.Buffers.MemoryManager<T> manager, out int start, out int length) { throw null; }
public static bool TryGetReadOnlyMemory<T>(System.Buffers.ReadOnlySequence<T> sequence, out System.ReadOnlyMemory<T> memory) { throw null; }
+ public static bool TryGetReadOnlySequenceSegment<T>(System.Buffers.ReadOnlySequence<T> sequence, out System.Buffers.ReadOnlySequenceSegment<T> startSegment, out int startIndex, out System.Buffers.ReadOnlySequenceSegment<T> endSegment, out int endIndex) { throw null; }
}
}
diff --git a/src/System.Memory/src/System.Memory.csproj b/src/System.Memory/src/System.Memory.csproj
index 5e364ecf6b..dda3aac4c1 100644
--- a/src/System.Memory/src/System.Memory.csproj
+++ b/src/System.Memory/src/System.Memory.csproj
@@ -116,9 +116,10 @@
<Compile Include="$(CommonPath)\CoreLib\System\SpanHelpers.Byte.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\SpanHelpers.Char.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\SpanHelpers.T.cs" />
- <Compile Include="$(CommonPath)\CoreLib\System\Buffers\IRetainable.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\Buffers\IPinnable.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\Buffers\IMemoryOwner.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\Buffers\MemoryHandle.cs" />
- <Compile Include="$(CommonPath)\CoreLib\System\Buffers\OwnedMemory.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\Buffers\MemoryManager.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\Runtime\InteropServices\MemoryMarshal.cs" />
<Compile Include="System\ReadOnlySpan.Portable.cs" />
<Compile Include="System\Span.Portable.cs" />
diff --git a/src/System.Memory/src/System/Buffers/ArrayMemoryPool.ArrayMemoryPoolBuffer.cs b/src/System.Memory/src/System/Buffers/ArrayMemoryPool.ArrayMemoryPoolBuffer.cs
index e3db9db89d..6e94654423 100644
--- a/src/System.Memory/src/System/Buffers/ArrayMemoryPool.ArrayMemoryPoolBuffer.cs
+++ b/src/System.Memory/src/System/Buffers/ArrayMemoryPool.ArrayMemoryPoolBuffer.cs
@@ -15,7 +15,7 @@ namespace System.Buffers
{
internal sealed partial class ArrayMemoryPool<T> : MemoryPool<T>
{
- private sealed class ArrayMemoryPoolBuffer : OwnedMemory<T>
+ private sealed class ArrayMemoryPoolBuffer : MemoryManager<T>
{
private T[] _array;
private int _refCount;
@@ -28,19 +28,16 @@ namespace System.Buffers
public sealed override int Length => _array.Length;
- public sealed override bool IsDisposed => _array == null;
+ public bool IsDisposed => _array == null;
- protected sealed override bool IsRetained => Volatile.Read(ref _refCount) > 0;
+ public bool IsRetained => Volatile.Read(ref _refCount) > 0;
- public sealed override Span<T> Span
+ public sealed override Span<T> GetSpan()
{
- get
- {
- if (IsDisposed)
- ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
+ if (IsDisposed)
+ ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
- return _array;
- }
+ return _array;
}
protected sealed override void Dispose(bool disposing)
@@ -67,44 +64,39 @@ namespace System.Buffers
return true;
}
- public sealed override MemoryHandle Pin(int byteOffset = 0)
+ public sealed override MemoryHandle Pin(int elementIndex = 0)
{
unsafe
{
- Retain(); // this checks IsDisposed
+ while (true)
+ {
+ int currentCount = Volatile.Read(ref _refCount);
+ if (currentCount <= 0)
+ ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
+ if (Interlocked.CompareExchange(ref _refCount, currentCount + 1, currentCount) == currentCount)
+ break;
+ }
try
{
- if ((IntPtr.Size == 4 && (uint)byteOffset > (uint)_array.Length * (uint)Unsafe.SizeOf<T>())
- || (IntPtr.Size != 4 && (ulong)byteOffset > (uint)_array.Length * (ulong)Unsafe.SizeOf<T>()))
+ if ((uint)elementIndex > (uint)_array.Length)
{
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.byteOffset);
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.elementIndex);
}
GCHandle handle = GCHandle.Alloc(_array, GCHandleType.Pinned);
- return new MemoryHandle(this, ((byte*)handle.AddrOfPinnedObject()) + byteOffset, handle);
+
+ return new MemoryHandle(Unsafe.Add<T>(((void*)handle.AddrOfPinnedObject()), elementIndex), handle, this);
}
catch
{
- Release();
+ Unpin();
throw;
}
}
}
- public sealed override void Retain()
- {
- while (true)
- {
- int currentCount = Volatile.Read(ref _refCount);
- if (currentCount <= 0)
- ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
- if (Interlocked.CompareExchange(ref _refCount, currentCount + 1, currentCount) == currentCount)
- break;
- }
- }
-
- public sealed override bool Release()
+ public sealed override void Unpin()
{
while (true)
{
@@ -115,10 +107,9 @@ namespace System.Buffers
{
if (currentCount == 1)
{
- Dispose();
- return false;
+ Dispose(true);
}
- return true;
+ break;
}
}
}
diff --git a/src/System.Memory/src/System/Buffers/ArrayMemoryPool.cs b/src/System.Memory/src/System/Buffers/ArrayMemoryPool.cs
index 1882c5e723..5d8e0911d9 100644
--- a/src/System.Memory/src/System/Buffers/ArrayMemoryPool.cs
+++ b/src/System.Memory/src/System/Buffers/ArrayMemoryPool.cs
@@ -15,7 +15,7 @@ namespace System.Buffers
private const int s_maxBufferSize = int.MaxValue;
public sealed override int MaxBufferSize => s_maxBufferSize;
- public sealed override OwnedMemory<T> Rent(int minimumBufferSize = -1)
+ public sealed override IMemoryOwner<T> Rent(int minimumBufferSize = -1)
{
if (minimumBufferSize == -1)
minimumBufferSize = 1 + (4095 / Unsafe.SizeOf<T>());
diff --git a/src/System.Memory/src/System/Buffers/MemoryPool.cs b/src/System.Memory/src/System/Buffers/MemoryPool.cs
index febe988ccc..72dc890ecd 100644
--- a/src/System.Memory/src/System/Buffers/MemoryPool.cs
+++ b/src/System.Memory/src/System/Buffers/MemoryPool.cs
@@ -20,7 +20,7 @@ namespace System.Buffers
/// Returns a memory block capable of holding at least <paramref name="minBufferSize" /> elements of T.
/// </summary>
/// <param name="minBufferSize">If -1 is passed, this is set to a default value for the pool.</param>
- public abstract OwnedMemory<T> Rent(int minBufferSize = -1);
+ public abstract IMemoryOwner<T> Rent(int minBufferSize = -1);
/// <summary>
/// Returns the maximum buffer size supported by this pool.
diff --git a/src/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/System.Memory/src/System/Buffers/ReadOnlySequence.cs
index 64ccf639d9..bdd590ddd0 100644
--- a/src/System.Memory/src/System/Buffers/ReadOnlySequence.cs
+++ b/src/System.Memory/src/System/Buffers/ReadOnlySequence.cs
@@ -119,10 +119,10 @@ namespace System.Buffers
/// </summary>
public ReadOnlySequence(ReadOnlyMemory<T> memory)
{
- if (MemoryMarshal.TryGetOwnedMemory(memory, out OwnedMemory<T> ownedMemory, out int index, out int length))
+ if (MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<T> manager, out int index, out int length))
{
- _sequenceStart = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceStart(index));
- _sequenceEnd = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceEnd(length));
+ _sequenceStart = new SequencePosition(manager, ReadOnlySequence.MemoryManagerToSequenceStart(index));
+ _sequenceEnd = new SequencePosition(manager, ReadOnlySequence.MemoryManagerToSequenceEnd(length));
}
else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
{
@@ -149,34 +149,6 @@ namespace System.Buffers
}
/// <summary>
- /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="OwnedMemory{T}"/>.
- /// Consumer is expected to manage lifetime of memory until <see cref="ReadOnlySequence{T}"/> is not used anymore.
- /// </summary>
- public ReadOnlySequence(OwnedMemory<T> ownedMemory)
- {
- if (ownedMemory == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.ownedMemory);
-
- _sequenceStart = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceStart(0));
- _sequenceEnd = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceEnd(ownedMemory.Length));
- }
-
- /// <summary>
- /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="OwnedMemory{T}"/>, start and length.
- /// Consumer is expected to manage lifetime of memory until <see cref="ReadOnlySequence{T}"/> is not used anymore.
- /// </summary>
- public ReadOnlySequence(OwnedMemory<T> ownedMemory, int start, int length)
- {
- if (ownedMemory == null ||
- (uint)start > (uint)ownedMemory.Length ||
- (uint)length > (uint)(ownedMemory.Length - start))
- ThrowHelper.ThrowArgumentValidationException(ownedMemory, start);
-
- _sequenceStart = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceStart(start));
- _sequenceEnd = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceEnd(start + length));
- }
-
- /// <summary>
/// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items
/// </summary>
/// <param name="start">The index at which to begin this slice.</param>
@@ -411,7 +383,7 @@ namespace System.Buffers
{
MultiSegment = 0x00,
Array = 0x1,
- OwnedMemory = 0x2,
+ MemoryManager = 0x2,
String = 0x3,
Empty = 0x4
}
@@ -428,8 +400,8 @@ namespace System.Buffers
public const int ArrayStartMask = 0;
public const int ArrayEndMask = FlagBitMask;
- public const int OwnedMemoryStartMask = FlagBitMask;
- public const int OwnedMemoryEndMask = 0;
+ public const int MemoryManagerStartMask = FlagBitMask;
+ public const int MemoryManagerEndMask = 0;
public const int StringStartMask = FlagBitMask;
public const int StringEndMask = FlagBitMask;
@@ -443,9 +415,9 @@ namespace System.Buffers
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ArrayToSequenceEnd(int endIndex) => endIndex | ArrayEndMask;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int OwnedMemoryToSequenceStart(int startIndex) => startIndex | OwnedMemoryStartMask;
+ public static int MemoryManagerToSequenceStart(int startIndex) => startIndex | MemoryManagerStartMask;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int OwnedMemoryToSequenceEnd(int endIndex) => endIndex | OwnedMemoryEndMask;
+ public static int MemoryManagerToSequenceEnd(int endIndex) => endIndex | MemoryManagerEndMask;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int StringToSequenceStart(int startIndex) => startIndex | StringStartMask;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/src/System.Memory/src/System/Buffers/ReadOnlySequence_helpers.cs b/src/System.Memory/src/System/Buffers/ReadOnlySequence_helpers.cs
index 44c60e8e10..f3f40bf838 100644
--- a/src/System.Memory/src/System/Buffers/ReadOnlySequence_helpers.cs
+++ b/src/System.Memory/src/System/Buffers/ReadOnlySequence_helpers.cs
@@ -60,11 +60,11 @@ namespace System.Buffers
data = new ReadOnlyMemory<T>(Unsafe.As<T[]>(startObject));
}
- else if (type == SequenceType.OwnedMemory)
+ else if (type == SequenceType.MemoryManager)
{
- Debug.Assert(startObject is OwnedMemory<T>);
+ Debug.Assert(startObject is MemoryManager<T>);
- data = (Unsafe.As<OwnedMemory<T>>(startObject)).Memory;
+ data = (Unsafe.As<MemoryManager<T>>(startObject)).Memory;
}
else if (typeof(T) == typeof(char) && type == SequenceType.String)
{
@@ -121,11 +121,11 @@ namespace System.Buffers
memory = new ReadOnlyMemory<T>(Unsafe.As<T[]>(startObject));
}
- else if (type == SequenceType.OwnedMemory)
+ else if (type == SequenceType.MemoryManager)
{
- Debug.Assert(startObject is OwnedMemory<T>);
+ Debug.Assert(startObject is MemoryManager<T>);
- memory = (Unsafe.As<OwnedMemory<T>>(startObject)).Memory;
+ memory = (Unsafe.As<MemoryManager<T>>(startObject)).Memory;
}
else if (typeof(T) == typeof(char) && type == SequenceType.String)
{
@@ -158,7 +158,7 @@ namespace System.Buffers
var startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
int currentLength = startSegment.Memory.Length - startIndex;
-
+
// Position in start segment, defer to single segment seek
if (currentLength > count)
goto IsSingleSegment;
@@ -199,7 +199,7 @@ namespace System.Buffers
// Hit the end of the segments but didn't reach the count
if (currentSegment == null || (currentSegment == endObject && endPosition < count))
ThrowHelper.ThrowArgumentOutOfRangeException_CountOutOfRange();
-
+
FoundSegment:
return new SequencePosition(currentSegment, (int)count);
}
@@ -322,21 +322,21 @@ namespace System.Buffers
return true;
}
- internal bool TryGetOwnedMemory(out OwnedMemory<T> ownedMemory, out int start, out int length)
+ internal bool TryGetMemoryManager(out MemoryManager<T> manager, out int start, out int length)
{
GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out start, out int endIndex);
- if (type != SequenceType.OwnedMemory)
+ if (type != SequenceType.MemoryManager)
{
- ownedMemory = default;
+ manager = default;
length = 0;
return false;
}
Debug.Assert(Start.GetObject() != null);
- Debug.Assert(Start.GetObject() is OwnedMemory<T>);
+ Debug.Assert(Start.GetObject() is MemoryManager<T>);
- ownedMemory = Unsafe.As<OwnedMemory<T>>(Start.GetObject());
+ manager = Unsafe.As<MemoryManager<T>>(Start.GetObject());
length = endIndex - start;
return true;
}
@@ -364,11 +364,11 @@ namespace System.Buffers
memory = new ReadOnlyMemory<T>(Unsafe.As<T[]>(startObject));
}
- else if (type == SequenceType.OwnedMemory)
+ else if (type == SequenceType.MemoryManager)
{
- Debug.Assert(startObject is OwnedMemory<T>);
+ Debug.Assert(startObject is MemoryManager<T>);
- memory = Unsafe.As<OwnedMemory<T>>(startObject).Memory;
+ memory = Unsafe.As<MemoryManager<T>>(startObject).Memory;
}
else if (typeof(T) == typeof(char) && type == SequenceType.String)
{
diff --git a/src/System.Memory/src/System/Runtime/InteropServices/SequenceMarshal.cs b/src/System.Memory/src/System/Runtime/InteropServices/SequenceMarshal.cs
index e3710b1493..420748468d 100644
--- a/src/System.Memory/src/System/Runtime/InteropServices/SequenceMarshal.cs
+++ b/src/System.Memory/src/System/Runtime/InteropServices/SequenceMarshal.cs
@@ -34,12 +34,12 @@ namespace System.Runtime.InteropServices
}
/// <summary>
- /// Get <see cref="OwnedMemory{T}"/> from the underlying <see cref="ReadOnlySequence{T}"/>.
- /// If unable to get the <see cref="OwnedMemory{T}"/>, return false.
+ /// Get <see cref="MemoryManager{T}"/> from the underlying <see cref="ReadOnlySequence{T}"/>.
+ /// If unable to get the <see cref="MemoryManager{T}"/>, return false.
/// </summary>
- public static bool TryGetOwnedMemory<T>(ReadOnlySequence<T> sequence, out OwnedMemory<T> ownedMemory, out int start, out int length)
+ public static bool TryGetMemoryManager<T>(ReadOnlySequence<T> sequence, out MemoryManager<T> manager, out int start, out int length)
{
- return sequence.TryGetOwnedMemory(out ownedMemory, out start, out length);
+ return sequence.TryGetMemoryManager(out manager, out start, out length);
}
/// <summary>
diff --git a/src/System.Memory/src/System/ThrowHelper.cs b/src/System.Memory/src/System/ThrowHelper.cs
index 75a486ace0..5c39e4f93f 100644
--- a/src/System.Memory/src/System/ThrowHelper.cs
+++ b/src/System.Memory/src/System/ThrowHelper.cs
@@ -88,10 +88,6 @@ namespace System
[MethodImpl(MethodImplOptions.NoInlining)]
private static Exception CreateObjectDisposedException_ArrayMemoryPoolBuffer() { return new ObjectDisposedException("ArrayMemoryPoolBuffer"); }
- internal static void ThrowObjectDisposedException_MemoryDisposed() { throw CreateObjectDisposedException_MemoryDisposed(); }
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static Exception CreateObjectDisposedException_MemoryDisposed() { return new ObjectDisposedException("OwnedMemory<T>", SR.MemoryDisposed); }
-
internal static void ThrowFormatException_BadFormatSpecifier() { throw CreateFormatException_BadFormatSpecifier(); }
[MethodImpl(MethodImplOptions.NoInlining)]
private static Exception CreateFormatException_BadFormatSpecifier() { return new FormatException(SR.Argument_BadFormatSpecifier); }
@@ -155,19 +151,6 @@ namespace System
else
return CreateArgumentOutOfRangeException(ExceptionArgument.length);
}
-
- public static void ThrowArgumentValidationException<T>(OwnedMemory<T> ownedMemory, int start)
- => throw CreateArgumentValidationException(ownedMemory, start);
-
- private static Exception CreateArgumentValidationException<T>(OwnedMemory<T> ownedMemory, int start)
- {
- if (ownedMemory == null)
- return CreateArgumentNullException(ExceptionArgument.ownedMemory);
- else if ((uint)start > (uint)ownedMemory.Length)
- return CreateArgumentOutOfRangeException(ExceptionArgument.start);
- else
- return CreateArgumentOutOfRangeException(ExceptionArgument.length);
- }
}
#if !MONO
internal enum ExceptionArgument
@@ -175,7 +158,7 @@ namespace System
length,
start,
minimumBufferSize,
- byteOffset,
+ elementIndex,
comparable,
comparer,
destination,
@@ -185,7 +168,6 @@ namespace System
startIndex,
endIndex,
array,
- ownedMemory,
culture
}
#endif
diff --git a/src/System.Memory/tests/Memory/CtorArray.cs b/src/System.Memory/tests/Memory/CtorArray.cs
index f7122f3d73..fe60e41ffb 100644
--- a/src/System.Memory/tests/Memory/CtorArray.cs
+++ b/src/System.Memory/tests/Memory/CtorArray.cs
@@ -75,7 +75,7 @@ namespace System.MemoryTests
memory.Validate();
Assert.Equal(default, memory);
- memory = new Memory<int>(null, 0, 0);
+ memory = new Memory<int>((int[])null, 0, 0);
memory.Validate();
Assert.Equal(default, memory);
}
@@ -83,10 +83,10 @@ namespace System.MemoryTests
[Fact]
public static void CtorArrayNullArrayNonZeroStartAndLength()
{
- Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>(null, 1, 0));
- Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>(null, 0, 1));
- Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>(null, 1, 1));
- Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>(null, -1, -1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>((int[])null, 1, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>((int[])null, 0, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>((int[])null, 1, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>((int[])null, -1, -1));
}
[Fact]
diff --git a/src/System.Memory/tests/Memory/CustomMemoryForTest.cs b/src/System.Memory/tests/Memory/CustomMemoryForTest.cs
index 2692bee41d..5afebf3832 100644
--- a/src/System.Memory/tests/Memory/CustomMemoryForTest.cs
+++ b/src/System.Memory/tests/Memory/CustomMemoryForTest.cs
@@ -9,7 +9,7 @@ using System.Threading;
namespace System.MemoryTests
{
- public class CustomMemoryForTest<T> : OwnedMemory<T>
+ public class CustomMemoryForTest<T> : MemoryManager<T>
{
private bool _disposed;
private int _referenceCount;
@@ -18,7 +18,7 @@ namespace System.MemoryTests
private readonly int _offset;
private readonly int _length;
- public CustomMemoryForTest(T[] array): this(array, 0, array.Length)
+ public CustomMemoryForTest(T[] array) : this(array, 0, array.Length)
{
}
@@ -33,40 +33,38 @@ namespace System.MemoryTests
public override int Length => _length;
- public override bool IsDisposed => _disposed;
+ public bool IsDisposed => _disposed;
- protected override bool IsRetained => _referenceCount > 0;
+ protected bool IsRetained => _referenceCount > 0;
- public override Span<T> Span
+ public override Span<T> GetSpan()
{
- get
- {
- if (IsDisposed)
- throw new ObjectDisposedException(nameof(CustomMemoryForTest<T>));
- return new Span<T>(_array, _offset, _length);
- }
+ if (IsDisposed)
+ throw new ObjectDisposedException(nameof(CustomMemoryForTest<T>));
+ return new Span<T>(_array, _offset, _length);
}
- public override MemoryHandle Pin(int byteOffset = 0)
+ public override MemoryHandle Pin(int elementIndex = 0)
{
unsafe
{
- Retain(); // this checks IsDisposed
+ if (IsDisposed)
+ throw new ObjectDisposedException(nameof(CustomMemoryForTest<T>));
+ Interlocked.Increment(ref _referenceCount);
try
{
- if ((IntPtr.Size == 4 && (uint)byteOffset > (uint)_array.Length * (uint)Unsafe.SizeOf<T>())
- || (IntPtr.Size != 4 && (ulong)byteOffset > (uint)_array.Length * (ulong)Unsafe.SizeOf<T>()))
+ if ((uint)elementIndex > (uint)(_array.Length - _offset))
{
- throw new ArgumentOutOfRangeException(nameof(byteOffset));
+ throw new ArgumentOutOfRangeException(nameof(elementIndex));
}
var handle = GCHandle.Alloc(_array, GCHandleType.Pinned);
- return new MemoryHandle(this, Unsafe.Add<byte>((void*)handle.AddrOfPinnedObject(), _offset + byteOffset), handle);
+ return new MemoryHandle(Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _offset + elementIndex), handle, this);
}
catch
{
- Release();
+ Unpin();
throw;
}
}
@@ -94,14 +92,7 @@ namespace System.MemoryTests
}
- public override void Retain()
- {
- if (IsDisposed)
- throw new ObjectDisposedException(nameof(CustomMemoryForTest<T>));
- Interlocked.Increment(ref _referenceCount);
- }
-
- public override bool Release()
+ public override void Unpin()
{
int newRefCount = Interlocked.Decrement(ref _referenceCount);
@@ -111,9 +102,7 @@ namespace System.MemoryTests
if (newRefCount == 0)
{
_noReferencesCalledCount++;
- return false;
}
- return true;
}
}
}
diff --git a/src/System.Memory/tests/Memory/OwnedMemory.cs b/src/System.Memory/tests/Memory/MemoryManager.cs
index d75e164b40..4f6f2461cf 100644
--- a/src/System.Memory/tests/Memory/OwnedMemory.cs
+++ b/src/System.Memory/tests/Memory/MemoryManager.cs
@@ -8,16 +8,16 @@ using Xunit;
namespace System.MemoryTests
{
//
- // Tests for internal Memory<T>.ctor(OwnedMemory<T>, int , int)
+ // Tests for Memory<T>.ctor(MemoryManager<T>, int , int)
//
public static partial class MemoryTests
{
[Fact]
- public static void MemoryFromOwnedMemoryInt()
+ public static void MemoryFromMemoryManagerInt()
{
int[] a = { 91, 92, -93, 94 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- Memory<int> memory = owner.Memory;
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ Memory<int> memory = manager.Memory;
memory.Validate(91, 92, -93, 94);
memory.Slice(0, 4).Validate(91, 92, -93, 94);
memory.Slice(1, 0).Validate();
@@ -28,11 +28,11 @@ namespace System.MemoryTests
}
[Fact]
- public static void ReadOnlyMemoryFromMemoryFromOwnedMemoryInt()
+ public static void ReadOnlyMemoryFromMemoryFromMemoryManagerInt()
{
int[] a = { 91, 92, -93, 94 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- ReadOnlyMemory<int> readOnlyMemory = owner.Memory;
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ ReadOnlyMemory<int> readOnlyMemory = manager.Memory;
readOnlyMemory.Validate(91, 92, -93, 94);
readOnlyMemory.Slice(0, 4).Validate(91, 92, -93, 94);
readOnlyMemory.Slice(1, 0).Validate();
@@ -43,11 +43,11 @@ namespace System.MemoryTests
}
[Fact]
- public static void MemoryFromOwnedMemoryLong()
+ public static void MemoryFromMemoryManagerLong()
{
long[] a = { 91, -92, 93, 94, -95 };
- OwnedMemory<long> owner = new CustomMemoryForTest<long>(a);
- Memory<long> memory = owner.Memory;
+ MemoryManager<long> manager = new CustomMemoryForTest<long>(a);
+ Memory<long> memory = manager.Memory;
memory.Validate(91, -92, 93, 94, -95);
memory.Slice(0, 5).Validate(91, -92, 93, 94, -95);
memory.Slice(1, 0).Validate();
@@ -58,58 +58,63 @@ namespace System.MemoryTests
}
[Fact]
- public static void MemoryFromOwnedMemoryObject()
+ public static void MemoryFromMemoryManagerObject()
{
object o1 = new object();
object o2 = new object();
object[] a = { o1, o2 };
- OwnedMemory<object> owner = new CustomMemoryForTest<object>(a);
- Memory<object> memory = owner.Memory;
+ MemoryManager<object> manager = new CustomMemoryForTest<object>(a);
+ Memory<object> memory = manager.Memory;
memory.ValidateReferenceType(o1, o2);
}
[Fact]
- public static void ImplicitReadOnlyMemoryFromOwnedMemory()
+ public static void ImplicitReadOnlyMemoryFromMemoryManager()
{
long[] a = { 91, -92, 93, 94, -95 };
- OwnedMemory<long> owner = new CustomMemoryForTest<long>(a);
- Memory<long> memory = owner.Memory;
+ MemoryManager<long> manager = new CustomMemoryForTest<long>(a);
+ Memory<long> memory = manager.Memory;
CastReadOnly<long>(memory, 91, -92, 93, 94, -95);
}
[Fact]
- public static void OwnedMemoryDispose()
+ public static void MemoryManagerDispose()
{
int[] a = { 91, 92, -93, 94 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- Assert.False(owner.IsDisposed);
- owner.Dispose();
- Assert.True(owner.IsDisposed);
+ CustomMemoryForTest<int> manager;
+ using (manager = new CustomMemoryForTest<int>(a))
+ {
+ Assert.False(manager.IsDisposed);
+ }
+ Assert.True(manager.IsDisposed);
}
-
+
[Fact]
- public static void OwnedMemoryPinEmptyArray()
+ public static void MemoryManagerPinEmptyArray()
{
- int[] a = {};
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- MemoryHandle handle = owner.Pin();
- Assert.True(handle.HasPointer);
+ int[] a = { };
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ MemoryHandle handle = manager.Pin();
+ unsafe
+ {
+ Assert.True(handle.Pointer != null);
+ }
}
[Fact]
- public static void OwnedMemoryPinArray()
+ public static void MemoryManagerPinArray()
{
int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- MemoryHandle handle = owner.Pin();
- Assert.True(handle.HasPointer);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(array);
+ MemoryHandle handle = manager.Pin();
unsafe
{
int* pointer = (int*)handle.Pointer;
+ Assert.True(pointer != null);
GC.Collect();
- for (int i = 0; i < owner.Memory.Length; i++)
+ for (int i = 0; i < manager.Memory.Length; i++)
{
Assert.Equal(array[i], pointer[i]);
}
@@ -120,7 +125,7 @@ namespace System.MemoryTests
[Fact]
[OuterLoop]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Desktop framework doesn't support large arrays by default.")]
- public static void OwnedMemoryPinLargeArray()
+ public static void MemoryManagerPinLargeArray()
{
// Early-out: we can only run this test on 64-bit platforms.
if (IntPtr.Size == 4)
@@ -129,38 +134,20 @@ namespace System.MemoryTests
}
int[] array = new int[0x2000_0000]; // will produce array with total byte length > 2 GB
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- Assert.Throws<ArgumentOutOfRangeException>(() => owner.Pin(int.MinValue));
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(array);
+ Assert.Throws<ArgumentOutOfRangeException>(() => manager.Pin(int.MinValue));
}
[Fact]
- public static void MemoryFromOwnedMemoryAfterDispose()
+ public static void SpanFromMemoryManagerAfterDispose()
{
int[] a = { 91, 92, -93, 94 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- owner.Dispose();
- Assert.Throws<ObjectDisposedException>(() => owner.Memory);
- }
-
- [Fact]
- public static void DisposeOwnedMemoryAfterRetain()
- {
- int[] a = { 91, 92, -93, 94 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- owner.Retain();
- Assert.Throws<InvalidOperationException>(() => owner.Dispose());
- owner.Release();
- }
+ MemoryManager<int> manager;
+ using (manager = new CustomMemoryForTest<int>(a))
+ {
- [Fact]
- public static void DisposeOwnedMemoryAfterRetainAndRelease()
- {
- int[] a = { 91, 92, -93, 94 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- owner.Retain();
- owner.Release();
- owner.Dispose();
- Assert.True(owner.IsDisposed);
+ }
+ Assert.Throws<ObjectDisposedException>(() => manager.GetSpan());
}
}
diff --git a/src/System.Memory/tests/Memory/Pin.cs b/src/System.Memory/tests/Memory/Pin.cs
index 2d0d8ff523..a52af07006 100644
--- a/src/System.Memory/tests/Memory/Pin.cs
+++ b/src/System.Memory/tests/Memory/Pin.cs
@@ -15,10 +15,10 @@ namespace System.MemoryTests
int[] array = { 1, 2, 3, 4, 5 };
Memory<int> memory = array;
MemoryHandle handle = memory.Pin();
- Assert.True(handle.HasPointer);
unsafe
{
int* pointer = (int*)handle.Pointer;
+ Assert.True(pointer != null);
GC.Collect();
@@ -35,7 +35,10 @@ namespace System.MemoryTests
{
Memory<int> memory = new int[0];
MemoryHandle handle = memory.Pin();
- Assert.True(handle.HasPointer);
+ unsafe
+ {
+ Assert.True(handle.Pointer != null);
+ }
handle.Dispose();
}
@@ -44,7 +47,6 @@ namespace System.MemoryTests
{
Memory<int> memory = default;
MemoryHandle handle = memory.Pin();
- Assert.False(handle.HasPointer);
unsafe
{
Assert.True(handle.Pointer == null);
@@ -60,10 +62,10 @@ namespace System.MemoryTests
memory = memory.Slice(1);
MemoryHandle handle = memory.Pin();
Span<int> span = memory.Span;
- Assert.True(handle.HasPointer);
unsafe
{
int* pointer = (int*)handle.Pointer;
+ Assert.True(pointer != null);
GC.Collect();
@@ -81,16 +83,16 @@ namespace System.MemoryTests
}
[Fact]
- public static void OwnedMemoryPin()
+ public static void MemoryManagerPin()
{
int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- Memory<int> memory = owner.Memory;
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(array);
+ Memory<int> memory = manager.Memory;
MemoryHandle handle = memory.Pin();
- Assert.True(handle.HasPointer);
unsafe
{
int* pointer = (int*)handle.Pointer;
+ Assert.True(pointer != null);
GC.Collect();
@@ -103,17 +105,17 @@ namespace System.MemoryTests
}
[Fact]
- public static void OwnedMemoryPinAndSlice()
+ public static void MemoryManagerPinAndSlice()
{
int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- Memory<int> memory = owner.Memory.Slice(1);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(array);
+ Memory<int> memory = manager.Memory.Slice(1);
MemoryHandle handle = memory.Pin();
Span<int> span = memory.Span;
- Assert.True(handle.HasPointer);
unsafe
{
int* pointer = (int*)handle.Pointer;
+ Assert.True(pointer != null);
GC.Collect();
diff --git a/src/System.Memory/tests/Memory/Retain.cs b/src/System.Memory/tests/Memory/Retain.cs
deleted file mode 100644
index 1ef319103c..0000000000
--- a/src/System.Memory/tests/Memory/Retain.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-// 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.Buffers;
-using Xunit;
-
-namespace System.MemoryTests
-{
- public static partial class MemoryTests
- {
-
- [Fact]
- public static void MemoryRetainWithoutPinning()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- Memory<int> memory = array;
- MemoryHandle handle = memory.Retain();
- Assert.False(handle.HasPointer);
- unsafe
- {
- Assert.True(handle.Pointer == null);
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void MemoryRetainWithPinning()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- Memory<int> memory = array;
- MemoryHandle handle = memory.Retain(pin: true);
- Assert.True(handle.HasPointer);
- unsafe
- {
- int* pointer = (int*)handle.Pointer;
-
- GC.Collect();
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i], pointer[i]);
- }
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void MemoryFromEmptyArrayRetainWithPinning()
- {
- Memory<int> memory = new int[0];
- MemoryHandle handle = memory.Retain(pin: true);
- Assert.True(handle.HasPointer);
- handle.Dispose();
- }
-
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public static void DefaultMemoryRetain(bool pin)
- {
- Memory<int> memory = default;
- MemoryHandle handle = memory.Retain(pin: pin);
- Assert.False(handle.HasPointer);
- unsafe
- {
- Assert.True(handle.Pointer == null);
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void MemoryRetainWithPinningAndSlice()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- Memory<int> memory = array;
- memory = memory.Slice(1);
- MemoryHandle handle = memory.Retain(pin: true);
- Span<int> span = memory.Span;
- Assert.True(handle.HasPointer);
- unsafe
- {
- int* pointer = (int*)handle.Pointer;
-
- GC.Collect();
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i + 1], pointer[i]);
- }
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i + 1], span[i]);
- }
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void OwnedMemoryRetainWithoutPinning()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- Memory<int> memory = owner.Memory;
- MemoryHandle handle = memory.Retain();
- Assert.False(handle.HasPointer);
- unsafe
- {
- Assert.True(handle.Pointer == null);
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void OwnedMemoryRetainWithPinning()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- Memory<int> memory = owner.Memory;
- MemoryHandle handle = memory.Retain(pin: true);
- Assert.True(handle.HasPointer);
- unsafe
- {
- int* pointer = (int*)handle.Pointer;
-
- GC.Collect();
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i], pointer[i]);
- }
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void OwnedMemoryRetainWithPinningAndSlice()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- Memory<int> memory = owner.Memory.Slice(1);
- MemoryHandle handle = memory.Retain(pin: true);
- Span<int> span = memory.Span;
- Assert.True(handle.HasPointer);
- unsafe
- {
- int* pointer = (int*)handle.Pointer;
-
- GC.Collect();
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i + 1], pointer[i]);
- }
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i + 1], span[i]);
- }
- }
- handle.Dispose();
- }
- }
-}
diff --git a/src/System.Memory/tests/Memory/Slice.cs b/src/System.Memory/tests/Memory/Slice.cs
index c047472175..16e330cf3b 100644
--- a/src/System.Memory/tests/Memory/Slice.cs
+++ b/src/System.Memory/tests/Memory/Slice.cs
@@ -19,11 +19,11 @@ namespace System.MemoryTests
Assert.Equal(4, memory.Length);
Assert.True(Unsafe.AreSame(ref a[6], ref MemoryMarshal.GetReference(memory.Span)));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- Memory<int> memoryFromOwner = owner.Memory.Slice(6);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ Memory<int> memoryFromManager = manager.Memory.Slice(6);
- Assert.Equal(4, memoryFromOwner.Length);
- Assert.True(Unsafe.AreSame(ref a[6], ref MemoryMarshal.GetReference(memoryFromOwner.Span)));
+ Assert.Equal(4, memoryFromManager.Length);
+ Assert.True(Unsafe.AreSame(ref a[6], ref MemoryMarshal.GetReference(memoryFromManager.Span)));
}
[Fact]
@@ -34,11 +34,11 @@ namespace System.MemoryTests
Assert.Equal(0, memory.Length);
Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref MemoryMarshal.GetReference(memory.Span), 1)));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- Memory<int> memoryFromOwner = owner.Memory.Slice(a.Length);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ Memory<int> memoryFromManager = manager.Memory.Slice(a.Length);
- Assert.Equal(0, memoryFromOwner.Length);
- Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref MemoryMarshal.GetReference(memoryFromOwner.Span), 1)));
+ Assert.Equal(0, memoryFromManager.Length);
+ Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref MemoryMarshal.GetReference(memoryFromManager.Span), 1)));
}
[Fact]
@@ -49,11 +49,11 @@ namespace System.MemoryTests
Assert.Equal(5, memory.Length);
Assert.True(Unsafe.AreSame(ref a[3], ref MemoryMarshal.GetReference(memory.Span)));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- Memory<int> memoryFromOwner = owner.Memory.Slice(3, 5);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ Memory<int> memoryFromManager = manager.Memory.Slice(3, 5);
- Assert.Equal(5, memoryFromOwner.Length);
- Assert.True(Unsafe.AreSame(ref a[3], ref MemoryMarshal.GetReference(memoryFromOwner.Span)));
+ Assert.Equal(5, memoryFromManager.Length);
+ Assert.True(Unsafe.AreSame(ref a[3], ref MemoryMarshal.GetReference(memoryFromManager.Span)));
}
[Fact]
@@ -64,11 +64,11 @@ namespace System.MemoryTests
Assert.Equal(6, memory.Length);
Assert.True(Unsafe.AreSame(ref a[4], ref MemoryMarshal.GetReference(memory.Span)));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- Memory<int> memoryFromOwner = owner.Memory.Slice(4, 6);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ Memory<int> memoryFromManager = manager.Memory.Slice(4, 6);
- Assert.Equal(6, memoryFromOwner.Length);
- Assert.True(Unsafe.AreSame(ref a[4], ref MemoryMarshal.GetReference(memoryFromOwner.Span)));
+ Assert.Equal(6, memoryFromManager.Length);
+ Assert.True(Unsafe.AreSame(ref a[4], ref MemoryMarshal.GetReference(memoryFromManager.Span)));
}
[Fact]
@@ -79,11 +79,11 @@ namespace System.MemoryTests
Assert.Equal(0, memory.Length);
Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref MemoryMarshal.GetReference(memory.Span), 1)));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- Memory<int> memoryFromOwner = owner.Memory.Slice(a.Length, 0);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ Memory<int> memoryFromManager = manager.Memory.Slice(a.Length, 0);
- Assert.Equal(0, memoryFromOwner.Length);
- Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref MemoryMarshal.GetReference(memoryFromOwner.Span), 1)));
+ Assert.Equal(0, memoryFromManager.Length);
+ Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref MemoryMarshal.GetReference(memoryFromManager.Span), 1)));
}
[Fact]
@@ -98,8 +98,8 @@ namespace System.MemoryTests
Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>(a).Slice(a.Length + 1, 0));
Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>(a).Slice(a.Length, 1));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- Memory<int> memory = owner.Memory;
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ Memory<int> memory = manager.Memory;
Assert.Throws<ArgumentOutOfRangeException>(() => memory.Slice(-1));
Assert.Throws<ArgumentOutOfRangeException>(() => memory.Slice(a.Length + 1));
diff --git a/src/System.Memory/tests/Memory/Span.cs b/src/System.Memory/tests/Memory/Span.cs
index 607a56a82e..472310d786 100644
--- a/src/System.Memory/tests/Memory/Span.cs
+++ b/src/System.Memory/tests/Memory/Span.cs
@@ -21,8 +21,8 @@ namespace System.MemoryTests
memory = new Memory<int>(a, 0, a.Length);
memory.Span.Validate(91, 92, -93, 94);
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- owner.Memory.Span.Validate(91, 92, -93, 94);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ manager.Memory.Span.Validate(91, 92, -93, 94);
}
[Fact]
@@ -37,8 +37,8 @@ namespace System.MemoryTests
memory = new Memory<long>(a, 0, a.Length);
memory.Span.Validate(91, -92, 93, 94, -95);
- OwnedMemory<long> owner = new CustomMemoryForTest<long>(a);
- owner.Memory.Span.Validate(91, -92, 93, 94, -95);
+ MemoryManager<long> manager = new CustomMemoryForTest<long>(a);
+ manager.Memory.Span.Validate(91, -92, 93, 94, -95);
}
[Fact]
@@ -55,8 +55,8 @@ namespace System.MemoryTests
memory = new Memory<object>(a, 0, a.Length);
memory.Span.ValidateReferenceType(o1, o2);
- OwnedMemory<object> owner = new CustomMemoryForTest<object>(a);
- owner.Memory.Span.ValidateReferenceType(o1, o2);
+ MemoryManager<object> manager = new CustomMemoryForTest<object>(a);
+ manager.Memory.Span.ValidateReferenceType(o1, o2);
}
[Fact]
@@ -71,8 +71,8 @@ namespace System.MemoryTests
memory = new Memory<int>(empty, 0, empty.Length);
memory.Span.ValidateNonNullEmpty();
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(empty);
- owner.Memory.Span.Validate();
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(empty);
+ manager.Memory.Span.Validate();
}
[Fact]
@@ -90,8 +90,8 @@ namespace System.MemoryTests
memory = new Memory<int>(aAsIntArray, 0, aAsIntArray.Length);
memory.Span.Validate(42, -1);
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(aAsIntArray);
- owner.Memory.Span.Validate(42, -1);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(aAsIntArray);
+ manager.Memory.Span.Validate(42, -1);
}
[Fact]
diff --git a/src/System.Memory/tests/Memory/ToString.cs b/src/System.Memory/tests/Memory/ToString.cs
index e6eb713c8a..98be45eee6 100644
--- a/src/System.Memory/tests/Memory/ToString.cs
+++ b/src/System.Memory/tests/Memory/ToString.cs
@@ -69,28 +69,28 @@ namespace System.MemoryTests
}
[Fact]
- public static void ToStringFromMemoryFromOwnedMemory()
+ public static void ToStringFromMemoryFromMemoryManager()
{
int[] a = { 91, 92, -93, 94 };
- OwnedMemory<int> intOwner = new CustomMemoryForTest<int>(a);
- Assert.Equal("System.Memory<Int32>[4]", intOwner.Memory.ToString());
+ MemoryManager<int> intManager = new CustomMemoryForTest<int>(a);
+ Assert.Equal("System.Memory<Int32>[4]", intManager.Memory.ToString());
- intOwner = new CustomMemoryForTest<int>(Array.Empty<int>());
- Assert.Equal("System.Memory<Int32>[0]", intOwner.Memory.ToString());
+ intManager = new CustomMemoryForTest<int>(Array.Empty<int>());
+ Assert.Equal("System.Memory<Int32>[0]", intManager.Memory.ToString());
char[] charArray = { '1', '2', '-', '4' };
- OwnedMemory<char> charOwner = new CustomMemoryForTest<char>(charArray);
- Assert.Equal("12-4", charOwner.Memory.ToString());
+ MemoryManager<char> charManager = new CustomMemoryForTest<char>(charArray);
+ Assert.Equal("12-4", charManager.Memory.ToString());
- charOwner = new CustomMemoryForTest<char>(Array.Empty<char>());
- Assert.Equal("", charOwner.Memory.ToString());
+ charManager = new CustomMemoryForTest<char>(Array.Empty<char>());
+ Assert.Equal("", charManager.Memory.ToString());
string[] strArray = { "91", "92", "-93", "94" };
- OwnedMemory<string> strOwner = new CustomMemoryForTest<string>(strArray);
- Assert.Equal("System.Memory<String>[4]", strOwner.Memory.ToString());
+ MemoryManager<string> strManager = new CustomMemoryForTest<string>(strArray);
+ Assert.Equal("System.Memory<String>[4]", strManager.Memory.ToString());
- strOwner = new CustomMemoryForTest<string>(Array.Empty<string>());
- Assert.Equal("System.Memory<String>[0]", strOwner.Memory.ToString());
+ strManager = new CustomMemoryForTest<string>(Array.Empty<string>());
+ Assert.Equal("System.Memory<String>[0]", strManager.Memory.ToString());
}
[Fact]
diff --git a/src/System.Memory/tests/MemoryMarshal/TryGetArray.cs b/src/System.Memory/tests/MemoryMarshal/TryGetArray.cs
index 0443ed7a6e..045d5e9a7c 100644
--- a/src/System.Memory/tests/MemoryMarshal/TryGetArray.cs
+++ b/src/System.Memory/tests/MemoryMarshal/TryGetArray.cs
@@ -33,11 +33,11 @@ namespace System.MemoryTests
}
[Fact]
- public static void OwnedMemoryTryGetArray()
+ public static void MemoryManagerTryGetArray()
{
int[] array = new int[10];
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- ReadOnlyMemory<int> memory = owner.Memory;
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = manager.Memory;
Assert.True(MemoryMarshal.TryGetArray(memory, out ArraySegment<int> segment));
Assert.Equal(array.Length, segment.Count);
@@ -62,22 +62,22 @@ namespace System.MemoryTests
}
[Fact]
- public static void TryGetArrayFromEmptyOwnedMemory()
+ public static void TryGetArrayFromEmptyMemoryManager()
{
int[] array = new int[0];
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(array);
- Assert.True(MemoryMarshal.TryGetArray(owner.Memory, out ArraySegment<int> segment));
+ Assert.True(MemoryMarshal.TryGetArray(manager.Memory, out ArraySegment<int> segment));
Assert.Same(array, segment.Array);
Assert.Equal(0, segment.Array.Length);
}
[Fact]
- public static void TryGetArrayFromEmptyNonRetrievableOwnedMemory()
+ public static void TryGetArrayFromEmptyNonRetrievableMemoryManager()
{
- using (var owner = new NativeOwnedMemory(0))
+ using (var manager = new NativeMemoryManager(0))
{
- Assert.True(MemoryMarshal.TryGetArray(owner.Memory, out ArraySegment<byte> segment));
+ Assert.True(MemoryMarshal.TryGetArray(manager.Memory, out ArraySegment<byte> segment));
Assert.Equal(0, segment.Array.Length);
}
}
diff --git a/src/System.Memory/tests/MemoryMarshal/TryGetMemoryManager.cs b/src/System.Memory/tests/MemoryMarshal/TryGetMemoryManager.cs
new file mode 100644
index 0000000000..3935af40a1
--- /dev/null
+++ b/src/System.Memory/tests/MemoryMarshal/TryGetMemoryManager.cs
@@ -0,0 +1,89 @@
+// 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.Buffers;
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace System.MemoryTests
+{
+ public static partial class MemoryMarshalTests
+ {
+ [Fact]
+ public static void TryGetMemoryManagerFromDefaultMemory()
+ {
+ ReadOnlyMemory<int> memory = default;
+ Assert.False(MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<int> manager));
+ Assert.Null(manager);
+ }
+
+ [Fact]
+ public static void TryGetMemoryManager()
+ {
+ int[] array = new int[10];
+ MemoryManager<int> originalManager = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = originalManager.Memory;
+
+ Assert.True(MemoryMarshal.TryGetMemoryManager(memory, out CustomMemoryForTest<int> customManager));
+ Assert.Same(originalManager, customManager);
+
+ Assert.True(MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<int> manager));
+ Assert.Same(originalManager, manager);
+
+ Assert.False(MemoryMarshal.TryGetMemoryManager(memory, out OtherMemoryForTest<int> notManager));
+ Assert.Null(notManager);
+ }
+
+ [Fact]
+ public static void TryGetMemoryManagerFromDefaultMemory_IndexLength()
+ {
+ ReadOnlyMemory<int> memory = default;
+ Assert.False(MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager<int> manager, out int index, out int length));
+ Assert.Equal(0, index);
+ Assert.Equal(0, length);
+ Assert.Null(manager);
+ }
+
+ [Fact]
+ public static void TryGetMemoryManager_IndexLength()
+ {
+ int[] array = new int[10];
+ MemoryManager<int> originalManager = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = originalManager.Memory;
+
+ for (int i = 0; i < array.Length; i++)
+ {
+ Assert.True(MemoryMarshal.TryGetMemoryManager(memory.Slice(i), out CustomMemoryForTest<int> customOwner, out int index, out int length));
+ Assert.Same(originalManager, customOwner);
+ Assert.Equal(i, index);
+ Assert.Equal(array.Length - i, length);
+ }
+
+ for (int i = 0; i < array.Length; i++)
+ {
+ Assert.True(MemoryMarshal.TryGetMemoryManager(memory.Slice(i), out MemoryManager<int> manager, out int index, out int length));
+ Assert.Same(originalManager, manager);
+ Assert.Equal(i, index);
+ Assert.Equal(array.Length - i, length);
+ }
+
+ for (int i = 0; i < array.Length; i++)
+ {
+ Assert.False(MemoryMarshal.TryGetMemoryManager(memory.Slice(i), out OtherMemoryForTest<int> notManager, out int index, out int length));
+ Assert.Null(notManager);
+ }
+ }
+
+ internal class OtherMemoryForTest<T> : MemoryManager<T>
+ {
+ public OtherMemoryForTest() { }
+
+ public override int Length => 0;
+ public override Span<T> GetSpan() => throw new NotImplementedException();
+ public override MemoryHandle Pin(int elementIndex = 0) => throw new NotImplementedException();
+ protected override void Dispose(bool disposing) => throw new NotImplementedException();
+ public override void Unpin() => throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/System.Memory/tests/MemoryMarshal/TryGetOwnedMemory.cs b/src/System.Memory/tests/MemoryMarshal/TryGetOwnedMemory.cs
deleted file mode 100644
index c786042f02..0000000000
--- a/src/System.Memory/tests/MemoryMarshal/TryGetOwnedMemory.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-// 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.Buffers;
-using System.Runtime.InteropServices;
-using Xunit;
-
-namespace System.MemoryTests
-{
- public static partial class MemoryMarshalTests
- {
- [Fact]
- public static void TryGetOwnedMemoryFromDefaultMemory()
- {
- ReadOnlyMemory<int> memory = default;
- Assert.False(MemoryMarshal.TryGetOwnedMemory(memory, out OwnedMemory<int> owner));
- Assert.Null(owner);
- }
-
- [Fact]
- public static void TryGetOwnedMemory()
- {
- int[] array = new int[10];
- OwnedMemory<int> orignalOwner = new CustomMemoryForTest<int>(array);
- ReadOnlyMemory<int> memory = orignalOwner.Memory;
-
- Assert.True(MemoryMarshal.TryGetOwnedMemory(memory, out CustomMemoryForTest<int> customOwner));
- Assert.Same(orignalOwner, customOwner);
-
- Assert.True(MemoryMarshal.TryGetOwnedMemory(memory, out OwnedMemory<int> owner));
- Assert.Same(orignalOwner, owner);
-
- Assert.False(MemoryMarshal.TryGetOwnedMemory(memory, out OtherMemoryForTest<int> notOwner));
- Assert.Null(notOwner);
- }
-
- [Fact]
- public static void TryGetOwnedMemoryFromDefaultMemory_IndexLength()
- {
- ReadOnlyMemory<int> memory = default;
- Assert.False(MemoryMarshal.TryGetOwnedMemory(memory, out OwnedMemory<int> owner, out int index, out int length));
- Assert.Equal(0, index);
- Assert.Equal(0, length);
- Assert.Null(owner);
- }
-
- [Fact]
- public static void TryGetOwnedMemory_IndexLength()
- {
- int[] array = new int[10];
- OwnedMemory<int> orignalOwner = new CustomMemoryForTest<int>(array);
- ReadOnlyMemory<int> memory = orignalOwner.Memory;
-
- for (int i = 0; i < array.Length; i++)
- {
- Assert.True(MemoryMarshal.TryGetOwnedMemory(memory.Slice(i), out CustomMemoryForTest<int> customOwner, out int index, out int length));
- Assert.Same(orignalOwner, customOwner);
- Assert.Equal(i, index);
- Assert.Equal(array.Length - i, length);
- }
-
- for (int i = 0; i < array.Length; i++)
- {
- Assert.True(MemoryMarshal.TryGetOwnedMemory(memory.Slice(i), out OwnedMemory<int> owner, out int index, out int length));
- Assert.Same(orignalOwner, owner);
- Assert.Equal(i, index);
- Assert.Equal(array.Length - i, length);
- }
-
- for (int i = 0; i < array.Length; i++)
- {
- Assert.False(MemoryMarshal.TryGetOwnedMemory(memory.Slice(i), out OtherMemoryForTest<int> notOwner, out int index, out int length));
- Assert.Null(notOwner);
- }
- }
-
- internal class OtherMemoryForTest<T> : OwnedMemory<T>
- {
- public OtherMemoryForTest() { }
-
- public override int Length => 0;
- public override bool IsDisposed => false;
- protected override bool IsRetained => false;
- public override Span<T> Span => throw new NotImplementedException();
- public override MemoryHandle Pin(int byteOffset = 0) => throw new NotImplementedException();
- protected override bool TryGetArray(out ArraySegment<T> segment) => throw new NotImplementedException();
- protected override void Dispose(bool disposing) => throw new NotImplementedException();
- public override void Retain() => throw new NotImplementedException();
- public override bool Release() => throw new NotImplementedException();
- }
- }
-}
diff --git a/src/System.Memory/tests/MemoryPool/MemoryPool.cs b/src/System.Memory/tests/MemoryPool/MemoryPool.cs
index 63d3419972..7af3434e70 100644
--- a/src/System.Memory/tests/MemoryPool/MemoryPool.cs
+++ b/src/System.Memory/tests/MemoryPool/MemoryPool.cs
@@ -26,10 +26,9 @@ namespace System.MemoryTests
MemoryPool<int> mp = MemoryPool<int>.Shared;
mp.Dispose();
mp.Dispose();
- using (OwnedMemory<int> block = mp.Rent(10))
+ using (IMemoryOwner<int> block = mp.Rent(10))
{
- Assert.True(block.Length >= 10);
- block.Release();
+ Assert.True(block.Memory.Length >= 10);
}
}
@@ -44,11 +43,13 @@ namespace System.MemoryTests
public static void MemoryPoolSpan()
{
MemoryPool<int> pool = MemoryPool<int>.Shared;
- using (OwnedMemory<int> block = pool.Rent(10))
+ using (IMemoryOwner<int> block = pool.Rent(10))
{
- Span<int> sp = block.Span;
- Assert.Equal(block.Length, sp.Length);
- using (MemoryHandle newMemoryHandle = block.Pin())
+ Memory<int> memory = block.Memory;
+ Span<int> sp = memory.Span;
+ Assert.Equal(memory.Length, sp.Length);
+ Assert.True(MemoryMarshal.TryGetMemoryManager<int, MemoryManager<int>>(memory, out MemoryManager<int> manager));
+ using (MemoryHandle newMemoryHandle = manager.Pin())
{
unsafe
{
@@ -56,69 +57,63 @@ namespace System.MemoryTests
Assert.Equal((IntPtr)newMemoryHandle.Pointer, (IntPtr)pSpan);
}
}
- block.Release();
}
}
[Theory]
[InlineData(0)]
[InlineData(3)]
- [InlineData(10 * sizeof(int))]
- public static void MemoryPoolPin(int byteOffset)
+ [InlineData(10)]
+ public static void MemoryPoolPin(int elementIndex)
{
MemoryPool<int> pool = MemoryPool<int>.Shared;
- using (OwnedMemory<int> block = pool.Rent(10))
+ using (IMemoryOwner<int> block = pool.Rent(10))
{
- Span<int> sp = block.Span;
- Assert.Equal(block.Length, sp.Length);
- using (MemoryHandle newMemoryHandle = block.Pin(byteOffset: byteOffset))
+ Memory<int> memory = block.Memory;
+ Span<int> sp = memory.Span;
+ Assert.Equal(memory.Length, sp.Length);
+ Assert.True(MemoryMarshal.TryGetMemoryManager<int, MemoryManager<int>>(memory, out MemoryManager<int> manager));
+ using (MemoryHandle newMemoryHandle = manager.Pin(elementIndex: elementIndex))
{
unsafe
{
- void* pSpan = Unsafe.AsPointer(ref MemoryMarshal.GetReference(sp));
- Assert.Equal((IntPtr)pSpan, ((IntPtr)newMemoryHandle.Pointer) - byteOffset);
+ void* pSpan = Unsafe.AsPointer(ref MemoryMarshal.GetReference(sp.Slice(elementIndex)));
+ Assert.Equal((IntPtr)pSpan, ((IntPtr)newMemoryHandle.Pointer));
}
}
- block.Release();
}
}
[Theory]
[InlineData(-1)]
[InlineData(int.MinValue)]
- public static void MemoryPoolPinBadOffset(int byteOffset)
+ public static void MemoryPoolPinBadOffset(int elementIndex)
{
MemoryPool<int> pool = MemoryPool<int>.Shared;
- OwnedMemory<int> block = pool.Rent(10);
- Span<int> sp = block.Span;
- Assert.Equal(block.Length, sp.Length);
- Assert.Throws<ArgumentOutOfRangeException>(() => block.Pin(byteOffset: byteOffset));
+ IMemoryOwner<int> block = pool.Rent(10);
+ Memory<int> memory = block.Memory;
+ Span<int> sp = memory.Span;
+ Assert.Equal(memory.Length, sp.Length);
+ Assert.Throws<ArgumentOutOfRangeException>(() => ((MemoryManager<int>)block).Pin(elementIndex: elementIndex));
}
[Fact]
public static void MemoryPoolPinOffsetAtEnd()
{
MemoryPool<int> pool = MemoryPool<int>.Shared;
- OwnedMemory<int> block = pool.Rent(10);
- Span<int> sp = block.Span;
- Assert.Equal(block.Length, sp.Length);
-
- int byteOffset = 0;
- try
- {
- byteOffset = checked(block.Length * sizeof(int));
- }
- catch (OverflowException)
- {
- return; // The pool gave us a very large block - too big to compute the byteOffset needed to carry out this test. Skip.
- }
+ IMemoryOwner<int> block = pool.Rent(10);
+ Memory<int> memory = block.Memory;
+ Span<int> sp = memory.Span;
+ Assert.Equal(memory.Length, sp.Length);
- using (MemoryHandle newMemoryHandle = block.Pin(byteOffset: byteOffset))
+ int elementIndex = memory.Length;
+ Assert.True(MemoryMarshal.TryGetMemoryManager<int, MemoryManager<int>>(memory, out MemoryManager<int> manager));
+ using (MemoryHandle newMemoryHandle = manager.Pin(elementIndex: elementIndex))
{
unsafe
{
- void* pSpan = Unsafe.AsPointer(ref MemoryMarshal.GetReference(sp));
- Assert.Equal((IntPtr)pSpan, ((IntPtr)newMemoryHandle.Pointer) - byteOffset);
+ void* pSpan = Unsafe.AsPointer(ref MemoryMarshal.GetReference(sp.Slice(elementIndex)));
+ Assert.Equal((IntPtr)pSpan, ((IntPtr)newMemoryHandle.Pointer));
}
}
}
@@ -127,28 +122,21 @@ namespace System.MemoryTests
public static void MemoryPoolPinBadOffsetTooLarge()
{
MemoryPool<int> pool = MemoryPool<int>.Shared;
- OwnedMemory<int> block = pool.Rent(10);
- Span<int> sp = block.Span;
- Assert.Equal(block.Length, sp.Length);
-
- int byteOffset = 0;
- try
- {
- byteOffset = checked(block.Length * sizeof(int) + 1);
- }
- catch (OverflowException)
- {
- return; // The pool gave us a very large block - too big to compute the byteOffset needed to carry out this test. Skip.
- }
+ IMemoryOwner<int> block = pool.Rent(10);
+ Memory<int> memory = block.Memory;
+ Span<int> sp = memory.Span;
+ Assert.Equal(memory.Length, sp.Length);
- Assert.Throws<ArgumentOutOfRangeException>(() => block.Pin(byteOffset: byteOffset));
+ int elementIndex = memory.Length + 1;
+ Assert.True(MemoryMarshal.TryGetMemoryManager<int, MemoryManager<int>>(memory, out MemoryManager<int> manager));
+ Assert.Throws<ArgumentOutOfRangeException>(() => manager.Pin(elementIndex: elementIndex));
}
[Fact]
public static void EachRentalIsUniqueUntilDisposed()
{
MemoryPool<int> pool = MemoryPool<int>.Shared;
- List<OwnedMemory<int>> priorBlocks = new List<OwnedMemory<int>>();
+ List<IMemoryOwner<int>> priorBlocks = new List<IMemoryOwner<int>>();
Random r = new Random(42);
List<int> testInputs = new List<int>();
@@ -159,14 +147,16 @@ namespace System.MemoryTests
foreach (int minBufferSize in testInputs)
{
- OwnedMemory<int> newBlock = pool.Rent(minBufferSize);
- Assert.True(newBlock.Length >= minBufferSize);
-
- foreach (OwnedMemory<int> prior in priorBlocks)
+ IMemoryOwner<int> newBlock = pool.Rent(minBufferSize);
+ Memory<int> memory = newBlock.Memory;
+ Assert.True(memory.Length >= minBufferSize);
+ Assert.True(MemoryMarshal.TryGetMemoryManager<int, MemoryManager<int>>(newBlock.Memory, out MemoryManager<int> newManager));
+ foreach (IMemoryOwner<int> prior in priorBlocks)
{
- using (MemoryHandle priorMemoryHandle = prior.Pin())
+ Assert.True(MemoryMarshal.TryGetMemoryManager<int, MemoryManager<int>>(prior.Memory, out MemoryManager<int> priorManager));
+ using (MemoryHandle priorMemoryHandle = priorManager.Pin())
{
- using (MemoryHandle newMemoryHandle = newBlock.Pin())
+ using (MemoryHandle newMemoryHandle = newManager.Pin())
{
unsafe
{
@@ -178,9 +168,10 @@ namespace System.MemoryTests
priorBlocks.Add(newBlock);
}
- foreach (OwnedMemory<int> prior in priorBlocks)
+ foreach (IMemoryOwner<int> prior in priorBlocks)
{
- prior.Release();
+ Assert.True(MemoryMarshal.TryGetMemoryManager<int, MemoryManager<int>>(prior.Memory, out MemoryManager<int> priorManager));
+ priorManager.Unpin();
prior.Dispose();
}
}
@@ -188,10 +179,15 @@ namespace System.MemoryTests
[Fact]
public static void RentWithDefaultSize()
{
- using (OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(minBufferSize: -1))
+ using (IMemoryOwner<int> block = MemoryPool<int>.Shared.Rent(minBufferSize: -1))
+ {
+ Assert.True(block.Memory.Length >= 1);
+ }
+
+ using (IMemoryOwner<int> block = MemoryPool<int>.Shared.Rent(minBufferSize: -1))
{
- Assert.True(block.Length >= 1);
- block.Release();
+ Assert.True(block.Memory.Length >= 1);
+ block.Dispose(); // intentional double dispose
}
}
@@ -215,66 +211,29 @@ namespace System.MemoryTests
[Fact]
public static void MemoryPoolTryGetArray()
{
- using (OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42))
+ using (IMemoryOwner<int> block = MemoryPool<int>.Shared.Rent(42))
{
Memory<int> memory = block.Memory;
bool success = MemoryMarshal.TryGetArray(memory, out ArraySegment<int> arraySegment);
Assert.True(success);
- Assert.Equal(block.Length, arraySegment.Count);
+ Assert.Equal(memory.Length, arraySegment.Count);
unsafe
{
- void* pSpan = Unsafe.AsPointer(ref MemoryMarshal.GetReference(block.Span));
+ Assert.True(MemoryMarshal.TryGetMemoryManager<int, MemoryManager<int>>(memory, out MemoryManager<int> manager));
+ void* pSpan = Unsafe.AsPointer(ref MemoryMarshal.GetReference(manager.GetSpan()));
fixed (int* pArray = arraySegment.Array)
{
Assert.Equal((IntPtr)pSpan, (IntPtr)pArray);
}
}
- block.Release();
- }
- }
-
- [Fact]
- public static void RefCounting()
- {
- using (OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42))
- {
- block.Retain();
- block.Retain();
- block.Retain();
-
- bool moreToGo;
- moreToGo = block.Release();
- Assert.True(moreToGo);
-
- moreToGo = block.Release();
- Assert.True(moreToGo);
-
- moreToGo = block.Release();
- Assert.True(moreToGo);
-
- moreToGo = block.Release();
- Assert.False(moreToGo);
-
- Assert.Throws<ObjectDisposedException>(() => block.Release());
}
}
[Fact]
- public static void IsDisposed()
- {
- OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
- Assert.False(block.IsDisposed);
- block.Release();
- Assert.True(block.IsDisposed);
- block.Dispose();
- Assert.True(block.IsDisposed);
- }
-
- [Fact]
public static void ExtraDisposesAreIgnored()
{
- OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
- block.Release();
+ IMemoryOwner<int> block = MemoryPool<int>.Shared.Rent(42);
+ ((MemoryManager<int>)block).Unpin();
block.Dispose();
block.Dispose();
}
@@ -282,64 +241,39 @@ namespace System.MemoryTests
[Fact]
public static void NoSpanAfterDispose()
{
- OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
- block.Release();
- block.Dispose();
- Assert.Throws<ObjectDisposedException>(() => block.Span.DontBox());
- }
-
- [Fact]
- public static void NoRetainAfterDispose()
- {
- OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
- block.Release();
+ IMemoryOwner<int> block = MemoryPool<int>.Shared.Rent(42);
+ ((MemoryManager<int>)block).Unpin();
block.Dispose();
- Assert.Throws<ObjectDisposedException>(() => block.Retain());
+ Assert.Throws<ObjectDisposedException>(() => ((MemoryManager<int>)block).GetSpan().DontBox());
}
[Fact]
- public static void NoRelease_AfterDispose()
+ public static void NoPinAfterDispose()
{
- OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
- block.Release();
+ IMemoryOwner<int> block = MemoryPool<int>.Shared.Rent(42);
+ ((MemoryManager<int>)block).Unpin();
block.Dispose();
- Assert.Throws<ObjectDisposedException>(() => block.Release());
+ Assert.Throws<ObjectDisposedException>(() => ((MemoryManager<int>)block).Pin());
}
[Fact]
- public static void NoPinAfterDispose()
+ public static void NoUnpin_AfterDispose()
{
- OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
- block.Release();
+ IMemoryOwner<int> block = MemoryPool<int>.Shared.Rent(42);
+ ((MemoryManager<int>)block).Unpin();
block.Dispose();
- Assert.Throws<ObjectDisposedException>(() => block.Pin());
+ Assert.Throws<ObjectDisposedException>(() => ((MemoryManager<int>)block).Unpin());
}
[Fact]
public static void NoTryGetArrayAfterDispose()
{
- OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
+ IMemoryOwner<int> block = MemoryPool<int>.Shared.Rent(42);
Memory<int> memory = block.Memory;
- block.Release();
+ ((MemoryManager<int>)block).Unpin();
block.Dispose();
Assert.Throws<ObjectDisposedException>(() => MemoryMarshal.TryGetArray(memory, out ArraySegment<int> arraySegment));
}
-
- [Fact]
- public static void IsRetainedWhenReturned()
- {
- OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
- Assert.False(block.Release());
- }
-
- [Fact]
- public static void IsDisposedWhenReleased()
- {
- OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
- block.Release();
-
- Assert.True(block.IsDisposed);
- }
}
}
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs
index d8734b34ec..fc5c05dac1 100644
--- a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs
@@ -13,7 +13,6 @@ namespace System.Memory.Tests
{
public static ReadOnlySequenceFactoryByte ArrayFactory { get; } = new ArrayTestSequenceFactoryByte();
public static ReadOnlySequenceFactoryByte MemoryFactory { get; } = new MemoryTestSequenceFactoryByte();
- public static ReadOnlySequenceFactoryByte OwnedMemoryFactory { get; } = new OwnedMemoryTestSequenceFactoryByte();
public static ReadOnlySequenceFactoryByte SingleSegmentFactory { get; } = new SingleSegmentTestSequenceFactoryByte();
public static ReadOnlySequenceFactoryByte SegmentPerByteFactory { get; } = new BytePerSegmentTestSequenceFactoryByte();
@@ -55,21 +54,6 @@ namespace System.Memory.Tests
}
}
- internal class OwnedMemoryTestSequenceFactoryByte : ReadOnlySequenceFactoryByte
- {
- public override ReadOnlySequence<byte> CreateOfSize(int size)
- {
- return CreateWithContent(new byte[size]);
- }
-
- public override ReadOnlySequence<byte> CreateWithContent(byte[] data)
- {
- var startSegment = new byte[data.Length + 20];
- Array.Copy(data, 0, startSegment, 10, data.Length);
- return new ReadOnlySequence<byte>(new CustomMemoryForTest<byte>(startSegment, 10, data.Length));
- }
- }
-
internal class SingleSegmentTestSequenceFactoryByte : ReadOnlySequenceFactoryByte
{
public override ReadOnlySequence<byte> CreateOfSize(int size)
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs
index 273f5670bb..e23f1e43d2 100644
--- a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs
@@ -15,7 +15,6 @@ namespace System.Memory.Tests
public static ReadOnlySequenceFactoryChar ArrayFactory { get; } = new ArrayTestSequenceFactoryChar();
public static ReadOnlySequenceFactoryChar MemoryFactory { get; } = new MemoryTestSequenceFactoryChar();
public static ReadOnlySequenceFactoryChar StringFactory { get; } = new StringTestSequenceFactoryChar();
- public static ReadOnlySequenceFactoryChar OwnedMemoryFactory { get; } = new OwnedMemoryTestSequenceFactoryChar();
public static ReadOnlySequenceFactoryChar SingleSegmentFactory { get; } = new SingleSegmentTestSequenceFactoryChar();
public static ReadOnlySequenceFactoryChar SegmentPerCharFactory { get; } = new CharPerSegmentTestSequenceFactoryChar();
@@ -89,21 +88,6 @@ namespace System.Memory.Tests
}
}
- internal class OwnedMemoryTestSequenceFactoryChar : ReadOnlySequenceFactoryChar
- {
- public override ReadOnlySequence<char> CreateOfSize(int size)
- {
- return CreateWithContent(new char[size]);
- }
-
- public override ReadOnlySequence<char> CreateWithContent(char[] data)
- {
- var startSegment = new char[data.Length + 20];
- Array.Copy(data, 0, startSegment, 10, data.Length);
- return new ReadOnlySequence<char>(new CustomMemoryForTest<char>(startSegment, 10, data.Length));
- }
- }
-
internal class SingleSegmentTestSequenceFactoryChar : ReadOnlySequenceFactoryChar
{
public override ReadOnlySequence<char> CreateOfSize(int size)
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs
index c7971c4a33..6bc16ec8cf 100644
--- a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs
@@ -264,7 +264,7 @@ namespace System.Memory.Tests
}
Assert.Equal(1, sizes.Count);
- Assert.Equal(new [] { 100 }, sizes);
+ Assert.Equal(new[] { 100 }, sizes);
}
[Fact]
@@ -282,7 +282,7 @@ namespace System.Memory.Tests
}
Assert.Equal(2, sizes.Count);
- Assert.Equal(new [] { 100, 0 }, sizes);
+ Assert.Equal(new[] { 100, 0 }, sizes);
}
[Fact]
@@ -300,7 +300,7 @@ namespace System.Memory.Tests
}
Assert.Equal(2, sizes.Count);
- Assert.Equal(new [] { 100, 0 }, sizes);
+ Assert.Equal(new[] { 100, 0 }, sizes);
}
[Fact]
@@ -396,33 +396,6 @@ namespace System.Memory.Tests
}
[Fact]
- public void Ctor_OwnedMemory_Offset()
- {
- var ownedMemory = new CustomMemoryForTest<byte>(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
- var buffer = new ReadOnlySequence<byte>(ownedMemory, 2, 3);
- Assert.Equal(buffer.ToArray(), new byte[] { 3, 4, 5 });
- }
-
- [Fact]
- public void Ctor_OwnedMemory_NoOffset()
- {
- var ownedMemory = new CustomMemoryForTest<byte>(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
- var buffer = new ReadOnlySequence<byte>(ownedMemory);
- Assert.Equal(buffer.ToArray(), new byte[] { 1, 2, 3, 4, 5 });
- }
-
- [Fact]
- public void Ctor_OwnedMemory_ValidatesArguments()
- {
- var ownedMemory = new CustomMemoryForTest<byte>(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
- Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(ownedMemory, 6, 0));
- Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(ownedMemory, 4, 2));
- Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(ownedMemory, -4, 0));
- Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(ownedMemory, 4, -2));
- Assert.Throws<ArgumentNullException>(() => new ReadOnlySequence<byte>((CustomMemoryForTest<byte>)null, 4, 2));
- }
-
- [Fact]
public void Ctor_Memory()
{
var memory = new ReadOnlyMemory<byte>(new byte[] { 1, 2, 3, 4, 5 });
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.TryGet.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.TryGet.cs
index b99a4f0fe6..9bde78b0ee 100644
--- a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.TryGet.cs
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.TryGet.cs
@@ -21,7 +21,7 @@ namespace System.Memory.Tests
Assert.Equal(3, array.Count);
Assert.False(SequenceMarshal.TryGetReadOnlySequenceSegment(buffer, out _, out _, out _, out _));
- Assert.False(SequenceMarshal.TryGetOwnedMemory(buffer, out _, out _, out _));
+ Assert.False(SequenceMarshal.TryGetMemoryManager(buffer, out _, out _, out _));
// Array can be retrieved with TryGetReadOnlyMemory
Assert.True(SequenceMarshal.TryGetReadOnlyMemory(buffer, out ReadOnlyMemory<byte> newMemory));
@@ -38,7 +38,7 @@ namespace System.Memory.Tests
Assert.Equal(new byte[] { 3, 4, 5 }, newMemory.ToArray());
Assert.False(SequenceMarshal.TryGetReadOnlySequenceSegment(buffer, out ReadOnlySequenceSegment<byte> startSegment, out int startIndex, out ReadOnlySequenceSegment<byte> endSegment, out int endIndex));
- Assert.False(SequenceMarshal.TryGetOwnedMemory(buffer, out _, out _, out _));
+ Assert.False(SequenceMarshal.TryGetMemoryManager(buffer, out _, out _, out _));
// Memory is internally decomposed to its container so it would be accessible via TryGetArray
Assert.True(SequenceMarshal.TryGetArray(buffer, out ArraySegment<byte> array));
@@ -58,30 +58,11 @@ namespace System.Memory.Tests
Assert.Equal(text.Substring(2, 3).ToCharArray(), newMemory.ToArray());
Assert.False(SequenceMarshal.TryGetReadOnlySequenceSegment(buffer, out ReadOnlySequenceSegment<char> startSegment, out int startIndex, out ReadOnlySequenceSegment<char> endSegment, out int endIndex));
- Assert.False(SequenceMarshal.TryGetOwnedMemory(buffer, out _, out _, out _));
+ Assert.False(SequenceMarshal.TryGetMemoryManager(buffer, out _, out _, out _));
Assert.False(SequenceMarshal.TryGetArray(buffer, out _));
}
[Fact]
- public void Ctor_OwnedMemory_Offset()
- {
- var ownedMemory = new CustomMemoryForTest<byte>(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
- var buffer = new ReadOnlySequence<byte>(ownedMemory, 2, 3);
-
- Assert.True(SequenceMarshal.TryGetOwnedMemory(buffer, out OwnedMemory<byte> newOwnedMemory, out int start, out int length));
- Assert.Equal(ownedMemory, newOwnedMemory);
- Assert.Equal(2, start);
- Assert.Equal(3, length);
-
- Assert.False(SequenceMarshal.TryGetReadOnlySequenceSegment(buffer, out _, out _, out _, out _));
- Assert.False(SequenceMarshal.TryGetArray(buffer, out _));
-
- // OwnedMemory can be retrieved with TryGetReadOnlyMemory
- Assert.True(SequenceMarshal.TryGetReadOnlyMemory(buffer, out ReadOnlyMemory<byte> newMemory));
- Assert.Equal(new byte[] { 3, 4, 5 }, newMemory.ToArray());
- }
-
- [Fact]
public void Ctor_IMemoryList_SingleBlock()
{
var memoryListSegment = new BufferSegment<byte>(new byte[] { 1, 2, 3, 4, 5 });
@@ -96,7 +77,7 @@ namespace System.Memory.Tests
Assert.Equal(5, endIndex);
Assert.False(SequenceMarshal.TryGetArray(buffer, out _));
- Assert.False(SequenceMarshal.TryGetOwnedMemory(buffer, out _, out _, out _));
+ Assert.False(SequenceMarshal.TryGetMemoryManager(buffer, out _, out _, out _));
// Single block can be retrieved with TryGetReadOnlyMemory
Assert.True(SequenceMarshal.TryGetReadOnlyMemory(buffer, out ReadOnlyMemory<byte> newMemory));
@@ -119,7 +100,7 @@ namespace System.Memory.Tests
Assert.Equal(1, endIndex);
Assert.False(SequenceMarshal.TryGetArray(buffer, out _));
- Assert.False(SequenceMarshal.TryGetOwnedMemory(buffer, out _, out _, out _));
+ Assert.False(SequenceMarshal.TryGetMemoryManager(buffer, out _, out _, out _));
// Multi-block can't be retrieved with TryGetReadOnlyMemory
Assert.False(SequenceMarshal.TryGetReadOnlyMemory(buffer, out _));
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs
index 3e49ca7ac6..42a48d8e9c 100644
--- a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs
@@ -16,11 +16,6 @@ namespace System.Memory.Tests
public Array() : base(ReadOnlySequenceFactoryByte.ArrayFactory) { }
}
- public class OwnedMemory : ReadOnlySequenceTestsByte
- {
- public OwnedMemory() : base(ReadOnlySequenceFactoryByte.OwnedMemoryFactory) { }
- }
-
public class Memory : ReadOnlySequenceTestsByte
{
public Memory() : base(ReadOnlySequenceFactoryByte.MemoryFactory) { }
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.char.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.char.cs
index 53a2f1a1a4..9b025fbbe8 100644
--- a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.char.cs
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.char.cs
@@ -21,11 +21,6 @@ namespace System.Memory.Tests
public String() : base(ReadOnlySequenceFactoryChar.StringFactory) { }
}
- public class OwnedMemory : ReadOnlySequenceTestsChar
- {
- public OwnedMemory() : base(ReadOnlySequenceFactoryChar.OwnedMemoryFactory) { }
- }
-
public class Memory : ReadOnlySequenceTestsChar
{
public Memory() : base(ReadOnlySequenceFactoryChar.MemoryFactory) { }
diff --git a/src/System.Memory/tests/ReadOnlyMemory/Pin.cs b/src/System.Memory/tests/ReadOnlyMemory/Pin.cs
index 803612035c..0fb69de3e5 100644
--- a/src/System.Memory/tests/ReadOnlyMemory/Pin.cs
+++ b/src/System.Memory/tests/ReadOnlyMemory/Pin.cs
@@ -15,10 +15,10 @@ namespace System.MemoryTests
int[] array = { 1, 2, 3, 4, 5 };
ReadOnlyMemory<int> memory = array;
MemoryHandle handle = memory.Pin();
- Assert.True(handle.HasPointer);
unsafe
{
int* pointer = (int*)handle.Pointer;
+ Assert.True(pointer != null);
GC.Collect();
@@ -35,7 +35,10 @@ namespace System.MemoryTests
{
ReadOnlyMemory<int> memory = new int[0];
MemoryHandle handle = memory.Pin();
- Assert.True(handle.HasPointer);
+ unsafe
+ {
+ Assert.True(handle.Pointer != null);
+ }
handle.Dispose();
}
@@ -44,7 +47,6 @@ namespace System.MemoryTests
{
ReadOnlyMemory<int> memory = default;
MemoryHandle handle = memory.Pin();
- Assert.False(handle.HasPointer);
unsafe
{
Assert.True(handle.Pointer == null);
@@ -60,10 +62,10 @@ namespace System.MemoryTests
memory = memory.Slice(1);
MemoryHandle handle = memory.Pin();
ReadOnlySpan<int> span = memory.Span;
- Assert.True(handle.HasPointer);
unsafe
{
int* pointer = (int*)handle.Pointer;
+ Assert.True(pointer != null);
GC.Collect();
@@ -81,16 +83,16 @@ namespace System.MemoryTests
}
[Fact]
- public static void OwnedMemoryPin()
+ public static void MemoryManagerPin()
{
int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- ReadOnlyMemory<int> memory = owner.Memory;
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = manager.Memory;
MemoryHandle handle = memory.Pin();
- Assert.True(handle.HasPointer);
unsafe
{
int* pointer = (int*)handle.Pointer;
+ Assert.True(pointer != null);
GC.Collect();
@@ -103,17 +105,17 @@ namespace System.MemoryTests
}
[Fact]
- public static void OwnedMemoryPinAndSlice()
+ public static void MemoryManagerPinAndSlice()
{
int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- ReadOnlyMemory<int> memory = owner.Memory.Slice(1);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = manager.Memory.Slice(1);
MemoryHandle handle = memory.Pin();
ReadOnlySpan<int> span = memory.Span;
- Assert.True(handle.HasPointer);
unsafe
{
int* pointer = (int*)handle.Pointer;
+ Assert.True(pointer != null);
GC.Collect();
diff --git a/src/System.Memory/tests/ReadOnlyMemory/Retain.cs b/src/System.Memory/tests/ReadOnlyMemory/Retain.cs
deleted file mode 100644
index d438c78d77..0000000000
--- a/src/System.Memory/tests/ReadOnlyMemory/Retain.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-// 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.Buffers;
-using Xunit;
-
-namespace System.MemoryTests
-{
- public static partial class ReadOnlyMemoryTests
- {
-
- [Fact]
- public static void MemoryRetainWithoutPinning()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- ReadOnlyMemory<int> memory = array;
- MemoryHandle handle = memory.Retain();
- Assert.False(handle.HasPointer);
- unsafe
- {
- Assert.True(handle.Pointer == null);
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void MemoryRetainWithPinning()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- ReadOnlyMemory<int> memory = array;
- MemoryHandle handle = memory.Retain(pin: true);
- Assert.True(handle.HasPointer);
- unsafe
- {
- int* pointer = (int*)handle.Pointer;
-
- GC.Collect();
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i], pointer[i]);
- }
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void MemoryFromEmptyArrayRetainWithPinning()
- {
- ReadOnlyMemory<int> memory = new int[0];
- MemoryHandle handle = memory.Retain(pin: true);
- Assert.True(handle.HasPointer);
- handle.Dispose();
- }
-
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public static void DefaultMemoryRetain(bool pin)
- {
- ReadOnlyMemory<int> memory = default;
- MemoryHandle handle = memory.Retain(pin: pin);
- Assert.False(handle.HasPointer);
- unsafe
- {
- Assert.True(handle.Pointer == null);
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void MemoryRetainWithPinningAndSlice()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- ReadOnlyMemory<int> memory = array;
- memory = memory.Slice(1);
- MemoryHandle handle = memory.Retain(pin: true);
- ReadOnlySpan<int> span = memory.Span;
- Assert.True(handle.HasPointer);
- unsafe
- {
- int* pointer = (int*)handle.Pointer;
-
- GC.Collect();
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i + 1], pointer[i]);
- }
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i + 1], span[i]);
- }
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void OwnedMemoryRetainWithoutPinning()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- ReadOnlyMemory<int> memory = owner.Memory;
- MemoryHandle handle = memory.Retain();
- Assert.False(handle.HasPointer);
- unsafe
- {
- Assert.True(handle.Pointer == null);
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void OwnedMemoryRetainWithPinning()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- ReadOnlyMemory<int> memory = owner.Memory;
- MemoryHandle handle = memory.Retain(pin: true);
- Assert.True(handle.HasPointer);
- unsafe
- {
- int* pointer = (int*)handle.Pointer;
-
- GC.Collect();
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i], pointer[i]);
- }
- }
- handle.Dispose();
- }
-
- [Fact]
- public static void OwnedMemoryRetainWithPinningAndSlice()
- {
- int[] array = { 1, 2, 3, 4, 5 };
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- ReadOnlyMemory<int> memory = owner.Memory.Slice(1);
- MemoryHandle handle = memory.Retain(pin: true);
- ReadOnlySpan<int> span = memory.Span;
- Assert.True(handle.HasPointer);
- unsafe
- {
- int* pointer = (int*)handle.Pointer;
-
- GC.Collect();
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i + 1], pointer[i]);
- }
-
- for (int i = 0; i < memory.Length; i++)
- {
- Assert.Equal(array[i + 1], span[i]);
- }
- }
- handle.Dispose();
- }
- }
-}
diff --git a/src/System.Memory/tests/ReadOnlyMemory/Slice.cs b/src/System.Memory/tests/ReadOnlyMemory/Slice.cs
index 70404ecca4..dbeb91d62e 100644
--- a/src/System.Memory/tests/ReadOnlyMemory/Slice.cs
+++ b/src/System.Memory/tests/ReadOnlyMemory/Slice.cs
@@ -19,11 +19,11 @@ namespace System.MemoryTests
Assert.Equal(4, memory.Length);
Assert.True(Unsafe.AreSame(ref a[6], ref Unsafe.AsRef(in MemoryMarshal.GetReference(memory.Span))));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- ReadOnlyMemory<int> memoryFromOwner = ((ReadOnlyMemory<int>)owner.Memory).Slice(6);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ ReadOnlyMemory<int> memoryFromManager = ((ReadOnlyMemory<int>)manager.Memory).Slice(6);
- Assert.Equal(4, memoryFromOwner.Length);
- Assert.True(Unsafe.AreSame(ref a[6], ref Unsafe.AsRef(in MemoryMarshal.GetReference(memoryFromOwner.Span))));
+ Assert.Equal(4, memoryFromManager.Length);
+ Assert.True(Unsafe.AreSame(ref a[6], ref Unsafe.AsRef(in MemoryMarshal.GetReference(memoryFromManager.Span))));
}
[Fact]
@@ -34,11 +34,11 @@ namespace System.MemoryTests
Assert.Equal(0, memory.Length);
Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref Unsafe.AsRef(in MemoryMarshal.GetReference(memory.Span)), 1)));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- ReadOnlyMemory<int> memoryFromOwner = ((ReadOnlyMemory<int>)owner.Memory).Slice(a.Length);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ ReadOnlyMemory<int> memoryFromManager = ((ReadOnlyMemory<int>)manager.Memory).Slice(a.Length);
- Assert.Equal(0, memoryFromOwner.Length);
- Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref Unsafe.AsRef(in MemoryMarshal.GetReference(memoryFromOwner.Span)), 1)));
+ Assert.Equal(0, memoryFromManager.Length);
+ Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref Unsafe.AsRef(in MemoryMarshal.GetReference(memoryFromManager.Span)), 1)));
}
[Fact]
@@ -49,11 +49,11 @@ namespace System.MemoryTests
Assert.Equal(5, memory.Length);
Assert.True(Unsafe.AreSame(ref a[3], ref Unsafe.AsRef(in MemoryMarshal.GetReference(memory.Span))));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- ReadOnlyMemory<int> memoryFromOwner = ((ReadOnlyMemory<int>)owner.Memory).Slice(3, 5);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ ReadOnlyMemory<int> memoryFromManager = ((ReadOnlyMemory<int>)manager.Memory).Slice(3, 5);
- Assert.Equal(5, memoryFromOwner.Length);
- Assert.True(Unsafe.AreSame(ref a[3], ref Unsafe.AsRef(in MemoryMarshal.GetReference(memoryFromOwner.Span))));
+ Assert.Equal(5, memoryFromManager.Length);
+ Assert.True(Unsafe.AreSame(ref a[3], ref Unsafe.AsRef(in MemoryMarshal.GetReference(memoryFromManager.Span))));
}
[Fact]
@@ -64,11 +64,11 @@ namespace System.MemoryTests
Assert.Equal(6, memory.Length);
Assert.True(Unsafe.AreSame(ref a[4], ref Unsafe.AsRef(in MemoryMarshal.GetReference(memory.Span))));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- ReadOnlyMemory<int> memoryFromOwner = ((ReadOnlyMemory<int>)owner.Memory).Slice(4, 6);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ ReadOnlyMemory<int> memoryFromManager = ((ReadOnlyMemory<int>)manager.Memory).Slice(4, 6);
- Assert.Equal(6, memoryFromOwner.Length);
- Assert.True(Unsafe.AreSame(ref a[4], ref Unsafe.AsRef(in MemoryMarshal.GetReference(memoryFromOwner.Span))));
+ Assert.Equal(6, memoryFromManager.Length);
+ Assert.True(Unsafe.AreSame(ref a[4], ref Unsafe.AsRef(in MemoryMarshal.GetReference(memoryFromManager.Span))));
}
[Fact]
@@ -79,11 +79,11 @@ namespace System.MemoryTests
Assert.Equal(0, memory.Length);
Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref Unsafe.AsRef(in MemoryMarshal.GetReference(memory.Span)), 1)));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- ReadOnlyMemory<int> memoryFromOwner = ((ReadOnlyMemory<int>)owner.Memory).Slice(a.Length, 0);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ ReadOnlyMemory<int> memoryFromManager = ((ReadOnlyMemory<int>)manager.Memory).Slice(a.Length, 0);
- Assert.Equal(0, memoryFromOwner.Length);
- Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref Unsafe.AsRef(in MemoryMarshal.GetReference(memoryFromOwner.Span)), 1)));
+ Assert.Equal(0, memoryFromManager.Length);
+ Assert.True(Unsafe.AreSame(ref a[a.Length - 1], ref Unsafe.Subtract(ref Unsafe.AsRef(in MemoryMarshal.GetReference(memoryFromManager.Span)), 1)));
}
[Fact]
@@ -98,8 +98,8 @@ namespace System.MemoryTests
Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlyMemory<int>(a).Slice(a.Length + 1, 0));
Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlyMemory<int>(a).Slice(a.Length, 1));
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- ReadOnlyMemory<int> memory = owner.Memory;
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ ReadOnlyMemory<int> memory = manager.Memory;
Assert.Throws<ArgumentOutOfRangeException>(() => memory.Slice(-1));
Assert.Throws<ArgumentOutOfRangeException>(() => memory.Slice(a.Length + 1));
diff --git a/src/System.Memory/tests/ReadOnlyMemory/Span.cs b/src/System.Memory/tests/ReadOnlyMemory/Span.cs
index 65029dc03b..781d3f5a55 100644
--- a/src/System.Memory/tests/ReadOnlyMemory/Span.cs
+++ b/src/System.Memory/tests/ReadOnlyMemory/Span.cs
@@ -21,8 +21,8 @@ namespace System.MemoryTests
memory = new ReadOnlyMemory<int>(a, 0, a.Length);
memory.Span.Validate(91, 92, -93, 94);
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(a);
- ((ReadOnlyMemory<int>)owner.Memory).Span.Validate(91, 92, -93, 94);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(a);
+ ((ReadOnlyMemory<int>)manager.Memory).Span.Validate(91, 92, -93, 94);
}
[Fact]
@@ -37,8 +37,8 @@ namespace System.MemoryTests
memory = new ReadOnlyMemory<long>(a, 0, a.Length);
memory.Span.Validate(91, -92, 93, 94, -95);
- OwnedMemory<long> owner = new CustomMemoryForTest<long>(a);
- ((ReadOnlyMemory<long>)owner.Memory).Span.Validate(91, -92, 93, 94, -95);
+ MemoryManager<long> manager = new CustomMemoryForTest<long>(a);
+ ((ReadOnlyMemory<long>)manager.Memory).Span.Validate(91, -92, 93, 94, -95);
}
[Fact]
@@ -55,8 +55,8 @@ namespace System.MemoryTests
memory = new ReadOnlyMemory<object>(a, 0, a.Length);
memory.Span.ValidateReferenceType(o1, o2);
- OwnedMemory<object> owner = new CustomMemoryForTest<object>(a);
- ((ReadOnlyMemory<object>)owner.Memory).Span.ValidateReferenceType(o1, o2);
+ MemoryManager<object> manager = new CustomMemoryForTest<object>(a);
+ ((ReadOnlyMemory<object>)manager.Memory).Span.ValidateReferenceType(o1, o2);
}
[Fact]
@@ -71,8 +71,8 @@ namespace System.MemoryTests
memory = new ReadOnlyMemory<int>(empty, 0, empty.Length);
memory.Span.ValidateNonNullEmpty();
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(empty);
- ((ReadOnlyMemory<int>)owner.Memory).Span.Validate();
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(empty);
+ ((ReadOnlyMemory<int>)manager.Memory).Span.Validate();
}
[Fact]
@@ -90,8 +90,8 @@ namespace System.MemoryTests
memory = new ReadOnlyMemory<int>(aAsIntArray, 0, aAsIntArray.Length);
memory.Span.Validate(42, -1);
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(aAsIntArray);
- ((ReadOnlyMemory<int>)owner.Memory).Span.Validate(42, -1);
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(aAsIntArray);
+ ((ReadOnlyMemory<int>)manager.Memory).Span.Validate(42, -1);
}
[Fact]
diff --git a/src/System.Memory/tests/ReadOnlyMemory/ToString.cs b/src/System.Memory/tests/ReadOnlyMemory/ToString.cs
index 8781c53942..4ce511a219 100644
--- a/src/System.Memory/tests/ReadOnlyMemory/ToString.cs
+++ b/src/System.Memory/tests/ReadOnlyMemory/ToString.cs
@@ -68,28 +68,28 @@ namespace System.MemoryTests
}
[Fact]
- public static void ToStringFromMemoryFromOwnedMemory()
+ public static void ToStringFromMemoryFromMemoryManager()
{
int[] a = { 91, 92, -93, 94 };
- OwnedMemory<int> intOwner = new CustomMemoryForTest<int>(a);
- Assert.Equal("System.ReadOnlyMemory<Int32>[4]", ((ReadOnlyMemory<int>)intOwner.Memory).ToString());
+ MemoryManager<int> intManager = new CustomMemoryForTest<int>(a);
+ Assert.Equal("System.ReadOnlyMemory<Int32>[4]", ((ReadOnlyMemory<int>)intManager.Memory).ToString());
- intOwner = new CustomMemoryForTest<int>(Array.Empty<int>());
- Assert.Equal("System.ReadOnlyMemory<Int32>[0]", ((ReadOnlyMemory<int>)intOwner.Memory).ToString());
+ intManager = new CustomMemoryForTest<int>(Array.Empty<int>());
+ Assert.Equal("System.ReadOnlyMemory<Int32>[0]", ((ReadOnlyMemory<int>)intManager.Memory).ToString());
char[] charArray = { '1', '2', '-', '4' };
- OwnedMemory<char> charOwner = new CustomMemoryForTest<char>(charArray);
- Assert.Equal("12-4", ((ReadOnlyMemory<char>)charOwner.Memory).ToString());
+ MemoryManager<char> charManager = new CustomMemoryForTest<char>(charArray);
+ Assert.Equal("12-4", ((ReadOnlyMemory<char>)charManager.Memory).ToString());
- charOwner = new CustomMemoryForTest<char>(Array.Empty<char>());
- Assert.Equal("", ((ReadOnlyMemory<char>)charOwner.Memory).ToString());
+ charManager = new CustomMemoryForTest<char>(Array.Empty<char>());
+ Assert.Equal("", ((ReadOnlyMemory<char>)charManager.Memory).ToString());
string[] strArray = { "91", "92", "-93", "94" };
- OwnedMemory<string> strOwner = new CustomMemoryForTest<string>(strArray);
- Assert.Equal("System.ReadOnlyMemory<String>[4]", ((ReadOnlyMemory<string>)strOwner.Memory).ToString());
+ MemoryManager<string> strManager = new CustomMemoryForTest<string>(strArray);
+ Assert.Equal("System.ReadOnlyMemory<String>[4]", ((ReadOnlyMemory<string>)strManager.Memory).ToString());
- strOwner = new CustomMemoryForTest<string>(Array.Empty<string>());
- Assert.Equal("System.ReadOnlyMemory<String>[0]", ((ReadOnlyMemory<string>)strOwner.Memory).ToString());
+ strManager = new CustomMemoryForTest<string>(Array.Empty<string>());
+ Assert.Equal("System.ReadOnlyMemory<String>[0]", ((ReadOnlyMemory<string>)strManager.Memory).ToString());
}
[Fact]
diff --git a/src/System.Memory/tests/Resources/System.Memory.Tests.rd.xml b/src/System.Memory/tests/Resources/System.Memory.Tests.rd.xml
index 7931c600d4..6dd7780ad6 100644
--- a/src/System.Memory/tests/Resources/System.Memory.Tests.rd.xml
+++ b/src/System.Memory/tests/Resources/System.Memory.Tests.rd.xml
@@ -1,6 +1,6 @@
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library>
- <!-- Needed because OwnedMemory is reflection blocked and xunit tries to reflect on this concrete type during discovery -->
+ <!-- Needed because MemoryManager is reflection blocked and xunit tries to reflect on this concrete type during discovery -->
<Type Name="System.MemoryTests.CustomMemoryForTest{T}" Dynamic="Excluded" Browse="Excluded" Serialize="Excluded" />
</Library>
</Directives> \ No newline at end of file
diff --git a/src/System.Memory/tests/Span/Reflection.cs b/src/System.Memory/tests/Span/Reflection.cs
new file mode 100644
index 0000000000..652e0f161e
--- /dev/null
+++ b/src/System.Memory/tests/Span/Reflection.cs
@@ -0,0 +1,186 @@
+// 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 Xunit;
+using System.Buffers;
+using System.Buffers.Binary;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.MemoryTests;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ // Calling Span APIs via Reflection is not supported yet.
+ // These tests check that using reflection results in graceful failures. See https://github.com/dotnet/coreclr/issues/17296
+ // These tests are only relevant for fast span.
+
+ [Fact]
+ public static void MemoryExtensions_StaticReturningReadOnlySpan()
+ {
+ Type type = typeof(MemoryExtensions);
+
+ MethodInfo method = type.GetMethod(nameof(MemoryExtensions.AsSpan), new Type[] { typeof(string) });
+ Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { "Hello" }));
+
+ method = type.GetMethod(nameof(MemoryExtensions.AsSpan), new Type[] { typeof(string), typeof(int), typeof(int) });
+ Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { "Hello", 1, 1 }));
+ }
+
+ [Fact]
+ public static void MemoryExtensions_StaticWithSpanArguments()
+ {
+ Type type = typeof(MemoryExtensions);
+
+ MethodInfo method = type.GetMethod(nameof(MemoryExtensions.CompareTo));
+
+ int result = (int)method.Invoke(null, new object[] { default, default, StringComparison.Ordinal });
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void BinaryPrimitives_StaticWithSpanArgument()
+ {
+ Type type = typeof(BinaryPrimitives);
+
+ MethodInfo method = type.GetMethod(nameof(BinaryPrimitives.ReadInt16LittleEndian));
+ Assert.Throws<TargetInvocationException>(() => method.Invoke(null, new object[] { default }));
+
+ method = type.GetMethod(nameof(BinaryPrimitives.TryReadInt16LittleEndian));
+ bool result = (bool)method.Invoke(null, new object[] { default, null });
+ Assert.False(result);
+ }
+
+ [Fact]
+ public static void MemoryMarshal_GenericStaticReturningSpan()
+ {
+ Type type = typeof(MemoryMarshal);
+
+ int value = 0;
+ ref int refInt = ref value;
+
+ MethodInfo method = type.GetMethod(nameof(MemoryMarshal.CreateSpan)).MakeGenericMethod((refInt.GetType()));
+ Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { null, 0 }));
+ }
+
+ [Fact]
+ public static void Span_Constructor()
+ {
+ Type type = typeof(Span<int>);
+
+ ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(int[]) });
+ Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { new int[10] }));
+
+ ctor = type.GetConstructor(new Type[] { typeof(int[]), typeof(int), typeof(int) });
+ Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { new int[10], 1, 1 }));
+
+ ctor = type.GetConstructor(new Type[] { typeof(void*), typeof(int) });
+ Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { null, 1 }));
+ }
+
+ [Fact]
+ public static void Span_Property()
+ {
+ Type type = typeof(Span<int>);
+
+ PropertyInfo property = type.GetProperty(nameof(Span<int>.Empty));
+ Assert.Throws<NotSupportedException>(() => property.GetValue(default));
+ }
+
+ [Fact]
+ public static void Span_StaticOperator()
+ {
+ Type type = typeof(Span<int>);
+
+ MethodInfo method = type.GetMethod("op_Equality");
+ Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { default, default }));
+
+ method = type.GetMethod("op_Inequality");
+ Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { default, default }));
+ }
+
+ [Fact]
+ public static void Span_InstanceMethod()
+ {
+ Type type = typeof(Span<int>);
+
+ MethodInfo method = type.GetMethod(nameof(Span<int>.CopyTo), new Type[] { typeof(Span<int>) });
+ Assert.Throws<NotSupportedException>(() => method.Invoke(default, new object[] { default }));
+ }
+
+ [Fact]
+ public static void ReadOnlySpan_Constructor()
+ {
+ Type type = typeof(ReadOnlySpan<int>);
+
+ ConstructorInfo ctor = type.GetConstructor(new Type[] { typeof(int[]) });
+ Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { new int[10] }));
+
+ ctor = type.GetConstructor(new Type[] { typeof(int[]), typeof(int), typeof(int) });
+ Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { new int[10], 1, 1 }));
+
+ ctor = type.GetConstructor(new Type[] { typeof(void*), typeof(int) });
+ Assert.Throws<TargetException>(() => ctor.Invoke(new object[] { null, 1 }));
+ }
+
+ [Fact]
+ public static void ReadOnlySpan_Property()
+ {
+ Type type = typeof(ReadOnlySpan<int>);
+
+ PropertyInfo property = type.GetProperty(nameof(ReadOnlySpan<int>.Empty));
+ Assert.Throws<NotSupportedException>(() => property.GetValue(default));
+ }
+
+ [Fact]
+ public static void ReadOnlySpan_Operator()
+ {
+ Type type = typeof(ReadOnlySpan<int>);
+
+ MethodInfo method = type.GetMethod("op_Equality");
+ Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { default, default }));
+
+ method = type.GetMethod("op_Inequality");
+ Assert.Throws<NotSupportedException>(() => method.Invoke(null, new object[] { default, default }));
+ }
+
+ [Fact]
+ public static void ReadOnlySpan_InstanceMethod()
+ {
+ Type type = typeof(ReadOnlySpan<int>);
+
+ MethodInfo method = type.GetMethod(nameof(ReadOnlySpan<int>.CopyTo), new Type[] { typeof(Span<int>) });
+ Assert.Throws<NotSupportedException>(() => method.Invoke(default, new object[] { default }));
+ }
+
+ [Fact]
+ public static void Memory_PropertyReturningSpan()
+ {
+ Type type = typeof(Memory<int>);
+
+ PropertyInfo property = type.GetProperty(nameof(Memory<int>.Span));
+ Assert.Throws<NotSupportedException>(() => property.GetValue(null));
+ }
+
+ [Fact]
+ public static void ReadOnlyMemory_PropertyReturningReadOnlySpan()
+ {
+ Type type = typeof(ReadOnlyMemory<int>);
+
+ PropertyInfo property = type.GetProperty(nameof(ReadOnlyMemory<int>.Span));
+ Assert.Throws<NotSupportedException>(() => property.GetValue(null));
+ }
+
+ [Fact]
+ public static void MemoryManager_MethodReturningSpan()
+ {
+ Type type = typeof(MemoryManager<int>);
+
+ MemoryManager<int> manager = new CustomMemoryForTest<int>(new int[10]);
+ MethodInfo method = type.GetMethod(nameof(MemoryManager<int>.GetSpan), BindingFlags.Public | BindingFlags.Instance);
+ Assert.Throws<NotSupportedException>(() => method.Invoke(manager, null));
+ }
+ }
+}
diff --git a/src/System.Memory/tests/System.Memory.Tests.csproj b/src/System.Memory/tests/System.Memory.Tests.csproj
index 27d689a92a..19c6e3377b 100644
--- a/src/System.Memory/tests/System.Memory.Tests.csproj
+++ b/src/System.Memory/tests/System.Memory.Tests.csproj
@@ -16,6 +16,7 @@
<!-- Tests specific to the fast span -->
<Compile Include="MemoryMarshal\CreateSpan.cs" />
<Compile Include="MemoryMarshal\CreateReadOnlySpan.cs" />
+ <Compile Include="Span\Reflection.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="AllocationHelper.cs" />
@@ -162,9 +163,8 @@
<Compile Include="Memory\Equality.cs" />
<Compile Include="Memory\GetHashCode.cs" />
<Compile Include="Memory\ImplicitConversion.cs" />
- <Compile Include="Memory\OwnedMemory.cs" />
+ <Compile Include="Memory\MemoryManager.cs" />
<Compile Include="Memory\Pin.cs" />
- <Compile Include="Memory\Retain.cs" />
<Compile Include="Memory\Slice.cs" />
<Compile Include="Memory\Span.cs" />
<Compile Include="Memory\Strings.cs" />
@@ -179,7 +179,7 @@
<Compile Include="MemoryMarshal\CastSpan.cs" />
<Compile Include="MemoryMarshal\GetReference.cs" />
<Compile Include="MemoryMarshal\TryGetArray.cs" />
- <Compile Include="MemoryMarshal\TryGetOwnedMemory.cs" />
+ <Compile Include="MemoryMarshal\TryGetMemoryManager.cs" />
<Compile Include="MemoryMarshal\TryGetString.cs" />
<Compile Include="MemoryMarshal\ToEnumerable.cs" />
</ItemGroup>
@@ -195,7 +195,6 @@
<Compile Include="ReadOnlyMemory\GetHashCode.cs" />
<Compile Include="ReadOnlyMemory\ImplicitConversion.cs" />
<Compile Include="ReadOnlyMemory\Pin.cs" />
- <Compile Include="ReadOnlyMemory\Retain.cs" />
<Compile Include="ReadOnlyMemory\Slice.cs" />
<Compile Include="ReadOnlyMemory\Span.cs" />
<Compile Include="ReadOnlyMemory\Strings.cs" />
@@ -236,8 +235,8 @@
<Compile Include="Base64\Base64TestHelper.cs" />
</ItemGroup>
<ItemGroup>
- <Compile Include="$(CommonTestPath)\System\Buffers\NativeOwnedMemory.cs">
- <Link>Common\System\Buffers\NativeOwnedMemory.cs</Link>
+ <Compile Include="$(CommonTestPath)\System\Buffers\NativeMemoryManager.cs">
+ <Link>Common\System\Buffers\NativeMemoryManager.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\MutableDecimal.cs">
<Link>Common\System\MutableDecimal.cs</Link>
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
index 65ae9c528a..b4e6458718 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
@@ -194,8 +194,6 @@ namespace System.Net.Http
set
{
- SecurityProtocol.ThrowOnNotAllowed(value, allowNone: true);
-
CheckDisposedOrStarted();
_sslProtocols = value;
}
@@ -929,6 +927,18 @@ namespace System.Net.Http
uint optionData = 0;
SslProtocols sslProtocols =
(_sslProtocols == SslProtocols.None) ? SecurityProtocol.DefaultSecurityProtocols : _sslProtocols;
+
+#pragma warning disable 0618 // SSL2/SSL3 are deprecated
+ if ((sslProtocols & SslProtocols.Ssl2) != 0)
+ {
+ optionData |= Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_SSL2;
+ }
+
+ if ((sslProtocols & SslProtocols.Ssl3) != 0)
+ {
+ optionData |= Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_SSL3;
+ }
+#pragma warning restore 0618
if ((sslProtocols & SslProtocols.Tls) != 0)
{
diff --git a/src/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs b/src/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs
index 7b4eb0eb42..bc5d9f1fdf 100644
--- a/src/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs
+++ b/src/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs
@@ -436,15 +436,6 @@ namespace System.Net.Http.WinHttpHandlerUnitTests
}
[Theory]
- [ClassData(typeof(SslProtocolSupport.UnsupportedSslProtocolsTestData))]
- public void SslProtocols_SetUsingUnsupported_Throws(SslProtocols protocol)
- {
- var handler = new WinHttpHandler();
-
- Assert.Throws<NotSupportedException>(() => { handler.SslProtocols = protocol; });
- }
-
- [Theory]
[ClassData(typeof(SslProtocolSupport.SupportedSslProtocolsTestData))]
public void SslProtocols_SetUsingSupported_Success(SslProtocols protocol)
{
@@ -460,33 +451,27 @@ namespace System.Net.Http.WinHttpHandlerUnitTests
handler.SslProtocols = SslProtocols.None;
}
- [Fact]
- public void SslProtocols_SetUsingInvalidEnum_Throws()
- {
- var handler = new WinHttpHandler();
-
- Assert.Throws<NotSupportedException>(() => { handler.SslProtocols = (SslProtocols)4096; });
- }
-
- [Fact]
- public void SslProtocols_SetUsingValidEnums_ExpectedWinHttpHandleSettings()
+ [Theory]
+ [InlineData(
+ SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12,
+ Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
+ Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
+ Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2)]
+#pragma warning disable 0618
+ [InlineData(
+ SslProtocols.Ssl2 | SslProtocols.Ssl3,
+ Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 |
+ Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_SSL3)]
+#pragma warning restore 0618
+ public void SslProtocols_SetUsingValidEnums_ExpectedWinHttpHandleSettings(
+ SslProtocols specified, uint expectedProtocols)
{
var handler = new WinHttpHandler();
SendRequestHelper.Send(
handler,
- delegate
- {
- handler.SslProtocols =
- SslProtocols.Tls |
- SslProtocols.Tls11 |
- SslProtocols.Tls12;
- });
+ delegate { handler.SslProtocols = specified; });
- uint expectedProtocols =
- Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
- Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
- Interop.WinHttp.WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;
Assert.Equal(expectedProtocols, APICallHistory.WinHttpOptionSecureProtocols);
}
diff --git a/src/System.Net.Http/src/System.Net.Http.csproj b/src/System.Net.Http/src/System.Net.Http.csproj
index 8b4f8e05f9..e4790711d9 100644
--- a/src/System.Net.Http/src/System.Net.Http.csproj
+++ b/src/System.Net.Http/src/System.Net.Http.csproj
@@ -152,6 +152,9 @@
<Compile Include="System\Net\Http\SocketsHttpHandler\SocketsHttpHandler.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\RawConnectionStream.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\RedirectHandler.cs" />
+ <Compile Include="$(CommonPath)\System\Collections\Concurrent\ConcurrentQueue_Segment.cs">
+ <Link>Common\System\Collections\Concurrent\ConcurrentQueue_Segment.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Net\NTAuthentication.Common.cs">
<Link>Common\System\Net\NTAuthentication.Common.cs</Link>
</Compile>
diff --git a/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs
index fc6f5b88c7..55e583e137 100644
--- a/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs
@@ -209,16 +209,21 @@ namespace System.Net.Http
return;
}
- // We explicitly disallow choosing SSL2/3. Make sure they were filtered out.
- Debug.Assert((protocols & ~SecurityProtocol.AllowedSecurityProtocols) == 0,
- "Disallowed protocols should have been filtered out.");
-
// libcurl supports options for either enabling all of the TLS1.* protocols or enabling
- // just one of them; it doesn't currently support enabling two of the three, e.g. you can't
+ // just one protocol; it doesn't currently support enabling two of the three, e.g. you can't
// pick TLS1.1 and TLS1.2 but not TLS1.0, but you can select just TLS1.2.
Interop.Http.CurlSslVersion curlSslVersion;
switch (protocols)
{
+#pragma warning disable 0618 // SSL2/3 are deprecated
+ case SslProtocols.Ssl2:
+ curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_SSLv2;
+ break;
+ case SslProtocols.Ssl3:
+ curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_SSLv3;
+ break;
+#pragma warning restore 0618
+
case SslProtocols.Tls:
curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1_0;
break;
diff --git a/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs
index 4b2c02904d..42b83fc6a3 100644
--- a/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs
@@ -101,16 +101,21 @@ namespace System.Net.Http
return;
}
- // We explicitly disallow choosing SSL2/3. Make sure they were filtered out.
- Debug.Assert((protocols & ~SecurityProtocol.AllowedSecurityProtocols) == 0,
- "Disallowed protocols should have been filtered out.");
-
// libcurl supports options for either enabling all of the TLS1.* protocols or enabling
- // just one of them; it doesn't currently support enabling two of the three, e.g. you can't
+ // just one protocol; it doesn't currently support enabling two of the three, e.g. you can't
// pick TLS1.1 and TLS1.2 but not TLS1.0, but you can select just TLS1.2.
Interop.Http.CurlSslVersion curlSslVersion;
switch (protocols)
{
+#pragma warning disable 0618 // SSL2/3 are deprecated
+ case SslProtocols.Ssl2:
+ curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_SSLv2;
+ break;
+ case SslProtocols.Ssl3:
+ curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_SSLv3;
+ break;
+#pragma warning restore 0618
+
case SslProtocols.Tls:
curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1_0;
break;
diff --git a/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs
index a63fe3991d..ba51560b68 100644
--- a/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs
@@ -308,7 +308,6 @@ namespace System.Net.Http
get { return _sslProtocols; }
set
{
- SecurityProtocol.ThrowOnNotAllowed(value, allowNone: true);
CheckDisposedOrStarted();
_sslProtocols = value;
}
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs
index de34df54c6..05477b2372 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs
@@ -198,7 +198,6 @@ namespace System.Net.Http
}
else
{
- SecurityProtocol.ThrowOnNotAllowed(value, allowNone: true);
ThrowForModifiedManagedSslOptionsIfStarted();
_socketsHttpHandler.SslOptions.EnabledSslProtocols = value;
}
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs
index 1c0251c404..5ce147043f 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs
@@ -427,7 +427,6 @@ namespace System.Net.Http
}
else
{
- SecurityProtocol.ThrowOnNotAllowed(value, allowNone: true);
ThrowForModifiedManagedSslOptionsIfStarted();
_socketsHttpHandler.SslOptions.EnabledSslProtocols = value;
}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs
index 22e2610f45..1c0e5d734d 100644
--- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs
@@ -62,6 +62,11 @@ namespace System.Net.Http
while (true)
{
string challengeResponse = authContext.GetOutgoingBlob(challengeData);
+ if (challengeResponse == null)
+ {
+ // Response indicated denial even after login, so stop processing and return current response.
+ break;
+ }
await connection.DrainResponseAsync(response).ConfigureAwait(false);
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs
index c2df52fdb3..a64cc7c112 100644
--- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs
@@ -2,6 +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.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Net.Security;
@@ -15,6 +16,11 @@ namespace System.Net.Http
{
internal static class ConnectHelper
{
+ /// <summary>Pool of event args to use to establish connections.</summary>
+ private static readonly ConcurrentQueue<ConnectEventArgs>.Segment s_connectEventArgs =
+ new ConcurrentQueue<ConnectEventArgs>.Segment(
+ ConcurrentQueue<ConnectEventArgs>.Segment.RoundUpToPowerOf2(Environment.ProcessorCount));
+
/// <summary>
/// Helper type used by HttpClientHandler when wrapping SocketsHttpHandler to map its
/// certificate validation callback to the one used by SslStream.
@@ -34,64 +40,46 @@ namespace System.Net.Http
public static async ValueTask<(Socket, Stream)> ConnectAsync(string host, int port, CancellationToken cancellationToken)
{
+ // Rather than creating a new Socket and calling ConnectAsync on it, we use the static
+ // Socket.ConnectAsync with a SocketAsyncEventArgs, as we can then use Socket.CancelConnectAsync
+ // to cancel it if needed. Rent or allocate one.
+ ConnectEventArgs saea;
+ if (!s_connectEventArgs.TryDequeue(out saea))
+ {
+ saea = new ConnectEventArgs();
+ }
+
try
{
- // Rather than creating a new Socket and calling ConnectAsync on it, we use the static
- // Socket.ConnectAsync with a SocketAsyncEventArgs, as we can then use Socket.CancelConnectAsync
- // to cancel it if needed.
- using (var saea = new BuilderAndCancellationTokenSocketAsyncEventArgs(cancellationToken))
- {
- // Configure which server to which to connect.
- saea.RemoteEndPoint = IPAddress.TryParse(host, out IPAddress address) ?
- (EndPoint)new IPEndPoint(address, port) :
- new DnsEndPoint(host, port);
+ saea.Initialize(cancellationToken);
- // Hook up a callback that'll complete the Task when the operation completes.
- saea.Completed += (s, e) =>
- {
- var csaea = (BuilderAndCancellationTokenSocketAsyncEventArgs)e;
- switch (e.SocketError)
- {
- case SocketError.Success:
- csaea.Builder.SetResult();
- break;
- case SocketError.OperationAborted:
- case SocketError.ConnectionAborted:
- if (csaea.CancellationToken.IsCancellationRequested)
- {
- csaea.Builder.SetException(CancellationHelper.CreateOperationCanceledException(null, csaea.CancellationToken));
- break;
- }
- goto default;
- default:
- csaea.Builder.SetException(new SocketException((int)e.SocketError));
- break;
- }
- };
+ // Configure which server to which to connect.
+ saea.RemoteEndPoint = IPAddress.TryParse(host, out IPAddress address) ?
+ (EndPoint)new IPEndPoint(address, port) :
+ new DnsEndPoint(host, port);
- // Initiate the connection.
- if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, saea))
- {
- // Connect completing asynchronously. Enable it to be canceled and wait for it.
- using (cancellationToken.Register(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s), saea))
- {
- await saea.Builder.Task.ConfigureAwait(false);
- }
- }
- else if (saea.SocketError != SocketError.Success)
+ // Initiate the connection.
+ if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, saea))
+ {
+ // Connect completing asynchronously. Enable it to be canceled and wait for it.
+ using (cancellationToken.Register(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s), saea))
{
- // Connect completed synchronously but unsuccessfully.
- throw new SocketException((int)saea.SocketError);
+ await saea.Builder.Task.ConfigureAwait(false);
}
-
- Debug.Assert(saea.SocketError == SocketError.Success, $"Expected Success, got {saea.SocketError}.");
- Debug.Assert(saea.ConnectSocket != null, "Expected non-null socket");
-
- // Configure the socket and return a stream for it.
- Socket socket = saea.ConnectSocket;
- socket.NoDelay = true;
- return (socket, new NetworkStream(socket, ownsSocket: true));
}
+ else if (saea.SocketError != SocketError.Success)
+ {
+ // Connect completed synchronously but unsuccessfully.
+ throw new SocketException((int)saea.SocketError);
+ }
+
+ Debug.Assert(saea.SocketError == SocketError.Success, $"Expected Success, got {saea.SocketError}.");
+ Debug.Assert(saea.ConnectSocket != null, "Expected non-null socket");
+
+ // Configure the socket and return a stream for it.
+ Socket socket = saea.ConnectSocket;
+ socket.NoDelay = true;
+ return (socket, new NetworkStream(socket, ownsSocket: true));
}
catch (Exception error)
{
@@ -99,21 +87,54 @@ namespace System.Net.Http
CancellationHelper.CreateOperationCanceledException(error, cancellationToken) :
new HttpRequestException(error.Message, error);
}
+ finally
+ {
+ // Pool the event args, or if the pool is full, dispose of it.
+ saea.Clear();
+ if (!s_connectEventArgs.TryEnqueue(saea))
+ {
+ saea.Dispose();
+ }
+ }
}
/// <summary>SocketAsyncEventArgs that carries with it additional state for a Task builder and a CancellationToken.</summary>
- private sealed class BuilderAndCancellationTokenSocketAsyncEventArgs : SocketAsyncEventArgs
+ private sealed class ConnectEventArgs : SocketAsyncEventArgs
{
- public AsyncTaskMethodBuilder Builder { get; }
- public CancellationToken CancellationToken { get; }
+ public AsyncTaskMethodBuilder Builder { get; private set; }
+ public CancellationToken CancellationToken { get; private set; }
- public BuilderAndCancellationTokenSocketAsyncEventArgs(CancellationToken cancellationToken)
+ public void Initialize(CancellationToken cancellationToken)
{
+ CancellationToken = cancellationToken;
var b = new AsyncTaskMethodBuilder();
var ignored = b.Task; // force initialization
Builder = b;
+ }
- CancellationToken = cancellationToken;
+ public void Clear() => CancellationToken = default;
+
+ protected override void OnCompleted(SocketAsyncEventArgs _)
+ {
+ switch (SocketError)
+ {
+ case SocketError.Success:
+ Builder.SetResult();
+ break;
+
+ case SocketError.OperationAborted:
+ case SocketError.ConnectionAborted:
+ if (CancellationToken.IsCancellationRequested)
+ {
+ Builder.SetException(CancellationHelper.CreateOperationCanceledException(null, CancellationToken));
+ break;
+ }
+ goto default;
+
+ default:
+ Builder.SetException(new SocketException((int)SocketError));
+ break;
+ }
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs
index 93e2b2f4a5..8a590a4777 100644
--- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs
@@ -55,6 +55,7 @@ namespace System.Net.Http
private int _allowedReadLineBytes;
private ValueTask<int>? _readAheadTask;
+ private int _readAheadTaskLock = 0; // 0 == free, 1 == held
private byte[] _readBuffer;
private int _readOffset;
private int _readLength;
@@ -121,33 +122,42 @@ namespace System.Net.Http
// Eat any exceptions from the read-ahead task. We don't need to log, as we expect
// failures from this task due to closing the connection while a read is in progress.
- if (_readAheadTask != null)
+ ValueTask<int>? readAheadTask = ConsumeReadAheadTask();
+ if (readAheadTask != null)
{
- ValueTask<int> t = _readAheadTask.GetValueOrDefault();
- if (t.IsCompleted)
- {
- if (!t.IsCompletedSuccessfully)
- {
- Exception ignored = t.AsTask().Exception; // accessing Exception prop is sufficient to suppress unobserved exception events
- }
- }
- else
- {
- t.AsTask().ContinueWith(p =>
- {
- Exception ignored = p.Exception;
- }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
- }
+ IgnoreExceptionsAsync(readAheadTask.GetValueOrDefault());
}
}
}
}
+ /// <summary>Awaits a task, ignoring any resulting exceptions.</summary>
+ private static async void IgnoreExceptionsAsync(ValueTask<int> task)
+ {
+ try { await task.ConfigureAwait(false); } catch { }
+ }
+
/// <summary>Do a non-blocking poll to see whether the connection has data available or has been closed.</summary>
/// <remarks>If we don't have direct access to the underlying socket, we instead use a read-ahead task.</remarks>
- public bool PollRead() => _socket != null ?
- _socket.Poll(0, SelectMode.SelectRead) :
- EnsureReadAheadAndPollRead();
+ public bool PollRead()
+ {
+ if (_socket != null) // may be null if we don't have direct access to the socket
+ {
+ try
+ {
+ return _socket.Poll(0, SelectMode.SelectRead);
+ }
+ catch (Exception e) when (e is SocketException || e is ObjectDisposedException)
+ {
+ // Poll can throw when used on a closed socket.
+ return true;
+ }
+ }
+ else
+ {
+ return EnsureReadAheadAndPollRead();
+ }
+ }
/// <summary>
/// Issues a read-ahead on the connection, which will serve both as the first read on the
@@ -175,6 +185,21 @@ namespace System.Net.Http
return _readAheadTask.Value.IsCompleted; // equivalent to polling
}
+ private ValueTask<int>? ConsumeReadAheadTask()
+ {
+ if (Interlocked.CompareExchange(ref _readAheadTaskLock, 1, 0) == 0)
+ {
+ ValueTask<int>? t = _readAheadTask;
+ _readAheadTask = null;
+ Volatile.Write(ref _readAheadTaskLock, 0);
+ return t;
+ }
+
+ // We couldn't get the lock, which means it must already be held
+ // by someone else who will consume the task.
+ return null;
+ }
+
public bool IsNewConnection
{
get
@@ -438,16 +463,11 @@ namespace System.Net.Http
// by the previous request handling. (Note we do not support HTTP pipelining.)
Debug.Assert(_readOffset == _readLength);
- // When the connection was put back into the pool, a pre-emptive read was performed
- // into the read buffer. That read should not complete prior to us using the
- // connection again, as that would mean the connection was either closed or had
- // erroneous data sent on it by the server in response to no request from us.
- // We need to consume that read prior to issuing another read request.
- ValueTask<int>? t = _readAheadTask;
+ // When the connection was taken out of the pool, a pre-emptive read was performed
+ // into the read buffer. We need to consume that read prior to issuing another read.
+ ValueTask<int>? t = ConsumeReadAheadTask();
if (t != null)
{
- _readAheadTask = null;
-
int bytesRead = await t.GetValueOrDefault().ConfigureAwait(false);
if (NetEventSource.IsEnabled) Trace($"Received {bytesRead} bytes.");
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs
index 1c624fcbc4..65e2bf405a 100644
--- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs
@@ -608,8 +608,9 @@ namespace System.Net.Http
// If the pool has been disposed of, dispose the connection being returned,
// as the pool is being deactivated. We do this after the above in order to
// use pooled connections to satisfy any requests that pended before the
- // the pool was disposed of.
- if (_disposed)
+ // the pool was disposed of. We also dispose of connections if connection
+ // timeouts are such that the connection would immediately expire, anyway.
+ if (_disposed || _poolManager.AvoidStoringConnections)
{
if (NetEventSource.IsEnabled) connection.Trace("Disposing connection returned to disposed pool.");
connection.Dispose();
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs
index b4b80898f1..df1f4f50ad 100644
--- a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs
@@ -5,7 +5,6 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
@@ -62,17 +61,41 @@ namespace System.Net.Http
// Start out with the timer not running, since we have no pools.
// When it does run, run it with a frequency based on the idle timeout.
- if (settings._pooledConnectionIdleTimeout == Timeout.InfiniteTimeSpan)
+ if (!AvoidStoringConnections)
{
- const int DefaultScavengeSeconds = 30;
- _cleanPoolTimeout = TimeSpan.FromSeconds(DefaultScavengeSeconds);
- }
- else
- {
- const int ScavengesPerIdle = 4;
- const int MinScavengeSeconds = 1;
- TimeSpan timerPeriod = settings._pooledConnectionIdleTimeout / ScavengesPerIdle;
- _cleanPoolTimeout = timerPeriod.TotalSeconds >= MinScavengeSeconds ? timerPeriod : TimeSpan.FromSeconds(MinScavengeSeconds);
+ if (settings._pooledConnectionIdleTimeout == Timeout.InfiniteTimeSpan)
+ {
+ const int DefaultScavengeSeconds = 30;
+ _cleanPoolTimeout = TimeSpan.FromSeconds(DefaultScavengeSeconds);
+ }
+ else
+ {
+ const int ScavengesPerIdle = 4;
+ const int MinScavengeSeconds = 1;
+ TimeSpan timerPeriod = settings._pooledConnectionIdleTimeout / ScavengesPerIdle;
+ _cleanPoolTimeout = timerPeriod.TotalSeconds >= MinScavengeSeconds ? timerPeriod : TimeSpan.FromSeconds(MinScavengeSeconds);
+ }
+
+ bool restoreFlow = false;
+ try
+ {
+ // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
+ if (!ExecutionContext.IsFlowSuppressed())
+ {
+ ExecutionContext.SuppressFlow();
+ restoreFlow = true;
+ }
+
+ _cleaningTimer = new Timer(s => ((HttpConnectionPoolManager)s).RemoveStalePools(), this, Timeout.Infinite, Timeout.Infinite);
+ }
+ finally
+ {
+ // Restore the current ExecutionContext
+ if (restoreFlow)
+ {
+ ExecutionContext.RestoreFlow();
+ }
+ }
}
// Figure out proxy stuff.
@@ -84,29 +107,13 @@ namespace System.Net.Http
_proxyCredentials = _proxy.Credentials ?? settings._defaultProxyCredentials;
}
}
-
- // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
- bool restoreFlow = false;
- try
- {
- if (!ExecutionContext.IsFlowSuppressed())
- {
- ExecutionContext.SuppressFlow();
- restoreFlow = true;
- }
-
- _cleaningTimer = new Timer(s => ((HttpConnectionPoolManager)s).RemoveStalePools(), this, Timeout.Infinite, Timeout.Infinite);
- }
- finally
- {
- // Restore the current ExecutionContext
- if (restoreFlow)
- ExecutionContext.RestoreFlow();
- }
}
public HttpConnectionSettings Settings => _settings;
public ICredentials ProxyCredentials => _proxyCredentials;
+ public bool AvoidStoringConnections =>
+ _settings._pooledConnectionIdleTimeout == TimeSpan.Zero ||
+ _settings._pooledConnectionLifetime == TimeSpan.Zero;
private static string ParseHostNameFromHeader(string hostHeader)
{
@@ -204,7 +211,7 @@ namespace System.Net.Http
while (!_pools.TryGetValue(key, out pool))
{
pool = new HttpConnectionPool(this, key.Kind, key.Host, key.Port, key.SslHostName, key.ProxyUri, _maxConnectionsPerServer);
- if (_pools.TryAdd(key, pool))
+ if (_pools.TryAdd(key, pool) && _cleaningTimer != null)
{
// We need to ensure the cleanup timer is running if it isn't
// already now that we added a new connection pool.
@@ -263,7 +270,8 @@ namespace System.Net.Http
/// <summary>Disposes of the pools, disposing of each individual pool.</summary>
public void Dispose()
{
- _cleaningTimer.Dispose();
+ _cleaningTimer?.Dispose();
+
foreach (KeyValuePair<HttpConnectionKey, HttpConnectionPool> pool in _pools)
{
pool.Value.Dispose();
@@ -278,6 +286,8 @@ namespace System.Net.Http
/// <summary>Removes unusable connections from each pool, and removes stale pools entirely.</summary>
private void RemoveStalePools()
{
+ Debug.Assert(_cleaningTimer != null);
+
// Iterate through each pool in the set of pools. For each, ask it to clear out
// any unusable connections (e.g. those which have expired, those which have been closed, etc.)
// The pool may detect that it's empty and long unused, in which case it'll dispose of itself,
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs
index f10fdb75f2..615f2cb4fa 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs
@@ -19,9 +19,5 @@ namespace System.Net.Http.Functional.Tests
private bool BackendSupportsSslConfiguration =>
UseSocketsHttpHandler ||
(Interop.Http.GetSslVersionDescription()?.StartsWith(Interop.Http.OpenSsl10Description, StringComparison.OrdinalIgnoreCase) ?? false);
-
- private bool SSLv3DisabledByDefault =>
- BackendSupportsSslConfiguration ||
- Version.Parse(Interop.Http.GetVersionDescription()) >= new Version(7, 39); // libcurl disables SSLv3 by default starting in v7.39
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs
index 020d9c5afa..961275bfc0 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs
@@ -8,7 +8,5 @@ namespace System.Net.Http.Functional.Tests
public abstract partial class HttpClientHandler_SslProtocols_Test
{
private static bool BackendSupportsSslConfiguration => true;
-
- private static bool SSLv3DisabledByDefault => true;
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs
index 25fd78fcb1..e578aa7597 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs
@@ -2,6 +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.Collections.Generic;
using System.IO;
using System.Net.Security;
using System.Net.Test.Common;
@@ -68,31 +69,35 @@ namespace System.Net.Http.Functional.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
- [Theory]
- [InlineData(~SslProtocols.None)]
-#pragma warning disable 0618 // obsolete warning
- [InlineData(SslProtocols.Ssl2)]
- [InlineData(SslProtocols.Ssl3)]
- [InlineData(SslProtocols.Ssl2 | SslProtocols.Ssl3)]
- [InlineData(SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12)]
-#pragma warning restore 0618
- public void DisabledProtocols_SetSslProtocols_ThrowsException(SslProtocols disabledProtocols)
+
+ public static IEnumerable<object[]> GetAsync_AllowedSSLVersion_Succeeds_MemberData()
{
- using (HttpClientHandler handler = CreateHttpClientHandler())
+ // These protocols are all enabled by default, so we can connect with them both when
+ // explicitly specifying it in the client and when not.
+ foreach (SslProtocols protocol in new[] { SslProtocols.Tls, SslProtocols.Tls11, SslProtocols.Tls12 })
{
- Assert.Throws<NotSupportedException>(() => handler.SslProtocols = disabledProtocols);
+ yield return new object[] { protocol, false };
+ yield return new object[] { protocol, true };
}
+
+ // These protocols are disabled by default, so we can only connect with them explicitly
+#pragma warning disable 0618
+ if (PlatformDetection.IsWindows ||
+ PlatformDetection.IsOSX ||
+ (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && PlatformDetection.OpenSslVersion < new Version(1, 0, 2) && !PlatformDetection.IsDebian))
+ {
+ yield return new object[] { SslProtocols.Ssl3, true };
+ }
+ if (PlatformDetection.IsWindows && !PlatformDetection.IsWindows10Version1607OrGreater)
+ {
+ yield return new object[] { SslProtocols.Ssl2, true };
+ }
+#pragma warning restore 0618
}
[OuterLoop] // TODO: Issue #11345
[Theory]
- [InlineData(SslProtocols.Tls, false)]
- [InlineData(SslProtocols.Tls, true)]
- [InlineData(SslProtocols.Tls11, false)]
- [InlineData(SslProtocols.Tls11, true)]
- [InlineData(SslProtocols.Tls12, false)]
- [InlineData(SslProtocols.Tls12, true)]
+ [MemberData(nameof(GetAsync_AllowedSSLVersion_Succeeds_MemberData))]
public async Task GetAsync_AllowedSSLVersion_Succeeds(SslProtocols acceptedProtocol, bool requestOnlyThisProtocol)
{
if (!BackendSupportsSslConfiguration)
@@ -125,17 +130,24 @@ namespace System.Net.Http.Functional.Tests
}
}
- public static readonly object[][] SupportedSSLVersionServers =
+ public static IEnumerable<object[]> SupportedSSLVersionServers()
{
- new object[] {SslProtocols.Tls, Configuration.Http.TLSv10RemoteServer},
- new object[] {SslProtocols.Tls11, Configuration.Http.TLSv11RemoteServer},
- new object[] {SslProtocols.Tls12, Configuration.Http.TLSv12RemoteServer},
- };
+#pragma warning disable 0618 // SSL2/3 are deprecated
+ if (PlatformDetection.IsWindows ||
+ PlatformDetection.IsOSX ||
+ (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && PlatformDetection.OpenSslVersion < new Version(1, 0, 2) && !PlatformDetection.IsDebian))
+ {
+ yield return new object[] { SslProtocols.Ssl3, Configuration.Http.SSLv3RemoteServer };
+ }
+#pragma warning restore 0618
+ yield return new object[] { SslProtocols.Tls, Configuration.Http.TLSv10RemoteServer };
+ yield return new object[] { SslProtocols.Tls11, Configuration.Http.TLSv11RemoteServer };
+ yield return new object[] { SslProtocols.Tls12, Configuration.Http.TLSv12RemoteServer };
+ }
- // This test is logically the same as the above test, albeit using remote servers
- // instead of local ones. We're keeping it for now (as outerloop) because it helps
- // to validate against another SSL implementation that what we mean by a particular
- // TLS version matches that other implementation.
+ // We have tests that validate with SslStream, but that's limited by what the current OS supports.
+ // This tests provides additional validation against an external server.
+ [ActiveIssue(26186)]
[OuterLoop("Avoid www.ssllabs.com dependency in innerloop.")]
[Theory]
[MemberData(nameof(SupportedSSLVersionServers))]
@@ -149,12 +161,7 @@ namespace System.Net.Http.Functional.Tests
using (HttpClientHandler handler = CreateHttpClientHandler())
{
- if (PlatformDetection.IsRedHatFamily7)
- {
- // Default protocol selection is always TLSv1 on Centos7 libcurl 7.29.0
- // Hence, set the specific protocol on HttpClient that is required by test
- handler.SslProtocols = sslProtocols;
- }
+ handler.SslProtocols = sslProtocols;
using (var client = new HttpClient(handler))
{
(await RemoteServerQuery.Run(() => client.GetAsync(url), remoteServerExceptionWrapper, url)).Dispose();
@@ -177,35 +184,27 @@ namespace System.Net.Http.Functional.Tests
}
};
- public static readonly object[][] NotSupportedSSLVersionServers =
+ public static IEnumerable<object[]> NotSupportedSSLVersionServers()
{
- new object[] {"SSLv2", Configuration.Http.SSLv2RemoteServer},
- new object[] {"SSLv3", Configuration.Http.SSLv3RemoteServer},
- };
+#pragma warning disable 0618
+ if (PlatformDetection.IsWindows10Version1607OrGreater)
+ {
+ yield return new object[] { SslProtocols.Ssl2, Configuration.Http.SSLv2RemoteServer };
+ }
+#pragma warning restore 0618
+ }
- // It would be easy to remove the dependency on these remote servers if we didn't
- // explicitly disallow creating SslStream with SSLv2/3. Since we explicitly throw
- // when trying to use such an SslStream, we can't stand up a localhost server that
- // only speaks those protocols.
+ // We have tests that validate with SslStream, but that's limited by what the current OS supports.
+ // This tests provides additional validation against an external server.
[OuterLoop("Avoid www.ssllabs.com dependency in innerloop.")]
[Theory]
[MemberData(nameof(NotSupportedSSLVersionServers))]
- public async Task GetAsync_UnsupportedSSLVersion_Throws(string name, string url)
+ public async Task GetAsync_UnsupportedSSLVersion_Throws(SslProtocols sslProtocols, string url)
{
- if (!SSLv3DisabledByDefault)
- {
- return;
- }
-
- if (UseSocketsHttpHandler && !PlatformDetection.IsWindows10Version1607OrGreater)
- {
- // On Windows, https://github.com/dotnet/corefx/issues/21925#issuecomment-313408314
- // On Linux, an older version of OpenSSL may permit negotiating SSLv3.
- return;
- }
-
- using (HttpClient client = CreateHttpClient())
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (HttpClient client = new HttpClient(handler))
{
+ handler.SslProtocols = sslProtocols;
await Assert.ThrowsAsync<HttpRequestException>(() => RemoteServerQuery.Run(() => client.GetAsync(url), remoteServerExceptionWrapper, url));
}
}
@@ -240,6 +239,10 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop] // TODO: Issue #11345
[Theory]
+#pragma warning disable 0618 // SSL2/3 are deprecated
+ [InlineData(SslProtocols.Ssl2, SslProtocols.Tls12)]
+ [InlineData(SslProtocols.Ssl3, SslProtocols.Tls12)]
+#pragma warning restore 0618
[InlineData(SslProtocols.Tls11, SslProtocols.Tls)]
[InlineData(SslProtocols.Tls12, SslProtocols.Tls11)]
[InlineData(SslProtocols.Tls, SslProtocols.Tls12)]
diff --git a/src/System.Net.Http/tests/FunctionalTests/ReadOnlyMemoryContentTest.cs b/src/System.Net.Http/tests/FunctionalTests/ReadOnlyMemoryContentTest.cs
index f33fc4bb74..cc2e7e9d9e 100644
--- a/src/System.Net.Http/tests/FunctionalTests/ReadOnlyMemoryContentTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/ReadOnlyMemoryContentTest.cs
@@ -35,12 +35,10 @@ namespace System.Net.Http.Functional.Tests
public void ContentLength_LengthMatchesArrayLength(int contentLength, bool useArray)
{
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out ownedMemory);
-
- Assert.Equal(contentLength, content.Headers.ContentLength);
-
- ownedMemory?.Dispose();
+ using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
+ {
+ Assert.Equal(contentLength, content.Headers.ContentLength);
+ }
}
[Theory]
@@ -49,32 +47,32 @@ namespace System.Net.Http.Functional.Tests
{
const int ContentLength = 42;
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out ownedMemory);
- using (Stream stream = await content.ReadAsStreamAsync())
+ using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
{
- // property values
- Assert.Equal(ContentLength, stream.Length);
- Assert.Equal(0, stream.Position);
- Assert.True(stream.CanRead);
- Assert.True(stream.CanSeek);
- Assert.False(stream.CanWrite);
-
- // not supported
- Assert.Throws<NotSupportedException>(() => stream.SetLength(12345));
- Assert.Throws<NotSupportedException>(() => stream.WriteByte(0));
- Assert.Throws<NotSupportedException>(() => stream.Write(new byte[1], 0, 1));
- Assert.Throws<NotSupportedException>(() => stream.Write(new ReadOnlySpan<byte>(new byte[1])));
- await Assert.ThrowsAsync<NotSupportedException>(async () => await stream.WriteAsync(new byte[1], 0, 1));
- await Assert.ThrowsAsync<NotSupportedException>(async () => await stream.WriteAsync(new ReadOnlyMemory<byte>(new byte[1])));
-
- // nops
- stream.Flush();
- await stream.FlushAsync();
- }
+ using (Stream stream = await content.ReadAsStreamAsync())
+ {
- ownedMemory?.Dispose();
+ // property values
+ Assert.Equal(ContentLength, stream.Length);
+ Assert.Equal(0, stream.Position);
+ Assert.True(stream.CanRead);
+ Assert.True(stream.CanSeek);
+ Assert.False(stream.CanWrite);
+
+ // not supported
+ Assert.Throws<NotSupportedException>(() => stream.SetLength(12345));
+ Assert.Throws<NotSupportedException>(() => stream.WriteByte(0));
+ Assert.Throws<NotSupportedException>(() => stream.Write(new byte[1], 0, 1));
+ Assert.Throws<NotSupportedException>(() => stream.Write(new ReadOnlySpan<byte>(new byte[1])));
+ await Assert.ThrowsAsync<NotSupportedException>(async () => await stream.WriteAsync(new byte[1], 0, 1));
+ await Assert.ThrowsAsync<NotSupportedException>(async () => await stream.WriteAsync(new ReadOnlyMemory<byte>(new byte[1])));
+
+ // nops
+ stream.Flush();
+ await stream.FlushAsync();
+ }
+ }
}
[Theory]
@@ -83,62 +81,61 @@ namespace System.Net.Http.Functional.Tests
{
const int ContentLength = 42;
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out ownedMemory);
- using (Stream s = await content.ReadAsStreamAsync())
+ using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
{
- foreach (int pos in new[] { 0, ContentLength / 2, ContentLength - 1 })
+ using (Stream s = await content.ReadAsStreamAsync())
{
- s.Position = pos;
- Assert.Equal(pos, s.Position);
- Assert.Equal(memory.Span[pos], s.ReadByte());
- }
+ foreach (int pos in new[] { 0, ContentLength / 2, ContentLength - 1 })
+ {
+ s.Position = pos;
+ Assert.Equal(pos, s.Position);
+ Assert.Equal(memory.Span[pos], s.ReadByte());
+ }
- foreach (int pos in new[] { 0, ContentLength / 2, ContentLength - 1 })
- {
- Assert.Equal(0, s.Seek(0, SeekOrigin.Begin));
+ foreach (int pos in new[] { 0, ContentLength / 2, ContentLength - 1 })
+ {
+ Assert.Equal(0, s.Seek(0, SeekOrigin.Begin));
+ Assert.Equal(memory.Span[0], s.ReadByte());
+ }
+
+ Assert.Equal(ContentLength, s.Seek(0, SeekOrigin.End));
+ Assert.Equal(s.Position, s.Length);
+ Assert.Equal(-1, s.ReadByte());
+
+ Assert.Equal(0, s.Seek(-ContentLength, SeekOrigin.End));
+ Assert.Equal(0, s.Position);
Assert.Equal(memory.Span[0], s.ReadByte());
- }
- Assert.Equal(ContentLength, s.Seek(0, SeekOrigin.End));
- Assert.Equal(s.Position, s.Length);
- Assert.Equal(-1, s.ReadByte());
-
- Assert.Equal(0, s.Seek(-ContentLength, SeekOrigin.End));
- Assert.Equal(0, s.Position);
- Assert.Equal(memory.Span[0], s.ReadByte());
-
- s.Position = 0;
- Assert.Equal(0, s.Seek(0, SeekOrigin.Current));
- Assert.Equal(0, s.Position);
-
- Assert.Equal(1, s.Seek(1, SeekOrigin.Current));
- Assert.Equal(1, s.Position);
- Assert.Equal(memory.Span[1], s.ReadByte());
- Assert.Equal(2, s.Position);
- Assert.Equal(3, s.Seek(1, SeekOrigin.Current));
- Assert.Equal(1, s.Seek(-2, SeekOrigin.Current));
-
- Assert.Equal(int.MaxValue, s.Seek(int.MaxValue, SeekOrigin.Begin));
- Assert.Equal(int.MaxValue, s.Position);
- Assert.Equal(int.MaxValue, s.Seek(0, SeekOrigin.Current));
- Assert.Equal(int.MaxValue, s.Position);
- Assert.Equal(int.MaxValue, s.Seek(int.MaxValue - ContentLength, SeekOrigin.End));
- Assert.Equal(int.MaxValue, s.Position);
- Assert.Equal(-1, s.ReadByte());
- Assert.Equal(int.MaxValue, s.Position);
-
- Assert.Throws<ArgumentOutOfRangeException>("value", () => s.Position = -1);
- Assert.Throws<IOException>(() => s.Seek(-1, SeekOrigin.Begin));
-
- AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => s.Position = (long)int.MaxValue + 1);
- AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => s.Seek((long)int.MaxValue + 1, SeekOrigin.Begin));
-
- Assert.ThrowsAny<ArgumentException>(() => s.Seek(0, (SeekOrigin)42));
+ s.Position = 0;
+ Assert.Equal(0, s.Seek(0, SeekOrigin.Current));
+ Assert.Equal(0, s.Position);
+
+ Assert.Equal(1, s.Seek(1, SeekOrigin.Current));
+ Assert.Equal(1, s.Position);
+ Assert.Equal(memory.Span[1], s.ReadByte());
+ Assert.Equal(2, s.Position);
+ Assert.Equal(3, s.Seek(1, SeekOrigin.Current));
+ Assert.Equal(1, s.Seek(-2, SeekOrigin.Current));
+
+ Assert.Equal(int.MaxValue, s.Seek(int.MaxValue, SeekOrigin.Begin));
+ Assert.Equal(int.MaxValue, s.Position);
+ Assert.Equal(int.MaxValue, s.Seek(0, SeekOrigin.Current));
+ Assert.Equal(int.MaxValue, s.Position);
+ Assert.Equal(int.MaxValue, s.Seek(int.MaxValue - ContentLength, SeekOrigin.End));
+ Assert.Equal(int.MaxValue, s.Position);
+ Assert.Equal(-1, s.ReadByte());
+ Assert.Equal(int.MaxValue, s.Position);
+
+ Assert.Throws<ArgumentOutOfRangeException>("value", () => s.Position = -1);
+ Assert.Throws<IOException>(() => s.Seek(-1, SeekOrigin.Begin));
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => s.Position = (long)int.MaxValue + 1);
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => s.Seek((long)int.MaxValue + 1, SeekOrigin.Begin));
+
+ Assert.ThrowsAny<ArgumentException>(() => s.Seek(0, (SeekOrigin)42));
+ }
}
-
- ownedMemory?.Dispose();
}
[Theory]
@@ -146,21 +143,20 @@ namespace System.Net.Http.Functional.Tests
public async Task ReadAsStreamAsync_ReadByte_MatchesInput(int contentLength, bool useArray)
{
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out ownedMemory);
- using (Stream stream = await content.ReadAsStreamAsync())
+ using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
{
- for (int i = 0; i < contentLength; i++)
+ using (Stream stream = await content.ReadAsStreamAsync())
{
- Assert.Equal(memory.Span[i], stream.ReadByte());
- Assert.Equal(i + 1, stream.Position);
+ for (int i = 0; i < contentLength; i++)
+ {
+ Assert.Equal(memory.Span[i], stream.ReadByte());
+ Assert.Equal(i + 1, stream.Position);
+ }
+ Assert.Equal(-1, stream.ReadByte());
+ Assert.Equal(stream.Length, stream.Position);
}
- Assert.Equal(-1, stream.ReadByte());
- Assert.Equal(stream.Length, stream.Position);
}
-
- ownedMemory?.Dispose();
}
[Theory]
@@ -169,27 +165,26 @@ namespace System.Net.Http.Functional.Tests
{
const int ContentLength = 42;
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out ownedMemory);
- using (Stream stream = await content.ReadAsStreamAsync())
+ using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
{
- AssertExtensions.Throws<ArgumentNullException>("buffer", () => stream.Read(null, 0, 0));
- AssertExtensions.Throws<ArgumentNullException>("buffer", () => { stream.ReadAsync(null, 0, 0); });
+ using (Stream stream = await content.ReadAsStreamAsync())
+ {
+ AssertExtensions.Throws<ArgumentNullException>("buffer", () => stream.Read(null, 0, 0));
+ AssertExtensions.Throws<ArgumentNullException>("buffer", () => { stream.ReadAsync(null, 0, 0); });
- AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => stream.Read(new byte[1], -1, 1));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => stream.Read(new byte[1], -1, 1));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => stream.Read(new byte[1], -1, 1));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => stream.Read(new byte[1], -1, 1));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => stream.Read(new byte[1], 0, -1));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => stream.Read(new byte[1], 0, -1));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => stream.Read(new byte[1], 0, -1));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => stream.Read(new byte[1], 0, -1));
- Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 2, 0); });
- Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 2, 0); });
- Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 0, 2); });
- Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 0, 2); });
+ Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 2, 0); });
+ Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 2, 0); });
+ Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 0, 2); });
+ Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 0, 2); });
+ }
}
-
- ownedMemory?.Dispose();
}
[Theory]
@@ -208,40 +203,38 @@ namespace System.Net.Http.Functional.Tests
const int ContentLength = 1024;
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out ownedMemory);
-
- var buffer = new byte[3];
-
- using (Stream stream = await content.ReadAsStreamAsync())
+ using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
{
- for (int i = 0; i < ContentLength; i += buffer.Length)
+ var buffer = new byte[3];
+
+ using (Stream stream = await content.ReadAsStreamAsync())
{
- int bytesRead =
+ for (int i = 0; i < ContentLength; i += buffer.Length)
+ {
+ int bytesRead =
+ mode == 0 ? stream.Read(buffer, 0, buffer.Length) :
+ mode == 1 ? stream.Read(new Span<byte>(buffer)) :
+ mode == 2 ? await stream.ReadAsync(buffer, 0, buffer.Length) :
+ mode == 3 ? await stream.ReadAsync(new Memory<byte>(buffer)) :
+ await Task.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, 0, buffer.Length, null);
+
+ Assert.Equal(Math.Min(buffer.Length, ContentLength - i), bytesRead);
+ for (int j = 0; j < bytesRead; j++)
+ {
+ Assert.Equal(memory.Span[i + j], buffer[j]);
+ }
+
+ Assert.Equal(i + bytesRead, stream.Position);
+ }
+
+ Assert.Equal(0,
mode == 0 ? stream.Read(buffer, 0, buffer.Length) :
mode == 1 ? stream.Read(new Span<byte>(buffer)) :
mode == 2 ? await stream.ReadAsync(buffer, 0, buffer.Length) :
mode == 3 ? await stream.ReadAsync(new Memory<byte>(buffer)) :
- await Task.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, 0, buffer.Length, null);
-
- Assert.Equal(Math.Min(buffer.Length, ContentLength - i), bytesRead);
- for (int j = 0; j < bytesRead; j++)
- {
- Assert.Equal(memory.Span[i + j], buffer[j]);
- }
-
- Assert.Equal(i + bytesRead, stream.Position);
+ await Task.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, 0, buffer.Length, null));
}
-
- Assert.Equal(0,
- mode == 0 ? stream.Read(buffer, 0, buffer.Length) :
- mode == 1 ? stream.Read(new Span<byte>(buffer)) :
- mode == 2 ? await stream.ReadAsync(buffer, 0, buffer.Length) :
- mode == 3 ? await stream.ReadAsync(new Memory<byte>(buffer)) :
- await Task.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, 0, buffer.Length, null));
}
-
- ownedMemory?.Dispose();
}
[Theory]
@@ -251,32 +244,30 @@ namespace System.Net.Http.Functional.Tests
const int ContentLength = 100;
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out ownedMemory);
-
- var buffer = new byte[1];
- var cts = new CancellationTokenSource();
- int bytesRead;
-
- using (Stream stream = await content.ReadAsStreamAsync())
+ using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
{
- for (int i = 0; i < ContentLength; i++)
+ var buffer = new byte[1];
+ var cts = new CancellationTokenSource();
+ int bytesRead;
+
+ using (Stream stream = await content.ReadAsStreamAsync())
{
- switch (i % 2)
+ for (int i = 0; i < ContentLength; i++)
{
- case 0:
- bytesRead = await stream.ReadAsync(buffer, 0, 1, cts.Token);
- break;
- default:
- bytesRead = await stream.ReadAsync(new Memory<byte>(buffer), cts.Token);
- break;
+ switch (i % 2)
+ {
+ case 0:
+ bytesRead = await stream.ReadAsync(buffer, 0, 1, cts.Token);
+ break;
+ default:
+ bytesRead = await stream.ReadAsync(new Memory<byte>(buffer), cts.Token);
+ break;
+ }
+ Assert.Equal(1, bytesRead);
+ Assert.Equal(memory.Span[i], buffer[0]);
}
- Assert.Equal(1, bytesRead);
- Assert.Equal(memory.Span[i], buffer[0]);
}
}
-
- ownedMemory?.Dispose();
}
[Theory]
@@ -286,17 +277,16 @@ namespace System.Net.Http.Functional.Tests
const int ContentLength = 2;
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out ownedMemory);
- using (Stream stream = await content.ReadAsStreamAsync())
+ using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
{
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => stream.ReadAsync(new byte[1], 0, 1, new CancellationToken(true)));
- await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await stream.ReadAsync(new Memory<byte>(new byte[1]), new CancellationToken(true)));
- await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await stream.CopyToAsync(new MemoryStream(), 1, new CancellationToken(true)));
+ using (Stream stream = await content.ReadAsStreamAsync())
+ {
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => stream.ReadAsync(new byte[1], 0, 1, new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await stream.ReadAsync(new Memory<byte>(new byte[1]), new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await stream.CopyToAsync(new MemoryStream(), 1, new CancellationToken(true)));
+ }
}
-
- ownedMemory?.Dispose();
}
[Theory]
@@ -304,15 +294,14 @@ namespace System.Net.Http.Functional.Tests
public async Task CopyToAsync_AllContentCopied(int contentLength, bool useArray)
{
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out ownedMemory);
-
- var destination = new MemoryStream();
- await content.CopyToAsync(destination);
+ using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
+ {
- Assert.Equal<byte>(memory.ToArray(), destination.ToArray());
+ var destination = new MemoryStream();
+ await content.CopyToAsync(destination);
- ownedMemory?.Dispose();
+ Assert.Equal<byte>(memory.ToArray(), destination.ToArray());
+ }
}
[Theory]
@@ -320,18 +309,17 @@ namespace System.Net.Http.Functional.Tests
public async Task ReadAsStreamAsync_CopyTo_AllContentCopied(int contentLength, bool useArray)
{
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out ownedMemory);
-
- var destination = new MemoryStream();
- using (Stream s = await content.ReadAsStreamAsync())
+ using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
{
- s.CopyTo(destination);
- }
- Assert.Equal<byte>(memory.ToArray(), destination.ToArray());
+ var destination = new MemoryStream();
+ using (Stream s = await content.ReadAsStreamAsync())
+ {
+ s.CopyTo(destination);
+ }
- ownedMemory?.Dispose();
+ Assert.Equal<byte>(memory.ToArray(), destination.ToArray());
+ }
}
[Theory]
@@ -340,27 +328,25 @@ namespace System.Net.Http.Functional.Tests
{
const int ContentLength = 42;
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out ownedMemory);
-
- using (Stream s = await content.ReadAsStreamAsync())
+ using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
{
- AssertExtensions.Throws<ArgumentNullException>("destination", () => s.CopyTo(null));
- AssertExtensions.Throws<ArgumentNullException>("destination", () => { s.CopyToAsync(null); });
+ using (Stream s = await content.ReadAsStreamAsync())
+ {
+ AssertExtensions.Throws<ArgumentNullException>("destination", () => s.CopyTo(null));
+ AssertExtensions.Throws<ArgumentNullException>("destination", () => { s.CopyToAsync(null); });
- AssertExtensions.Throws<ArgumentOutOfRangeException>("bufferSize", () => s.CopyTo(new MemoryStream(), 0));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("bufferSize", () => { s.CopyToAsync(new MemoryStream(), 0); });
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("bufferSize", () => s.CopyTo(new MemoryStream(), 0));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("bufferSize", () => { s.CopyToAsync(new MemoryStream(), 0); });
- Assert.Throws<NotSupportedException>(() => s.CopyTo(new MemoryStream(new byte[1], writable:false)));
- Assert.Throws<NotSupportedException>(() => { s.CopyToAsync(new MemoryStream(new byte[1], writable: false)); });
+ Assert.Throws<NotSupportedException>(() => s.CopyTo(new MemoryStream(new byte[1], writable: false)));
+ Assert.Throws<NotSupportedException>(() => { s.CopyToAsync(new MemoryStream(new byte[1], writable: false)); });
- var disposedDestination = new MemoryStream();
- disposedDestination.Dispose();
- Assert.Throws<ObjectDisposedException>(() => s.CopyTo(disposedDestination));
- Assert.Throws<ObjectDisposedException>(() => { s.CopyToAsync(disposedDestination); });
+ var disposedDestination = new MemoryStream();
+ disposedDestination.Dispose();
+ Assert.Throws<ObjectDisposedException>(() => s.CopyTo(disposedDestination));
+ Assert.Throws<ObjectDisposedException>(() => { s.CopyToAsync(disposedDestination); });
+ }
}
-
- ownedMemory?.Dispose();
}
[Theory]
@@ -368,21 +354,20 @@ namespace System.Net.Http.Functional.Tests
public async Task ReadAsStreamAsync_CopyToAsync_AllContentCopied(int contentLength, bool useArray)
{
Memory<byte> memory;
- OwnedMemory<byte> ownedMemory;
- ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out ownedMemory);
-
- var destination = new MemoryStream();
- using (Stream s = await content.ReadAsStreamAsync())
+ using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out MemoryManager<byte> ownedMemory))
{
- await s.CopyToAsync(destination);
- }
- Assert.Equal<byte>(memory.ToArray(), destination.ToArray());
+ var destination = new MemoryStream();
+ using (Stream s = await content.ReadAsStreamAsync())
+ {
+ await s.CopyToAsync(destination);
+ }
- ownedMemory?.Dispose();
+ Assert.Equal<byte>(memory.ToArray(), destination.ToArray());
+ }
}
- private static ReadOnlyMemoryContent CreateContent(int contentLength, bool useArray, out Memory<byte> memory, out OwnedMemory<byte> ownedMemory)
+ private static ReadOnlyMemoryContent CreateContent(int contentLength, bool useArray, out Memory<byte> memory, out MemoryManager<byte> ownedMemory)
{
if (useArray)
{
@@ -391,7 +376,7 @@ namespace System.Net.Http.Functional.Tests
}
else
{
- ownedMemory = new NativeOwnedMemory(contentLength);
+ ownedMemory = new NativeMemoryManager(contentLength);
memory = ownedMemory.Memory;
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
index 6e9a8807ef..b81d55947a 100644
--- a/src/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
+++ b/src/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
@@ -24,8 +24,8 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Net.Http.Native\Interop.VersionInfo.cs" Condition="'$(TargetsUnix)' == 'true'">
<Link>Common\Interop\Unix\System.Net.Http.Native\Interop.VersionInfo.cs</Link>
</Compile>
- <Compile Include="$(CommonTestPath)\System\Buffers\NativeOwnedMemory.cs">
- <Link>Common\System\Buffers\NativeOwnedMemory.cs</Link>
+ <Compile Include="$(CommonTestPath)\System\Buffers\NativeMemoryManager.cs">
+ <Link>Common\System\Buffers\NativeMemoryManager.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\Diagnostics\Tracing\TestEventListener.cs">
<Link>Common\System\Diagnostics\Tracing\TestEventListener.cs</Link>
diff --git a/src/System.Net.HttpListener/src/System/Net/Managed/WebSockets/HttpWebSocket.Managed.cs b/src/System.Net.HttpListener/src/System/Net/Managed/WebSockets/HttpWebSocket.Managed.cs
index d7c9ea6e58..f169e85717 100644
--- a/src/System.Net.HttpListener/src/System/Net/Managed/WebSockets/HttpWebSocket.Managed.cs
+++ b/src/System.Net.HttpListener/src/System/Net/Managed/WebSockets/HttpWebSocket.Managed.cs
@@ -58,12 +58,7 @@ namespace System.Net.WebSockets
// Send websocket handshake headers
await responseStream.WriteWebSocketHandshakeHeadersAsync().ConfigureAwait(false);
- const int MinBufferSize = 14; // from ManagedWebSocket.MaxMessageHeaderLength
- Memory<byte> buffer =
- internalBuffer.GetValueOrDefault().Count >= MinBufferSize ? internalBuffer.GetValueOrDefault() : // use provided buffer if it's big enough
- receiveBufferSize >= MinBufferSize ? new byte[receiveBufferSize] : // or use provided size if it's big enough
- Memory<byte>.Empty; // or use the default
- WebSocket webSocket = WebSocket.CreateFromStream(context.Connection.ConnectedStream, isServer:true, subProtocol, keepAliveInterval, buffer);
+ WebSocket webSocket = WebSocket.CreateFromStream(context.Connection.ConnectedStream, isServer:true, subProtocol, keepAliveInterval);
HttpListenerWebSocketContext webSocketContext = new HttpListenerWebSocketContext(
request.Url,
diff --git a/src/System.Net.Mail/tests/Functional/SmtpClientTest.cs b/src/System.Net.Mail/tests/Functional/SmtpClientTest.cs
index 618ebf85c7..60605123df 100644
--- a/src/System.Net.Mail/tests/Functional/SmtpClientTest.cs
+++ b/src/System.Net.Mail/tests/Functional/SmtpClientTest.cs
@@ -17,10 +17,9 @@ using Xunit;
namespace System.Net.Mail.Tests
{
- public class SmtpClientTest : IDisposable
+ public class SmtpClientTest : FileCleanupTestBase
{
private SmtpClient _smtp;
- private string _tempFolder;
private SmtpClient Smtp
{
@@ -34,28 +33,17 @@ namespace System.Net.Mail.Tests
{
get
{
- if (_tempFolder == null)
- {
- _tempFolder = Path.Combine(Path.GetTempPath(), GetType().FullName, Guid.NewGuid().ToString());
- if (Directory.Exists(_tempFolder))
- Directory.Delete(_tempFolder, true);
-
- Directory.CreateDirectory(_tempFolder);
- }
-
- return _tempFolder;
+ return TestDirectory;
}
}
- public void Dispose()
+ protected override void Dispose(bool disposing)
{
if (_smtp != null)
{
_smtp.Dispose();
}
-
- if (Directory.Exists(_tempFolder))
- Directory.Delete(_tempFolder, true);
+ base.Dispose(disposing);
}
[Theory]
diff --git a/src/System.Net.Primitives/src/System/Net/CookieContainer.cs b/src/System.Net.Primitives/src/System/Net/CookieContainer.cs
index 27dc045528..527a94ec2d 100644
--- a/src/System.Net.Primitives/src/System/Net/CookieContainer.cs
+++ b/src/System.Net.Primitives/src/System/Net/CookieContainer.cs
@@ -97,6 +97,7 @@ namespace System.Net
public const int DefaultPerDomainCookieLimit = 20;
public const int DefaultCookieLengthLimit = 4096;
+ private static readonly string s_fqdnMyDomain = CreateFqdnMyDomain();
private static readonly HeaderVariantInfo[] s_headerInfo = {
new HeaderVariantInfo(HttpKnownHeaderNames.SetCookie, CookieVariant.Rfc2109),
new HeaderVariantInfo(HttpKnownHeaderNames.SetCookie2, CookieVariant.Rfc2965)
@@ -107,19 +108,13 @@ namespace System.Net
private int m_maxCookies = DefaultCookieLimit; // Do not rename (binary serialization)
private int m_maxCookiesPerDomain = DefaultPerDomainCookieLimit; // Do not rename (binary serialization)
private int m_count = 0; // Do not rename (binary serialization)
- private string m_fqdnMyDomain = string.Empty; // Do not rename (binary serialization)
+ private string m_fqdnMyDomain = s_fqdnMyDomain; // Do not rename (binary serialization)
public CookieContainer()
{
- string domain = HostInformation.DomainName;
- if (domain != null && domain.Length > 1)
- {
- m_fqdnMyDomain = '.' + domain;
- }
- // Otherwise it will remain string.Empty.
}
- public CookieContainer(int capacity) : this()
+ public CookieContainer(int capacity)
{
if (capacity <= 0)
{
@@ -142,6 +137,14 @@ namespace System.Net
m_maxCookieSize = maxCookieSize;
}
+ private static string CreateFqdnMyDomain()
+ {
+ string domain = HostInformation.DomainName;
+ return domain != null && domain.Length > 1 ?
+ '.' + domain :
+ string.Empty;
+ }
+
// NOTE: after shrinking the capacity, Count can become greater than Capacity.
public int Capacity
{
diff --git a/src/System.Net.Security/ref/System.Net.Security.cs b/src/System.Net.Security/ref/System.Net.Security.cs
index fbe4022fbe..785eadd9c2 100644
--- a/src/System.Net.Security/ref/System.Net.Security.cs
+++ b/src/System.Net.Security/ref/System.Net.Security.cs
@@ -32,6 +32,8 @@ namespace System.Net.Security
RequireEncryption = 0,
}
public delegate System.Security.Cryptography.X509Certificates.X509Certificate LocalCertificateSelectionCallback(object sender, string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection localCertificates, System.Security.Cryptography.X509Certificates.X509Certificate remoteCertificate, string[] acceptableIssuers);
+ public delegate System.Security.Cryptography.X509Certificates.X509Certificate ServerCertificateSelectionCallback(object sender, string hostName);
+
public partial class NegotiateStream : AuthenticatedStream
{
public NegotiateStream(System.IO.Stream innerStream) : base(innerStream, false) { }
@@ -108,6 +110,7 @@ namespace System.Net.Security
public X509RevocationMode CertificateRevocationCheckMode { get { throw null; } set { } }
public List<SslApplicationProtocol> ApplicationProtocols { get { throw null; } set { } }
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get { throw null; } set { } }
+ public ServerCertificateSelectionCallback ServerCertificateSelectionCallback { get { throw null; } set { } }
public EncryptionPolicy EncryptionPolicy { get { throw null; } set { } }
}
public partial class SslClientAuthenticationOptions
diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj
index 5600de5691..e9a5737afe 100644
--- a/src/System.Net.Security/src/System.Net.Security.csproj
+++ b/src/System.Net.Security/src/System.Net.Security.csproj
@@ -23,6 +23,7 @@
<Compile Include="System\Net\FixedSizeReader.cs" />
<Compile Include="System\Net\HelperAsyncResults.cs" />
<Compile Include="System\Net\Logging\NetEventSource.cs" />
+ <Compile Include="System\Net\Security\SniHelper.cs" />
<Compile Include="System\Net\Security\SslApplicationProtocol.cs" />
<Compile Include="System\Net\Security\SslAuthenticationOptions.cs" />
<Compile Include="System\Net\Security\SslClientAuthenticationOptions.cs" />
diff --git a/src/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs b/src/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs
index 1fc55e8997..913e7e590e 100644
--- a/src/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs
+++ b/src/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs
@@ -239,44 +239,81 @@ namespace System.Net
}
}
+ private static readonly SslProtocols[] s_orderedSslProtocols = new SslProtocols[5]
+ {
+#pragma warning disable 0618
+ SslProtocols.Ssl2,
+ SslProtocols.Ssl3,
+#pragma warning restore 0618
+ SslProtocols.Tls,
+ SslProtocols.Tls11,
+ SslProtocols.Tls12
+ };
+
private static void SetProtocols(SafeSslHandle sslContext, SslProtocols protocols)
{
- const SslProtocols SupportedProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
- SslProtocols minProtocolId;
- SslProtocols maxProtocolId;
+ // A contiguous range of protocols is required. Find the min and max of the range,
+ // or throw if it's non-contiguous or if no protocols are specified.
- switch (protocols & SupportedProtocols)
+ // First, mark all of the specified protocols.
+ SslProtocols[] orderedSslProtocols = s_orderedSslProtocols;
+ Span<bool> protocolSet = stackalloc bool[orderedSslProtocols.Length];
+ for (int i = 0; i < orderedSslProtocols.Length; i++)
{
- case SslProtocols.None:
- throw new PlatformNotSupportedException(SR.net_securityprotocolnotsupported);
- case SslProtocols.Tls:
- minProtocolId = SslProtocols.Tls;
- maxProtocolId = SslProtocols.Tls;
- break;
- case SslProtocols.Tls11:
- minProtocolId = SslProtocols.Tls11;
- maxProtocolId = SslProtocols.Tls11;
- break;
- case SslProtocols.Tls12:
- minProtocolId = SslProtocols.Tls12;
- maxProtocolId = SslProtocols.Tls12;
- break;
- case SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12:
- minProtocolId = SslProtocols.Tls;
- maxProtocolId = SslProtocols.Tls12;
- break;
- case SslProtocols.Tls11 | SslProtocols.Tls12:
- minProtocolId = SslProtocols.Tls11;
- maxProtocolId = SslProtocols.Tls12;
- break;
- case SslProtocols.Tls | SslProtocols.Tls11:
- minProtocolId = SslProtocols.Tls;
- maxProtocolId = SslProtocols.Tls11;
+ protocolSet[i] = (protocols & orderedSslProtocols[i]) != 0;
+ }
+
+ SslProtocols minProtocolId = (SslProtocols)(-1);
+ SslProtocols maxProtocolId = (SslProtocols)(-1);
+
+ // Loop through them, starting from the lowest.
+ for (int min = 0; min < protocolSet.Length; min++)
+ {
+ if (protocolSet[min])
+ {
+ // We found the first one that's set; that's the bottom of the range.
+ minProtocolId = orderedSslProtocols[min];
+
+ // Now loop from there to look for the max of the range.
+ for (int max = min + 1; max < protocolSet.Length; max++)
+ {
+ if (!protocolSet[max])
+ {
+ // We found the first one after the min that's not set; the top of the range
+ // is the one before this (which might be the same as the min).
+ maxProtocolId = orderedSslProtocols[max - 1];
+
+ // Finally, verify that nothing beyond this one is set, as that would be
+ // a discontiguous set of protocols.
+ for (int verifyNotSet = max + 1; verifyNotSet < protocolSet.Length; verifyNotSet++)
+ {
+ if (protocolSet[verifyNotSet])
+ {
+ throw new PlatformNotSupportedException(SR.Format(SR.net_security_sslprotocol_contiguous, protocols));
+ }
+ }
+
+ break;
+ }
+ }
+
break;
- default:
- throw new PlatformNotSupportedException(SR.Format(SR.net_security_sslprotocol_contiguous, protocols));
+ }
+ }
+
+ // If no protocols were set, throw.
+ if (minProtocolId == (SslProtocols)(-1))
+ {
+ throw new PlatformNotSupportedException(SR.net_securityprotocolnotsupported);
+ }
+
+ // If we didn't find an unset protocol after the min, go all the way to the last one.
+ if (maxProtocolId == (SslProtocols)(-1))
+ {
+ maxProtocolId = orderedSslProtocols[orderedSslProtocols.Length - 1];
}
+ // Finally set this min and max.
Interop.AppleCrypto.SslSetMinProtocolVersion(sslContext, minProtocolId);
Interop.AppleCrypto.SslSetMaxProtocolVersion(sslContext, maxProtocolId);
}
diff --git a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs
index 4c92ae8754..6440b38c6a 100644
--- a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs
@@ -624,7 +624,7 @@ namespace System.Net.Security
//
// Acquire Server Side Certificate information and set it on the class.
//
- private bool AcquireServerCredentials(ref byte[] thumbPrint)
+ private bool AcquireServerCredentials(ref byte[] thumbPrint, byte[] clientHello)
{
if (NetEventSource.IsEnabled)
NetEventSource.Enter(this);
@@ -632,7 +632,18 @@ namespace System.Net.Security
X509Certificate localCertificate = null;
bool cachedCred = false;
- if (_sslAuthenticationOptions.CertSelectionDelegate != null)
+ if (_sslAuthenticationOptions.ServerCertSelectionDelegate != null)
+ {
+ string serverIdentity = SniHelper.GetServerName(clientHello);
+ localCertificate = _sslAuthenticationOptions.ServerCertSelectionDelegate(serverIdentity);
+
+ if (localCertificate == null)
+ {
+ throw new AuthenticationException(SR.net_ssl_io_no_server_cert);
+ }
+ }
+ // This probably never gets called as this is a client options delegate
+ else if (_sslAuthenticationOptions.CertSelectionDelegate != null)
{
X509CertificateCollection tempCollection = new X509CertificateCollection();
tempCollection.Add(_sslAuthenticationOptions.ServerCertificate);
@@ -744,7 +755,6 @@ namespace System.Net.Security
#if TRACE_VERBOSE
if (NetEventSource.IsEnabled) NetEventSource.Enter(this, $"_refreshCredentialNeeded = {_refreshCredentialNeeded}");
#endif
-
if (offset < 0 || offset > (input == null ? 0 : input.Length))
{
NetEventSource.Fail(this, "Argument 'offset' out of range.");
@@ -786,7 +796,7 @@ namespace System.Net.Security
if (_refreshCredentialNeeded)
{
cachedCreds = _sslAuthenticationOptions.IsServer
- ? AcquireServerCredentials(ref thumbPrint)
+ ? AcquireServerCredentials(ref thumbPrint, input)
: AcquireClientCredentials(ref thumbPrint);
}
diff --git a/src/System.Net.Security/src/System/Net/Security/SniHelper.cs b/src/System.Net.Security/src/System/Net/Security/SniHelper.cs
new file mode 100644
index 0000000000..b1540f122b
--- /dev/null
+++ b/src/System.Net.Security/src/System/Net/Security/SniHelper.cs
@@ -0,0 +1,391 @@
+// 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.Buffers.Binary;
+using System.Globalization;
+using System.Text;
+
+namespace System.Net.Security
+{
+ internal class SniHelper
+ {
+ private const int ProtocolVersionSize = 2;
+ private const int UInt24Size = 3;
+ private const int RandomSize = 32;
+ private readonly static IdnMapping s_idnMapping = CreateIdnMapping();
+ private readonly static Encoding s_encoding = CreateEncoding();
+
+ public static string GetServerName(byte[] clientHello)
+ {
+ return GetSniFromSslPlainText(clientHello);
+ }
+
+ private static string GetSniFromSslPlainText(ReadOnlySpan<byte> sslPlainText)
+ {
+ // https://tools.ietf.org/html/rfc6101#section-5.2.1
+ // struct {
+ // ContentType type; // enum with max value 255
+ // ProtocolVersion version; // 2x uint8
+ // uint16 length;
+ // opaque fragment[SSLPlaintext.length];
+ // } SSLPlaintext;
+ const int ContentTypeOffset = 0;
+ const int ProtocolVersionOffset = ContentTypeOffset + sizeof(ContentType);
+ const int LengthOffset = ProtocolVersionOffset + ProtocolVersionSize;
+ const int HandshakeOffset = LengthOffset + sizeof(ushort);
+
+ // SSL v2's ContentType has 0x80 bit set.
+ // We do not care about SSL v2 here because it does not support client hello extensions
+ if (sslPlainText.Length < HandshakeOffset || (ContentType)sslPlainText[ContentTypeOffset] != ContentType.Handshake)
+ {
+ return null;
+ }
+
+ // Skip ContentType and ProtocolVersion
+ int handshakeLength = BinaryPrimitives.ReadUInt16BigEndian(sslPlainText.Slice(LengthOffset));
+ ReadOnlySpan<byte> sslHandshake = sslPlainText.Slice(HandshakeOffset);
+
+ if (handshakeLength != sslHandshake.Length)
+ {
+ return null;
+ }
+
+ return GetSniFromSslHandshake(sslHandshake);
+ }
+
+ private static string GetSniFromSslHandshake(ReadOnlySpan<byte> sslHandshake)
+ {
+ // https://tools.ietf.org/html/rfc6101#section-5.6
+ // struct {
+ // HandshakeType msg_type; /* handshake type */
+ // uint24 length; /* bytes in message */
+ // select (HandshakeType) {
+ // ...
+ // case client_hello: ClientHello;
+ // ...
+ // } body;
+ // } Handshake;
+ const int HandshakeTypeOffset = 0;
+ const int ClientHelloLengthOffset = HandshakeTypeOffset + sizeof(HandshakeType);
+ const int ClientHelloOffset = ClientHelloLengthOffset + UInt24Size;
+
+ if (sslHandshake.Length < ClientHelloOffset || (HandshakeType)sslHandshake[HandshakeTypeOffset] != HandshakeType.ClientHello)
+ {
+ return null;
+ }
+
+ int clientHelloLength = ReadUInt24BigEndian(sslHandshake.Slice(ClientHelloLengthOffset));
+ ReadOnlySpan<byte> clientHello = sslHandshake.Slice(ClientHelloOffset);
+
+ if (clientHello.Length != clientHelloLength)
+ {
+ return null;
+ }
+
+ return GetSniFromClientHello(clientHello);
+ }
+
+ private static string GetSniFromClientHello(ReadOnlySpan<byte> clientHello)
+ {
+ // Basic structure: https://tools.ietf.org/html/rfc6101#section-5.6.1.2
+ // Extended structure: https://tools.ietf.org/html/rfc3546#section-2.1
+ // struct {
+ // ProtocolVersion client_version; // 2x uint8
+ // Random random; // 32 bytes
+ // SessionID session_id; // opaque type
+ // CipherSuite cipher_suites<2..2^16-1>; // opaque type
+ // CompressionMethod compression_methods<1..2^8-1>; // opaque type
+ // Extension client_hello_extension_list<0..2^16-1>;
+ // } ClientHello;
+ ReadOnlySpan<byte> p = SkipBytes(clientHello, ProtocolVersionSize + RandomSize);
+
+ // Skip SessionID (max size 32 => size fits in 1 byte)
+ p = SkipOpaqueType1(p);
+
+ // Skip cipher suites (max size 2^16-1 => size fits in 2 bytes)
+ p = SkipOpaqueType2(p, out _);
+
+ // Skip compression methods (max size 2^8-1 => size fits in 1 byte)
+ p = SkipOpaqueType1(p);
+
+ // is invalid structure or no extensions?
+ if (p.IsEmpty)
+ {
+ return null;
+ }
+
+ // client_hello_extension_list (max size 2^16-1 => size fits in 2 bytes)
+ int extensionListLength = BinaryPrimitives.ReadUInt16BigEndian(p);
+ p = SkipBytes(p, sizeof(ushort));
+
+ if (extensionListLength != p.Length)
+ {
+ return null;
+ }
+
+ string ret = null;
+ while (!p.IsEmpty)
+ {
+ bool invalid;
+ string sni = GetSniFromExtension(p, out p, out invalid);
+ if (invalid)
+ {
+ return null;
+ }
+
+ if (ret != null && sni != null)
+ {
+ return null;
+ }
+
+ if (sni != null)
+ {
+ ret = sni;
+ }
+ }
+
+ return ret;
+ }
+
+ private static string GetSniFromExtension(ReadOnlySpan<byte> extension, out ReadOnlySpan<byte> remainingBytes, out bool invalid)
+ {
+ // https://tools.ietf.org/html/rfc3546#section-2.3
+ // struct {
+ // ExtensionType extension_type;
+ // opaque extension_data<0..2^16-1>;
+ // } Extension;
+ const int ExtensionDataOffset = sizeof(ExtensionType);
+
+ if (extension.Length < ExtensionDataOffset)
+ {
+ remainingBytes = ReadOnlySpan<byte>.Empty;
+ invalid = true;
+ return null;
+ }
+
+ ExtensionType extensionType = (ExtensionType)BinaryPrimitives.ReadUInt16BigEndian(extension);
+ ReadOnlySpan<byte> extensionData = extension.Slice(ExtensionDataOffset);
+
+ if (extensionType == ExtensionType.ServerName)
+ {
+ return GetSniFromServerNameList(extensionData, out remainingBytes, out invalid);
+ }
+ else
+ {
+ remainingBytes = SkipOpaqueType2(extensionData, out invalid);
+ return null;
+ }
+ }
+
+ private static string GetSniFromServerNameList(ReadOnlySpan<byte> serverNameListExtension, out ReadOnlySpan<byte> remainingBytes, out bool invalid)
+ {
+ // https://tools.ietf.org/html/rfc3546#section-3.1
+ // struct {
+ // ServerName server_name_list<1..2^16-1>
+ // } ServerNameList;
+ // ServerNameList is an opaque type (length of sufficient size for max data length is prepended)
+ const int ServerNameListOffset = sizeof(ushort);
+
+ if (serverNameListExtension.Length < ServerNameListOffset)
+ {
+ remainingBytes = ReadOnlySpan<byte>.Empty;
+ invalid = true;
+ return null;
+ }
+
+ int serverNameListLength = BinaryPrimitives.ReadUInt16BigEndian(serverNameListExtension);
+ ReadOnlySpan<byte> serverNameList = serverNameListExtension.Slice(ServerNameListOffset);
+
+ if (serverNameListLength > serverNameList.Length)
+ {
+ remainingBytes = ReadOnlySpan<byte>.Empty;
+ invalid = true;
+ return null;
+ }
+
+ remainingBytes = serverNameList.Slice(serverNameListLength);
+ ReadOnlySpan<byte> serverName = serverNameList.Slice(0, serverNameListLength);
+
+ return GetSniFromServerName(serverName, out invalid);
+ }
+
+ private static string GetSniFromServerName(ReadOnlySpan<byte> serverName, out bool invalid)
+ {
+ // https://tools.ietf.org/html/rfc3546#section-3.1
+ // struct {
+ // NameType name_type;
+ // select (name_type) {
+ // case host_name: HostName;
+ // } name;
+ // } ServerName;
+ // ServerName is an opaque type (length of sufficient size for max data length is prepended)
+ const int ServerNameLengthOffset = 0;
+ const int NameTypeOffset = ServerNameLengthOffset + sizeof(ushort);
+ const int HostNameStructOffset = NameTypeOffset + sizeof(NameType);
+
+ if (serverName.Length < HostNameStructOffset)
+ {
+ invalid = true;
+ return null;
+ }
+
+ // Following can underflow but it is ok due to equality check below
+ int hostNameStructLength = BinaryPrimitives.ReadUInt16BigEndian(serverName) - sizeof(NameType);
+ NameType nameType = (NameType)serverName[NameTypeOffset];
+ ReadOnlySpan<byte> hostNameStruct = serverName.Slice(HostNameStructOffset);
+
+ if (hostNameStructLength != hostNameStruct.Length || nameType != NameType.HostName)
+ {
+ invalid = true;
+ return null;
+ }
+
+ return GetSniFromHostNameStruct(hostNameStruct, out invalid);
+ }
+
+ private static string GetSniFromHostNameStruct(ReadOnlySpan<byte> hostNameStruct, out bool invalid)
+ {
+ // https://tools.ietf.org/html/rfc3546#section-3.1
+ // HostName is an opaque type (length of sufficient size for max data length is prepended)
+ const int HostNameLengthOffset = 0;
+ const int HostNameOffset = HostNameLengthOffset + sizeof(ushort);
+
+ int hostNameLength = BinaryPrimitives.ReadUInt16BigEndian(hostNameStruct);
+ ReadOnlySpan<byte> hostName = hostNameStruct.Slice(HostNameOffset);
+ if (hostNameLength != hostName.Length)
+ {
+ invalid = true;
+ return null;
+ }
+
+ invalid = false;
+ return DecodeString(hostName);
+ }
+
+ private static string DecodeString(ReadOnlySpan<byte> bytes)
+ {
+ // https://tools.ietf.org/html/rfc3546#section-3.1
+ // Per spec:
+ // If the hostname labels contain only US-ASCII characters, then the
+ // client MUST ensure that labels are separated only by the byte 0x2E,
+ // representing the dot character U+002E (requirement 1 in section 3.1
+ // of [IDNA] notwithstanding). If the server needs to match the HostName
+ // against names that contain non-US-ASCII characters, it MUST perform
+ // the conversion operation described in section 4 of [IDNA], treating
+ // the HostName as a "query string" (i.e. the AllowUnassigned flag MUST
+ // be set). Note that IDNA allows labels to be separated by any of the
+ // Unicode characters U+002E, U+3002, U+FF0E, and U+FF61, therefore
+ // servers MUST accept any of these characters as a label separator. If
+ // the server only needs to match the HostName against names containing
+ // exclusively ASCII characters, it MUST compare ASCII names case-
+ // insensitively.
+
+ string idnEncodedString;
+ try
+ {
+ idnEncodedString = s_encoding.GetString(bytes);
+ }
+ catch (DecoderFallbackException)
+ {
+ return null;
+ }
+
+ try
+ {
+ return s_idnMapping.GetUnicode(idnEncodedString);
+ }
+ catch (ArgumentException)
+ {
+ // client has not done IDN mapping
+ return idnEncodedString;
+ }
+ }
+
+ private static int ReadUInt24BigEndian(ReadOnlySpan<byte> bytes)
+ {
+ return (bytes[0] << 16) | (bytes[1] << 8) | bytes[2];
+ }
+
+ private static ReadOnlySpan<byte> SkipBytes(ReadOnlySpan<byte> bytes, int numberOfBytesToSkip)
+ {
+ return (numberOfBytesToSkip < bytes.Length) ? bytes.Slice(numberOfBytesToSkip) : ReadOnlySpan<byte>.Empty;
+ }
+
+ // Opaque type is of structure:
+ // - length (minimum number of bytes to hold the max value)
+ // - data (length bytes)
+ // We will only use opaque types which are of max size: 255 (length = 1) or 2^16-1 (length = 2).
+ // We will call them SkipOpaqueType`length`
+ private static ReadOnlySpan<byte> SkipOpaqueType1(ReadOnlySpan<byte> bytes)
+ {
+ const int OpaqueTypeLengthSize = sizeof(byte);
+ if (bytes.Length < OpaqueTypeLengthSize)
+ {
+ return ReadOnlySpan<byte>.Empty;
+ }
+
+ byte length = bytes[0];
+ int totalBytes = OpaqueTypeLengthSize + length;
+
+ return SkipBytes(bytes, totalBytes);
+ }
+
+ private static ReadOnlySpan<byte> SkipOpaqueType2(ReadOnlySpan<byte> bytes, out bool invalid)
+ {
+ const int OpaqueTypeLengthSize = sizeof(ushort);
+ if (bytes.Length < OpaqueTypeLengthSize)
+ {
+ invalid = true;
+ return ReadOnlySpan<byte>.Empty;
+ }
+
+ ushort length = BinaryPrimitives.ReadUInt16BigEndian(bytes);
+ int totalBytes = OpaqueTypeLengthSize + length;
+
+ invalid = bytes.Length < totalBytes;
+ if (invalid)
+ {
+ return ReadOnlySpan<byte>.Empty;
+ }
+ else
+ {
+ return bytes.Slice(totalBytes);
+ }
+ }
+
+ private static IdnMapping CreateIdnMapping()
+ {
+ return new IdnMapping()
+ {
+ // Per spec "AllowUnassigned flag MUST be set". See comment above GetSniFromServerNameList for more details.
+ AllowUnassigned = true
+ };
+ }
+
+ private static Encoding CreateEncoding()
+ {
+ return Encoding.GetEncoding("utf-8", new EncoderExceptionFallback(), new DecoderExceptionFallback());
+ }
+
+ private enum ContentType : byte
+ {
+ Handshake = 0x16
+ }
+
+ private enum HandshakeType : byte
+ {
+ ClientHello = 0x01
+ }
+
+ private enum ExtensionType : ushort
+ {
+ ServerName = 0x00
+ }
+
+ private enum NameType : byte
+ {
+ HostName = 0x00
+ }
+ }
+}
diff --git a/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs b/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs
index 5fede486d1..73741757fd 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs
@@ -37,7 +37,6 @@ namespace System.Net.Security
// Common options.
AllowRenegotiation = sslServerAuthenticationOptions.AllowRenegotiation;
ApplicationProtocols = sslServerAuthenticationOptions.ApplicationProtocols;
- CertValidationDelegate = sslServerAuthenticationOptions._certValidationDelegate;
CheckCertName = false;
EnabledSslProtocols = sslServerAuthenticationOptions.EnabledSslProtocols;
EncryptionPolicy = sslServerAuthenticationOptions.EncryptionPolicy;
@@ -66,6 +65,7 @@ namespace System.Net.Security
internal bool CheckCertName { get; set; }
internal RemoteCertValidationCallback CertValidationDelegate { get; set; }
internal LocalCertSelectionCallback CertSelectionDelegate { get; set; }
+ internal ServerCertSelectionCallback ServerCertSelectionDelegate { get; set; }
}
}
diff --git a/src/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs b/src/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs
index cf5b271a10..5b3935ba07 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs
@@ -15,8 +15,6 @@ namespace System.Net.Security
private EncryptionPolicy _encryptionPolicy = EncryptionPolicy.RequireEncryption;
private bool _allowRenegotiation = true;
- internal RemoteCertValidationCallback _certValidationDelegate;
-
public bool AllowRenegotiation
{
get => _allowRenegotiation;
@@ -29,6 +27,8 @@ namespace System.Net.Security
public RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; }
+ public ServerCertificateSelectionCallback ServerCertificateSelectionCallback { get; set; }
+
public X509Certificate ServerCertificate { get; set; }
public SslProtocols EnabledSslProtocols
diff --git a/src/System.Net.Security/src/System/Net/Security/SslState.cs b/src/System.Net.Security/src/System/Net/Security/SslState.cs
index 0e08a47427..9c60b706cc 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslState.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslState.cs
@@ -132,7 +132,7 @@ namespace System.Net.Security
}
}
- internal void ValidateCreateContext(SslServerAuthenticationOptions sslServerAuthenticationOptions)
+ internal void ValidateCreateContext(SslAuthenticationOptions sslAuthenticationOptions)
{
ThrowIfExceptional();
@@ -146,15 +146,11 @@ namespace System.Net.Security
throw new InvalidOperationException(SR.net_auth_client_server);
}
- if (sslServerAuthenticationOptions.ServerCertificate == null)
- {
- throw new ArgumentNullException(nameof(sslServerAuthenticationOptions.ServerCertificate));
- }
-
_exception = null;
+ _sslAuthenticationOptions = sslAuthenticationOptions;
+
try
{
- _sslAuthenticationOptions = new SslAuthenticationOptions(sslServerAuthenticationOptions);
_context = new SecureChannel(_sslAuthenticationOptions);
}
catch (Win32Exception e)
diff --git a/src/System.Net.Security/src/System/Net/Security/SslStream.cs b/src/System.Net.Security/src/System/Net/Security/SslStream.cs
index a4ff6d8c05..941a064ead 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslStream.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslStream.cs
@@ -31,9 +31,12 @@ namespace System.Net.Security
// A user delegate used to select local SSL certificate.
public delegate X509Certificate LocalCertificateSelectionCallback(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers);
+ public delegate X509Certificate ServerCertificateSelectionCallback(object sender, string hostName);
+
// Internal versions of the above delegates.
internal delegate bool RemoteCertValidationCallback(string host, X509Certificate2 certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors);
internal delegate X509Certificate LocalCertSelectionCallback(string targetHost, X509CertificateCollection localCertificates, X509Certificate2 remoteCertificate, string[] acceptableIssuers);
+ internal delegate X509Certificate ServerCertSelectionCallback(string hostName);
public class SslStream : AuthenticatedStream
{
@@ -42,6 +45,7 @@ namespace System.Net.Security
internal RemoteCertificateValidationCallback _userCertificateValidationCallback;
internal LocalCertificateSelectionCallback _userCertificateSelectionCallback;
+ internal ServerCertificateSelectionCallback _userServerCertificateSelectionCallback;
internal RemoteCertValidationCallback _certValidationDelegate;
internal LocalCertSelectionCallback _certSelectionDelegate;
internal EncryptionPolicy _encryptionPolicy;
@@ -141,6 +145,33 @@ namespace System.Net.Security
return _userCertificateSelectionCallback(this, targetHost, localCertificates, remoteCertificate, acceptableIssuers);
}
+ private X509Certificate ServerCertSelectionCallbackWrapper(string targetHost)
+ {
+ return _userServerCertificateSelectionCallback(this, targetHost);
+ }
+
+ private SslAuthenticationOptions CreateAuthenticationOptions(SslServerAuthenticationOptions sslServerAuthenticationOptions)
+ {
+ if (sslServerAuthenticationOptions.ServerCertificate == null && sslServerAuthenticationOptions.ServerCertificateSelectionCallback == null)
+ {
+ throw new ArgumentNullException(nameof(sslServerAuthenticationOptions.ServerCertificate));
+ }
+
+ if (sslServerAuthenticationOptions.ServerCertificate != null && sslServerAuthenticationOptions.ServerCertificateSelectionCallback != null)
+ {
+ throw new InvalidOperationException(SR.Format(SR.net_conflicting_options, nameof(ServerCertificateSelectionCallback)));
+ }
+
+ var authOptions = new SslAuthenticationOptions(sslServerAuthenticationOptions);
+
+ _userServerCertificateSelectionCallback = sslServerAuthenticationOptions.ServerCertificateSelectionCallback;
+ authOptions.ServerCertSelectionDelegate = _userServerCertificateSelectionCallback == null ? null : new ServerCertSelectionCallback(ServerCertSelectionCallbackWrapper);
+
+ authOptions.CertValidationDelegate = _certValidationDelegate;
+
+ return authOptions;
+ }
+
//
// Client side auth.
//
@@ -174,7 +205,6 @@ namespace System.Net.Security
internal virtual IAsyncResult BeginAuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken, AsyncCallback asyncCallback, object asyncState)
{
- SecurityProtocol.ThrowOnNotAllowed(sslClientAuthenticationOptions.EnabledSslProtocols);
SetAndVerifyValidationCallback(sslClientAuthenticationOptions.RemoteCertificateValidationCallback);
SetAndVerifySelectionCallback(sslClientAuthenticationOptions.LocalCertificateSelectionCallback);
@@ -226,13 +256,9 @@ namespace System.Net.Security
private IAsyncResult BeginAuthenticateAsServer(SslServerAuthenticationOptions sslServerAuthenticationOptions, CancellationToken cancellationToken, AsyncCallback asyncCallback, object asyncState)
{
- SecurityProtocol.ThrowOnNotAllowed(sslServerAuthenticationOptions.EnabledSslProtocols);
SetAndVerifyValidationCallback(sslServerAuthenticationOptions.RemoteCertificateValidationCallback);
- // Set the delegate on the options.
- sslServerAuthenticationOptions._certValidationDelegate = _certValidationDelegate;
-
- _sslState.ValidateCreateContext(sslServerAuthenticationOptions);
+ _sslState.ValidateCreateContext(CreateAuthenticationOptions(sslServerAuthenticationOptions));
LazyAsyncResult result = new LazyAsyncResult(_sslState, asyncState, asyncCallback);
_sslState.ProcessAuthentication(result);
@@ -294,7 +320,6 @@ namespace System.Net.Security
private void AuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions)
{
- SecurityProtocol.ThrowOnNotAllowed(sslClientAuthenticationOptions.EnabledSslProtocols);
SetAndVerifyValidationCallback(sslClientAuthenticationOptions.RemoteCertificateValidationCallback);
SetAndVerifySelectionCallback(sslClientAuthenticationOptions.LocalCertificateSelectionCallback);
@@ -328,13 +353,9 @@ namespace System.Net.Security
private void AuthenticateAsServer(SslServerAuthenticationOptions sslServerAuthenticationOptions)
{
- SecurityProtocol.ThrowOnNotAllowed(sslServerAuthenticationOptions.EnabledSslProtocols);
SetAndVerifyValidationCallback(sslServerAuthenticationOptions.RemoteCertificateValidationCallback);
- // Set the delegate on the options.
- sslServerAuthenticationOptions._certValidationDelegate = _certValidationDelegate;
-
- _sslState.ValidateCreateContext(sslServerAuthenticationOptions);
+ _sslState.ValidateCreateContext(CreateAuthenticationOptions(sslServerAuthenticationOptions));
_sslState.ProcessAuthentication(null);
}
#endregion
diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs
index 399d1c3750..1217c710fe 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs
@@ -467,9 +467,8 @@ namespace System.Net.Security
return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential);
});
}
- catch (Exception ex)
+ catch
{
- Debug.Fail("AcquireCredentialsHandle failed.", ex.ToString());
return SSPIWrapper.AcquireCredentialsHandle(GlobalSSPI.SSPISecureChannel, SecurityPackage, credUsage, secureCredential);
}
}
diff --git a/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs b/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs
index 4739156715..d11df7b8af 100644
--- a/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs
+++ b/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs
@@ -55,15 +55,18 @@ namespace System.Net.Security.Tests
await ClientAsyncSslHelper(protocol, protocol);
}
- [Theory]
- [ClassData(typeof(SslProtocolSupport.UnsupportedSslProtocolsTestData))]
- [ActiveIssue(16534, TestPlatforms.Windows)]
- public async Task ClientAsyncAuthenticate_EachClientUnsupportedProtocol_Fail(SslProtocols protocol)
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public async Task ClientAsyncAuthenticate_Ssl2WithSelf_Success()
{
- await Assert.ThrowsAsync<NotSupportedException>(() =>
+ // Test Ssl2 against itself. This is a standalone test as even on versions where Windows supports Ssl2,
+ // it appears to have rules around not using it when other protocols are mentioned.
+ if (!PlatformDetection.IsWindows10Version1607OrGreater)
{
- return ClientAsyncSslHelper(protocol, SslProtocolSupport.SupportedSslProtocols);
- });
+#pragma warning disable 0618
+ await ClientAsyncSslHelper(SslProtocols.Ssl2, SslProtocols.Ssl2);
+#pragma warning restore 0618
+ }
}
[Theory]
@@ -74,7 +77,9 @@ namespace System.Net.Security.Tests
SslProtocols clientProtocol,
Type expectedException)
{
- await Assert.ThrowsAsync(expectedException, () => ClientAsyncSslHelper(serverProtocol, clientProtocol));
+ Exception e = await Record.ExceptionAsync(() => ClientAsyncSslHelper(serverProtocol, clientProtocol));
+ Assert.NotNull(e);
+ Assert.IsAssignableFrom(expectedException, e);
}
[Fact]
@@ -86,18 +91,6 @@ namespace System.Net.Security.Tests
SslProtocolSupport.SupportedSslProtocols);
}
- [Fact]
- [ActiveIssue(16534, TestPlatforms.Windows)]
- public async Task ClientAsyncAuthenticate_UnsupportedAllClient_Fail()
- {
- await Assert.ThrowsAsync<NotSupportedException>(() =>
- {
- return ClientAsyncSslHelper(
- SslProtocolSupport.UnsupportedSslProtocols,
- SslProtocolSupport.SupportedSslProtocols);
- });
- }
-
[Theory]
[ClassData(typeof(SslProtocolSupport.SupportedSslProtocolsTestData))]
[ActiveIssue(16534, TestPlatforms.Windows)]
@@ -120,6 +113,11 @@ namespace System.Net.Security.Tests
private static IEnumerable<object[]> ProtocolMismatchData()
{
+#pragma warning disable 0618
+ yield return new object[] { SslProtocols.Ssl2, SslProtocols.Ssl3, typeof(Exception) };
+ yield return new object[] { SslProtocols.Ssl2, SslProtocols.Tls12, typeof(Exception) };
+ yield return new object[] { SslProtocols.Ssl3, SslProtocols.Tls12, typeof(Exception) };
+#pragma warning restore 0618
yield return new object[] { SslProtocols.Tls, SslProtocols.Tls11, typeof(IOException) };
yield return new object[] { SslProtocols.Tls, SslProtocols.Tls12, typeof(IOException) };
yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls, typeof(AuthenticationException) };
diff --git a/src/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs b/src/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs
index fd01c39fbb..c91a0775c5 100644
--- a/src/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs
+++ b/src/System.Net.Security/tests/FunctionalTests/ServerAsyncAuthenticateTest.cs
@@ -3,9 +3,9 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.ComponentModel;
using System.Net.Sockets;
using System.Net.Test.Common;
-using System.Runtime.ExceptionServices;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
@@ -42,20 +42,6 @@ namespace System.Net.Security.Tests
await ServerAsyncSslHelper(protocol, protocol);
}
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "These protocols are explicitly disabled on .NET Core but still supported on .NET Framework.")]
- [Theory]
- [ClassData(typeof(SslProtocolSupport.UnsupportedSslProtocolsTestData))]
- public async Task ServerAsyncAuthenticate_EachServerUnsupportedProtocol_Fail(SslProtocols protocol)
- {
- await Assert.ThrowsAsync<NotSupportedException>(() =>
- {
- return ServerAsyncSslHelper(
- SslProtocolSupport.SupportedSslProtocols,
- protocol,
- expectedToFail: true);
- });
- }
-
[Theory]
[MemberData(nameof(ProtocolMismatchData))]
public async Task ServerAsyncAuthenticate_MismatchProtocols_Fails(
@@ -63,8 +49,7 @@ namespace System.Net.Security.Tests
SslProtocols clientProtocol,
Type expectedException)
{
- await Assert.ThrowsAsync(
- expectedException,
+ Exception e = await Record.ExceptionAsync(
() =>
{
return ServerAsyncSslHelper(
@@ -72,19 +57,9 @@ namespace System.Net.Security.Tests
clientProtocol,
expectedToFail: true);
});
- }
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "These protocols are explicitly disabled on .NET Core but still supported on .NET Framework.")]
- [Fact]
- public async Task ServerAsyncAuthenticate_UnsupportedAllServer_Fail()
- {
- await Assert.ThrowsAsync<NotSupportedException>(() =>
- {
- return ServerAsyncSslHelper(
- SslProtocolSupport.SupportedSslProtocols,
- SslProtocolSupport.UnsupportedSslProtocols,
- expectedToFail: true);
- });
+ Assert.NotNull(e);
+ Assert.IsAssignableFrom(expectedException, e);
}
[Theory]
@@ -97,6 +72,11 @@ namespace System.Net.Security.Tests
private static IEnumerable<object[]> ProtocolMismatchData()
{
+#pragma warning disable 0618
+ yield return new object[] { SslProtocols.Ssl2, SslProtocols.Ssl3, typeof(Exception) };
+ yield return new object[] { SslProtocols.Ssl2, SslProtocols.Tls12, typeof(Exception) };
+ yield return new object[] { SslProtocols.Ssl3, SslProtocols.Tls12, typeof(Exception) };
+#pragma warning restore 0618
yield return new object[] { SslProtocols.Tls, SslProtocols.Tls11, typeof(AuthenticationException) };
yield return new object[] { SslProtocols.Tls, SslProtocols.Tls12, typeof(AuthenticationException) };
yield return new object[] { SslProtocols.Tls11, SslProtocols.Tls, typeof(TimeoutException) };
diff --git a/src/System.Net.Security/tests/FunctionalTests/SniHelperTest.cs b/src/System.Net.Security/tests/FunctionalTests/SniHelperTest.cs
new file mode 100644
index 0000000000..3dafcc083f
--- /dev/null
+++ b/src/System.Net.Security/tests/FunctionalTests/SniHelperTest.cs
@@ -0,0 +1,3255 @@
+// 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.Generic;
+using System.Linq;
+using Xunit;
+
+namespace System.Net.Security.Tests
+{
+ public class SniHelperTest
+ {
+ [Fact]
+ public void SniHelper_ValidData_Ok()
+ {
+ InvalidClientHello(s_validClientHello, -1, shouldPass: true);
+ }
+
+ [Theory]
+ [MemberData(nameof(InvalidClientHelloData))]
+ public void SniHelper_InvalidData_Fails(int id, byte[] clientHello)
+ {
+ InvalidClientHello(clientHello, id, shouldPass: false);
+ }
+
+ [Theory]
+ [MemberData(nameof(InvalidClientHelloDataTruncatedBytes))]
+ public void SniHelper_TruncatedData_Fails(int id, byte[] clientHello)
+ {
+ InvalidClientHello(clientHello, id, shouldPass: false);
+ }
+
+ private void InvalidClientHello(byte[] clientHello, int id, bool shouldPass)
+ {
+ string ret = SniHelper.GetServerName(clientHello);
+ if (shouldPass)
+ Assert.NotNull(ret);
+ else
+ Assert.Null(ret);
+ }
+
+ private static IEnumerable<object[]> InvalidClientHelloData()
+ {
+ int id = 0;
+ foreach (byte[] invalidClientHello in InvalidClientHello())
+ {
+ id++;
+ yield return new object[] { id, invalidClientHello };
+ }
+ }
+
+ private static IEnumerable<object[]> InvalidClientHelloDataTruncatedBytes()
+ {
+ // converting to base64 first to remove duplicated test cases
+ var uniqueInvalidHellos = new HashSet<string>();
+ foreach (byte[] invalidClientHello in InvalidClientHello())
+ {
+ for (int i = 0; i < invalidClientHello.Length - 1; i++)
+ {
+ uniqueInvalidHellos.Add(Convert.ToBase64String(invalidClientHello.Take(i).ToArray()));
+ }
+ }
+
+ for (int i = 0; i < s_validClientHello.Length - 1; i++)
+ {
+ uniqueInvalidHellos.Add(Convert.ToBase64String(s_validClientHello.Take(i).ToArray()));
+ }
+
+ int id = 0;
+ foreach (string invalidClientHello in uniqueInvalidHellos)
+ {
+ id++;
+ yield return new object[] { id, Convert.FromBase64String(invalidClientHello) };
+ }
+ }
+
+ private static byte[] s_validClientHello = new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x0C, 0x3C, 0x85, 0x78, 0xCA,
+ 0x67, 0x70, 0xAA, 0x38, 0xCB,
+ 0x28, 0xBC, 0xDC, 0x3E, 0x30,
+ 0xBF, 0x11, 0x96, 0x95, 0x1A,
+ 0xB9, 0xF0, 0x99, 0xA4, 0x91,
+ 0x09, 0x13, 0xB4, 0x89, 0x94,
+ 0x27, 0x2E,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ private static IEnumerable<byte[]> InvalidClientHello()
+ {
+ // This test covers following test cases:
+ // - Length of structure off by 1 (search for "length off by 1")
+ // - Length of structure is max length (search for "max length")
+ // - Type is invalid or unknown (i.e. SslPlainText.ClientType is not 0x16 - search for "unknown")
+ // - Invalid utf-8 characters
+ // in each case sni will be null or will cause parsing error - we only expect some parsing errors,
+ // anything else is considered a bug
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01 - length off by 1
+ 0x00, 0x02, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01 - max length
+ 0xFF, 0xFF, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17 - length off by 1
+ 0x00, 0x01,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17 - max length
+ 0xFF, 0xFF,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23 - length off by 1
+ 0x00, 0x01,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23 - max length
+ 0xFF, 0xFF,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D - length off by 1
+ 0x00, 0x15, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D - max length
+ 0xFF, 0xFF, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B - length off by 1
+ 0x00, 0x03, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B - max length
+ 0xFF, 0xFF, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A - length off by 1
+ 0x00, 0x09, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A - max length
+ 0xFF, 0xFF, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length - length off by 1
+ 0x00, 0x35,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length - max length
+ 0xFF, 0xFF,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type - unknown
+ 0x01,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length - length off by 1
+ 0x00, 0x38,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length - max length
+ 0xFF, 0xFF,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length - length off by 1
+ 0x00, 0x3A,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length - max length
+ 0xFF, 0xFF,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name) - unknown
+ 0x01, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length - length off by 1
+ 0x00, 0x75,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length - max length
+ 0xFF, 0xFF,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods - length off by 1
+ 0x02, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods - max length
+ 0xFF, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites - length off by 1
+ 0x00, 0x2B, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites - max length
+ 0xFF, 0xFF, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId - length off by 1
+ 0x01,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId - max length
+ 0xFF,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length - length off by 1
+ 0x00, 0x00, 0xC8,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length - max length
+ 0xFF, 0xFF, 0xFF,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello) - unknown
+ 0x00,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length - length off by 1
+ 0x00, 0xCC,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length - max length
+ 0xFF, 0xFF,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion) - unknown
+ 0x01, 0x03, 0x04,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x58, 0xAA, 0x5F, 0xE7, 0x22,
+ 0xCF, 0x9F, 0x59, 0x8A, 0xC5,
+ 0x8B, 0x87, 0xC7, 0x62, 0x32,
+ 0x98, 0xD4, 0xD8, 0xA2, 0xBE,
+ 0x77, 0xCE, 0xA9, 0xCE, 0x42,
+ 0x25, 0x5A, 0x8B, 0xEE, 0x16,
+ 0x80, 0xF1,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+
+ yield return new byte[] {
+ // SslPlainText.(ContentType+ProtocolVersion)
+ 0x16, 0x03, 0x03,
+ // SslPlainText.length
+ 0x00, 0xCB,
+ // Handshake.msg_type (client hello)
+ 0x01,
+ // Handshake.length
+ 0x00, 0x00, 0xC7,
+ // ClientHello.client_version
+ 0x03, 0x03,
+ // ClientHello.random
+ 0x0C, 0x3C, 0x85, 0x78, 0xCA,
+ 0x67, 0x70, 0xAA, 0x38, 0xCB,
+ 0x28, 0xBC, 0xDC, 0x3E, 0x30,
+ 0xBF, 0x11, 0x96, 0x95, 0x1A,
+ 0xB9, 0xF0, 0x99, 0xA4, 0x91,
+ 0x09, 0x13, 0xB4, 0x89, 0x94,
+ 0x27, 0x2E,
+ // ClientHello.SessionId
+ 0x00,
+ // ClientHello.cipher_suites
+ 0x00, 0x2A, 0xC0, 0x2C, 0xC0,
+ 0x2B, 0xC0, 0x30, 0xC0, 0x2F,
+ 0x00, 0x9F, 0x00, 0x9E, 0xC0,
+ 0x24, 0xC0, 0x23, 0xC0, 0x28,
+ 0xC0, 0x27, 0xC0, 0x0A, 0xC0,
+ 0x09, 0xC0, 0x14, 0xC0, 0x13,
+ 0x00, 0x9D, 0x00, 0x9C, 0x00,
+ 0x3D, 0x00, 0x3C, 0x00, 0x35,
+ 0x00, 0x2F, 0x00, 0x0A,
+ // ClientHello.compression_methods
+ 0x01, 0x01,
+ // ClientHello.extension_list_length
+ 0x00, 0x74,
+ // Extension.extension_type (server_name)
+ 0x00, 0x00,
+ // ServerNameListExtension.length
+ 0x00, 0x39,
+ // ServerName.length
+ 0x00, 0x37,
+ // ServerName.type
+ 0x00,
+ // HostName.length
+ 0x00, 0x34,
+ // HostName.bytes
+ 0x80, 0x80, 0x80, 0x80, 0x61, // 0x80 0x80 0x80 0x80 is a forbidden utf-8 sequence
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61,
+ 0x61, 0x61,
+ // Extension.extension_type (00 0A)
+ 0x00, 0x0A,
+ // Extension 0A
+ 0x00, 0x08, 0x00, 0x06, 0x00,
+ 0x1D, 0x00, 0x17, 0x00, 0x18,
+ // Extension.extension_type (00 0B)
+ 0x00, 0x0B,
+ // Extension 0B
+ 0x00, 0x02, 0x01, 0x00,
+ // Extension.extension_type (00 0D)
+ 0x00, 0x0D,
+ // Extension 0D
+ 0x00, 0x14, 0x00, 0x12, 0x04,
+ 0x01, 0x05, 0x01, 0x02, 0x01,
+ 0x04, 0x03, 0x05, 0x03, 0x02,
+ 0x03, 0x02, 0x02, 0x06, 0x01,
+ 0x06, 0x03,
+ // Extension.extension_type (00 23)
+ 0x00, 0x23,
+ // Extension 00 23
+ 0x00, 0x00,
+ // Extension.extension_type (00 17)
+ 0x00, 0x17,
+ // Extension 17
+ 0x00, 0x00,
+ // Extension.extension_type (FF 01)
+ 0xFF, 0x01,
+ // Extension FF01
+ 0x00, 0x01, 0x00
+ };
+ }
+ }
+}
diff --git a/src/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs b/src/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs
new file mode 100644
index 0000000000..55cf3e9483
--- /dev/null
+++ b/src/System.Net.Security/tests/FunctionalTests/SslStreamSniTest.cs
@@ -0,0 +1,135 @@
+// 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.Generic;
+using System.Net.Test.Common;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Net.Security.Tests
+{
+ using Configuration = System.Net.Test.Common.Configuration;
+
+ public class SslStreamSniTest
+ {
+ [Theory]
+ [MemberData(nameof(HostNameData))]
+ public void SslStream_ClientSendsSNIServerReceives_Ok(string hostName)
+ {
+ X509Certificate serverCert = Configuration.Certificates.GetSelfSignedServerCertificate();
+
+ WithVirtualConnection((server, client) =>
+ {
+ Task clientJob = Task.Run(() => {
+ client.AuthenticateAsClient(hostName);
+ });
+
+ SslServerAuthenticationOptions options = DefaultServerOptions();
+
+ int timesCallbackCalled = 0;
+ options.ServerCertificateSelectionCallback = (sender, actualHostName) =>
+ {
+ timesCallbackCalled++;
+ Assert.Equal(hostName, actualHostName);
+ return serverCert;
+ };
+
+ var cts = new CancellationTokenSource();
+ server.AuthenticateAsServerAsync(options, cts.Token).Wait();
+
+ Assert.Equal(1, timesCallbackCalled);
+ clientJob.Wait();
+ },
+ (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
+ {
+ Assert.Equal(serverCert, certificate);
+ return true;
+ });
+ }
+
+ [Fact]
+ public void SslStream_NoSniFromClient_CallbackReturnsNull()
+ {
+ WithVirtualConnection((server, client) =>
+ {
+ Task clientJob = Task.Run(() => {
+ Assert.Throws<VirtualNetwork.VirtualNetworkConnectionBroken>(()
+ => client.AuthenticateAsClient("test"));
+ });
+
+ int timesCallbackCalled = 0;
+ SslServerAuthenticationOptions options = DefaultServerOptions();
+ options.ServerCertificateSelectionCallback = (sender, actualHostName) =>
+ {
+ timesCallbackCalled++;
+ return null;
+ };
+
+ var cts = new CancellationTokenSource();
+ Assert.Throws<AuthenticationException>(WithAggregateExceptionUnwrapping(() =>
+ server.AuthenticateAsServerAsync(options, cts.Token).Wait()
+ ));
+
+ // to break connection so that client is not waiting
+ server.Dispose();
+
+ Assert.Equal(1, timesCallbackCalled);
+
+ clientJob.Wait();
+ },
+ (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
+ {
+ return true;
+ });
+ }
+
+ private static Action WithAggregateExceptionUnwrapping(Action a)
+ {
+ return () => {
+ try
+ {
+ a();
+ }
+ catch (AggregateException e)
+ {
+ throw e.InnerException;
+ }
+ };
+ }
+
+ private static SslServerAuthenticationOptions DefaultServerOptions()
+ {
+ return new SslServerAuthenticationOptions()
+ {
+ ClientCertificateRequired = false,
+ EnabledSslProtocols = SslProtocols.Tls,
+ CertificateRevocationCheckMode = X509RevocationMode.NoCheck,
+ };
+ }
+
+ private void WithVirtualConnection(Action<SslStream, SslStream> serverClientConnection, RemoteCertificateValidationCallback clientCertValidate)
+ {
+ VirtualNetwork vn = new VirtualNetwork();
+ using (VirtualNetworkStream serverStream = new VirtualNetworkStream(vn, isServer: true),
+ clientStream = new VirtualNetworkStream(vn, isServer: false))
+ using (SslStream server = new SslStream(serverStream, leaveInnerStreamOpen: false),
+ client = new SslStream(clientStream, leaveInnerStreamOpen: false, clientCertValidate))
+ {
+ serverClientConnection(server, client);
+ }
+ }
+
+ private static IEnumerable<object[]> HostNameData()
+ {
+ yield return new object[] { "a" };
+ yield return new object[] { "test" };
+ // max allowed hostname length is 63
+ yield return new object[] { new string('a', 63) };
+ yield return new object[] { "\u017C\u00F3\u0142\u0107 g\u0119\u015Bl\u0105 ja\u017A\u0144. \u7EA2\u70E7. \u7167\u308A\u713C\u304D" };
+ }
+ }
+}
diff --git a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs
index ae608d302b..61da0d226e 100644
--- a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs
+++ b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs
@@ -310,7 +310,11 @@ namespace System.Net.Security.Tests
[Fact]
public async Task SslStream_StreamToStream_Dispose_Throws()
{
- VirtualNetwork network = new VirtualNetwork();
+ VirtualNetwork network = new VirtualNetwork()
+ {
+ DisableConnectionBreaking = true
+ };
+
using (var clientStream = new VirtualNetworkStream(network, isServer: false))
using (var serverStream = new VirtualNetworkStream(network, isServer: true))
using (var clientSslStream = new SslStream(clientStream, false, AllowAnyServerCertificate))
diff --git a/src/System.Net.Security/tests/FunctionalTests/SslStreamSystemDefaultsTest.cs b/src/System.Net.Security/tests/FunctionalTests/SslStreamSystemDefaultsTest.cs
index 941d34fce4..311ea12e21 100644
--- a/src/System.Net.Security/tests/FunctionalTests/SslStreamSystemDefaultsTest.cs
+++ b/src/System.Net.Security/tests/FunctionalTests/SslStreamSystemDefaultsTest.cs
@@ -45,37 +45,56 @@ namespace System.Net.Security.Tests
[InlineData(SslProtocols.Tls12, null)]
[InlineData(SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12, null)]
[InlineData(null, SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12)]
+#pragma warning disable 0618
+ [InlineData(SslProtocols.Default, null)]
+ [InlineData(null, SslProtocols.Default)]
+#pragma warning restore 0618
public async Task ClientAndServer_OneOrBothUseDefault_Ok(SslProtocols? clientProtocols, SslProtocols? serverProtocols)
{
- const int SEC_E_BUFFER_TOO_SMALL = unchecked((int)0x80090321);
-
- X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate();
- string serverHost = serverCertificate.GetNameInfo(X509NameType.SimpleName, false);
- var clientCertificates = new X509CertificateCollection();
- clientCertificates.Add(Configuration.Certificates.GetClientCertificate());
-
- var tasks = new Task[2];
- tasks[0] = AuthenticateClientAsync(serverHost, clientCertificates, checkCertificateRevocation: false, protocols: clientProtocols);
- tasks[1] = AuthenticateServerAsync(serverCertificate, clientCertificateRequired: true, checkCertificateRevocation: false, protocols: serverProtocols);
-
- try
+ using (X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate())
+ using (X509Certificate2 clientCertificate = Configuration.Certificates.GetClientCertificate())
{
- await TestConfiguration.WhenAllOrAnyFailedWithTimeout(tasks);
- if (PlatformDetection.IsWindows && PlatformDetection.WindowsVersion >= 10)
+ string serverHost = serverCertificate.GetNameInfo(X509NameType.SimpleName, false);
+ var clientCertificates = new X509CertificateCollection() { clientCertificate };
+
+ await TestConfiguration.WhenAllOrAnyFailedWithTimeout(
+ AuthenticateClientAsync(serverHost, clientCertificates, checkCertificateRevocation: false, protocols: clientProtocols),
+ AuthenticateServerAsync(serverCertificate, clientCertificateRequired: true, checkCertificateRevocation: false, protocols: serverProtocols));
+ if (PlatformDetection.IsWindows && PlatformDetection.WindowsVersion >= 10 &&
+#pragma warning disable 0618
+ clientProtocols.GetValueOrDefault() != SslProtocols.Default &&
+ serverProtocols.GetValueOrDefault() != SslProtocols.Default)
+#pragma warning restore 0618
{
Assert.True(
(_clientStream.SslProtocol == SslProtocols.Tls11 && _clientStream.HashAlgorithm == HashAlgorithmType.Sha1) ||
_clientStream.HashAlgorithm == HashAlgorithmType.Sha256 ||
_clientStream.HashAlgorithm == HashAlgorithmType.Sha384 ||
- _clientStream.HashAlgorithm == HashAlgorithmType.Sha512);
+ _clientStream.HashAlgorithm == HashAlgorithmType.Sha512,
+ _clientStream.SslProtocol + " " + _clientStream.HashAlgorithm);
}
}
- catch (HttpRequestException e) when (e.InnerException?.GetType().Name == "WinHttpException" &&
- e.InnerException.HResult == SEC_E_BUFFER_TOO_SMALL &&
- !PlatformDetection.IsWindows10Version1607OrGreater)
+ }
+
+ [ConditionalTheory(nameof(IsNotWindows7))]
+#pragma warning disable 0618
+ [InlineData(null, SslProtocols.Ssl2)]
+ [InlineData(SslProtocols.None, SslProtocols.Ssl2)]
+ [InlineData(SslProtocols.Ssl2, null)]
+ [InlineData(SslProtocols.Ssl2, SslProtocols.None)]
+#pragma warning restore 0618
+ public async Task ClientAndServer_OneUsesDefault_OtherUsesLowerProtocol_Fails(
+ SslProtocols? clientProtocols, SslProtocols? serverProtocols)
+ {
+ using (X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate())
+ using (X509Certificate2 clientCertificate = Configuration.Certificates.GetClientCertificate())
{
- // Testing on old Windows versions can hit https://github.com/dotnet/corefx/issues/7812
- // Ignore SEC_E_BUFFER_TOO_SMALL error on such cases.
+ string serverHost = serverCertificate.GetNameInfo(X509NameType.SimpleName, false);
+ var clientCertificates = new X509CertificateCollection() { clientCertificate };
+
+ await Assert.ThrowsAnyAsync<Exception>(() => TestConfiguration.WhenAllOrAnyFailedWithTimeout(
+ AuthenticateClientAsync(serverHost, clientCertificates, checkCertificateRevocation: false, protocols: clientProtocols),
+ AuthenticateServerAsync(serverCertificate, clientCertificateRequired: true, checkCertificateRevocation: false, protocols: serverProtocols)));
}
}
diff --git a/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj
index 8268fd077b..c758241a3b 100644
--- a/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj
+++ b/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj
@@ -90,10 +90,15 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)'=='netcoreapp'">
<!-- TODO #13070: Add net463 to the condition after the TFM gets updated to the actual .Net 4.7-->
+ <Compile Include="..\..\src\System\Net\Security\SniHelper.cs">
+ <Link>src\SniHelper.cs</Link>
+ </Compile>
+ <Compile Include="SniHelperTest.cs" />
<Compile Include="SslAuthenticationOptionsTest.cs" />
<Compile Include="SslStreamAlertsTest.cs" />
<Compile Include="SslStreamAllowRenegotiationTests.cs" />
<Compile Include="SslStreamAlpnTests.cs" />
+ <Compile Include="SslStreamSniTest.cs" />
<Compile Include="SslStreamEKUTest.cs" />
<Compile Include="SslStreamSchSendAuxRecordTest.cs" />
<Compile Include="SslStreamCredentialCacheTest.cs" />
@@ -159,4 +164,4 @@
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Net.Security/tests/UnitTests/Fakes/FakeSslState.cs b/src/System.Net.Security/tests/UnitTests/Fakes/FakeSslState.cs
index 9382bd1398..52d650a8a0 100644
--- a/src/System.Net.Security/tests/UnitTests/Fakes/FakeSslState.cs
+++ b/src/System.Net.Security/tests/UnitTests/Fakes/FakeSslState.cs
@@ -25,7 +25,7 @@ namespace System.Net.Security
{
}
- internal void ValidateCreateContext(SslServerAuthenticationOptions sslServerAuthenticationOptions)
+ internal void ValidateCreateContext(SslAuthenticationOptions sslAuthenticationOptions)
{
}
diff --git a/src/System.Net.Security/tests/UnitTests/SslStreamAllowedProtocolsTest.cs b/src/System.Net.Security/tests/UnitTests/SslStreamAllowedProtocolsTest.cs
index b316e129e4..a2229efde9 100644
--- a/src/System.Net.Security/tests/UnitTests/SslStreamAllowedProtocolsTest.cs
+++ b/src/System.Net.Security/tests/UnitTests/SslStreamAllowedProtocolsTest.cs
@@ -19,14 +19,6 @@ namespace System.Net.Security.Tests
string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation);
[Theory]
- [ClassData(typeof(SslProtocolSupport.UnsupportedSslProtocolsTestData))]
- public void SslStream_AuthenticateAsClientAsync_NotSupported_Fails(SslProtocols protocol)
- {
- SslStream stream = new SslStream(new NotImplementedStream());
- Assert.Throws<NotSupportedException>(() => AuthenticateAsClient(stream, false, "host", null, protocol, false));
- }
-
- [Theory]
[ClassData(typeof(SslProtocolSupport.SupportedSslProtocolsTestData))]
public void SslStream_AuthenticateAsClientAsync_Supported_Success(SslProtocols protocol)
{
@@ -43,27 +35,6 @@ namespace System.Net.Security.Tests
}
[Fact]
- public void SslStream_AuthenticateAsClientAsync_Invalid_Fails()
- {
- SslStream stream = new SslStream(new NotImplementedStream());
- Assert.Throws<NotSupportedException>(() => AuthenticateAsClient(stream, false, "host", null, (SslProtocols)4096, false));
- }
-
- [Fact]
- public void SslStream_AuthenticateAsClient_Invalid_Fails()
- {
- SslStream stream = new SslStream(new NotImplementedStream());
- Assert.Throws<NotSupportedException>(() => AuthenticateAsClient(stream, false, "host", null, (SslProtocols)4096, false));
- }
-
- [Fact]
- public void SslStream_AuthenticateAsClientAsync_AllUnsupported_Fails()
- {
- SslStream stream = new SslStream(new NotImplementedStream());
- Assert.Throws<NotSupportedException>(() => AuthenticateAsClient(stream, false, "host", null, SslProtocolSupport.UnsupportedSslProtocols, false));
- }
-
- [Fact]
public void SslStream_AuthenticateAsClientAsync_AllSupported_Success()
{
SslStream stream = new SslStream(new NotImplementedStream());
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs
index 6320ac5d40..ef7a0a0ce6 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs
@@ -266,7 +266,7 @@ namespace System.Net.Sockets
// we can't pool the object, as ProcessQueue may still have a reference to it, due to
// using a pattern whereby it takes the lock to grab an item, but then releases the lock
// to do further processing on the item that's still in the list.
- ThreadPool.QueueUserWorkItem(o => ((AsyncOperation)o).InvokeCallback(allowPooling: false), this);
+ ThreadPool.UnsafeQueueUserWorkItem(o => ((AsyncOperation)o).InvokeCallback(allowPooling: false), this);
}
Trace("Exit");
@@ -837,7 +837,7 @@ namespace System.Net.Sockets
// We just transitioned from Waiting to Processing.
// Spawn a work item to do the actual processing.
- ThreadPool.QueueUserWorkItem(s_processingCallback, context);
+ ThreadPool.UnsafeQueueUserWorkItem(s_processingCallback, context);
}
// Called on the threadpool when data may be available.
@@ -968,7 +968,7 @@ namespace System.Net.Sockets
Debug.Assert(_state == QueueState.Processing);
// Spawn a new work item to continue processing the queue.
- ThreadPool.QueueUserWorkItem(s_processingCallback, context);
+ ThreadPool.UnsafeQueueUserWorkItem(s_processingCallback, context);
}
// At this point, the operation has completed and it's no longer
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs
index 39b503551e..b270ff7c77 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs
@@ -286,11 +286,21 @@ namespace System.Net.Sockets
//
// Start the event loop on its own thread.
//
- Task.Factory.StartNew(
- EventLoop,
- CancellationToken.None,
- TaskCreationOptions.LongRunning,
- TaskScheduler.Default);
+ bool suppressFlow = !ExecutionContext.IsFlowSuppressed();
+ try
+ {
+ if (suppressFlow) ExecutionContext.SuppressFlow();
+ Task.Factory.StartNew(
+ s => ((SocketAsyncEngine)s).EventLoop(),
+ this,
+ CancellationToken.None,
+ TaskCreationOptions.LongRunning,
+ TaskScheduler.Default);
+ }
+ finally
+ {
+ if (suppressFlow) ExecutionContext.RestoreFlow();
+ }
}
catch
{
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
index 0caf582202..ad12b6c911 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
@@ -1053,7 +1053,6 @@ namespace System.Net.Sockets
try
{
Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.Set);
- Debug.Assert(_singleBufferHandle.HasPointer);
bool userBuffer = _count >= _acceptAddressBufferCount;
_currentSocket.GetAcceptExSockaddrs(
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.netcoreapp.cs b/src/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.netcoreapp.cs
index 78f1545426..5fb9e97ecf 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.netcoreapp.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.netcoreapp.cs
@@ -182,7 +182,7 @@ namespace System.Net.Sockets.Tests
[Fact]
public void SetBufferMemory_NonArray_BufferReturnsNull()
{
- using (var m = new NativeOwnedMemory(42))
+ using (var m = new NativeMemoryManager(42))
using (var saea = new SocketAsyncEventArgs())
{
saea.SetBuffer(m.Memory);
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.netcoreapp.cs b/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.netcoreapp.cs
index 3e41627e37..945e905764 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.netcoreapp.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.netcoreapp.cs
@@ -39,7 +39,7 @@ namespace System.Net.Sockets.Tests
public override bool ValidatesArrayArguments => false;
public override async Task<int> ReceiveAsync(Socket s, ArraySegment<byte> buffer)
{
- using (var m = new NativeOwnedMemory(buffer.Count))
+ using (var m = new NativeMemoryManager(buffer.Count))
{
int bytesReceived = await s.ReceiveAsync(m.Memory, SocketFlags.None).ConfigureAwait(false);
m.Memory.Span.Slice(0, bytesReceived).CopyTo(buffer.AsSpan());
@@ -48,7 +48,7 @@ namespace System.Net.Sockets.Tests
}
public override async Task<int> SendAsync(Socket s, ArraySegment<byte> buffer)
{
- using (var m = new NativeOwnedMemory(buffer.Count))
+ using (var m = new NativeMemoryManager(buffer.Count))
{
buffer.AsSpan().CopyTo(m.Memory.Span);
return await s.SendAsync(m.Memory, SocketFlags.None).ConfigureAwait(false);
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj b/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj
index 186d721e72..8ef8f9b4cd 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj
+++ b/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj
@@ -98,8 +98,8 @@
<Compile Include="$(CommonTestPath)\System\Threading\Tasks\TaskTimeoutExtensions.cs">
<Link>Common\System\Threading\Tasks\TaskTimeoutExtensions.cs</Link>
</Compile>
- <Compile Include="$(CommonTestPath)\System\Buffers\NativeOwnedMemory.cs">
- <Link>Common\System\Buffers\NativeOwnedMemory.cs</Link>
+ <Compile Include="$(CommonTestPath)\System\Buffers\NativeMemoryManager.cs">
+ <Link>Common\System\Buffers\NativeMemoryManager.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Threading\Tasks\TaskToApm.cs">
<Link>Common\System\Threading\Tasks\TaskToApm.cs</Link>
diff --git a/src/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.cs b/src/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.cs
index b66dd7b603..87509360b6 100644
--- a/src/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.cs
+++ b/src/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.cs
@@ -5,12 +5,10 @@
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------
-using System.IO;
-
namespace System.Net.WebSockets
{
public static class WebSocketProtocol
{
- public static WebSocket CreateFromStream(Stream stream, bool isServer, string subProtocol, TimeSpan keepAliveInterval, Memory<byte> buffer = default) { throw null; }
+ public static WebSocket CreateFromStream(System.IO.Stream stream, bool isServer, string subProtocol, System.TimeSpan keepAliveInterval) { throw null; }
}
}
diff --git a/src/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/WebSocketProtocol.cs b/src/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/WebSocketProtocol.cs
index e4756eb603..732cbb5e91 100644
--- a/src/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/WebSocketProtocol.cs
+++ b/src/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/WebSocketProtocol.cs
@@ -13,8 +13,7 @@ namespace System.Net.WebSockets
Stream stream,
bool isServer,
string subProtocol,
- TimeSpan keepAliveInterval,
- Memory<byte> buffer = default)
+ TimeSpan keepAliveInterval)
{
if (stream == null)
{
@@ -38,7 +37,7 @@ namespace System.Net.WebSockets
0));
}
- return ManagedWebSocket.CreateFromConnectedStream(stream, isServer, subProtocol, keepAliveInterval, buffer);
+ return ManagedWebSocket.CreateFromConnectedStream(stream, isServer, subProtocol, keepAliveInterval);
}
}
}
diff --git a/src/System.Net.WebSockets.WebSocketProtocol/tests/WebSocketProtocolTests.cs b/src/System.Net.WebSockets.WebSocketProtocol/tests/WebSocketProtocolTests.cs
index 9db60cd882..b5a5c2857f 100644
--- a/src/System.Net.WebSockets.WebSocketProtocol/tests/WebSocketProtocolTests.cs
+++ b/src/System.Net.WebSockets.WebSocketProtocol/tests/WebSocketProtocolTests.cs
@@ -25,19 +25,19 @@ namespace System.Net.WebSockets.Tests
public void CreateFromStream_InvalidArguments_Throws()
{
AssertExtensions.Throws<ArgumentNullException>("stream",
- () => WebSocketProtocol.CreateFromStream(null, true, "subProtocol", TimeSpan.FromSeconds(30), default(Memory<byte>)));
+ () => WebSocketProtocol.CreateFromStream(null, true, "subProtocol", TimeSpan.FromSeconds(30)));
AssertExtensions.Throws<ArgumentException>("stream",
- () => WebSocketProtocol.CreateFromStream(new MemoryStream(new byte[100], writable: false), true, "subProtocol", TimeSpan.FromSeconds(30), default(Memory<byte>)));
+ () => WebSocketProtocol.CreateFromStream(new MemoryStream(new byte[100], writable: false), true, "subProtocol", TimeSpan.FromSeconds(30)));
AssertExtensions.Throws<ArgumentException>("stream",
- () => WebSocketProtocol.CreateFromStream(new UnreadableStream(), true, "subProtocol", TimeSpan.FromSeconds(30), default(Memory<byte>)));
+ () => WebSocketProtocol.CreateFromStream(new UnreadableStream(), true, "subProtocol", TimeSpan.FromSeconds(30)));
AssertExtensions.Throws<ArgumentException>("subProtocol",
- () => WebSocketProtocol.CreateFromStream(new MemoryStream(), true, " ", TimeSpan.FromSeconds(30), default(Memory<byte>)));
+ () => WebSocketProtocol.CreateFromStream(new MemoryStream(), true, " ", TimeSpan.FromSeconds(30)));
AssertExtensions.Throws<ArgumentException>("subProtocol",
- () => WebSocketProtocol.CreateFromStream(new MemoryStream(), true, "\xFF", TimeSpan.FromSeconds(30), default(Memory<byte>)));
+ () => WebSocketProtocol.CreateFromStream(new MemoryStream(), true, "\xFF", TimeSpan.FromSeconds(30)));
AssertExtensions.Throws<ArgumentOutOfRangeException>("keepAliveInterval", () =>
- WebSocketProtocol.CreateFromStream(new MemoryStream(), true, "subProtocol", TimeSpan.FromSeconds(-2), default(Memory<byte>)));
+ WebSocketProtocol.CreateFromStream(new MemoryStream(), true, "subProtocol", TimeSpan.FromSeconds(-2)));
}
[Theory]
@@ -47,8 +47,8 @@ namespace System.Net.WebSockets.Tests
[InlineData(4096)]
public void CreateFromStream_ValidBufferSizes_Succeed(int bufferSize)
{
- Assert.NotNull(WebSocketProtocol.CreateFromStream(new MemoryStream(), false, null, Timeout.InfiniteTimeSpan, new Memory<byte>(new byte[bufferSize])));
- Assert.NotNull(WebSocketProtocol.CreateFromStream(new MemoryStream(), true, null, Timeout.InfiniteTimeSpan, new Memory<byte>(new byte[bufferSize])));
+ Assert.NotNull(WebSocketProtocol.CreateFromStream(new MemoryStream(), false, null, Timeout.InfiniteTimeSpan));
+ Assert.NotNull(WebSocketProtocol.CreateFromStream(new MemoryStream(), true, null, Timeout.InfiniteTimeSpan));
}
[OuterLoop] // Connects to external server.
diff --git a/src/System.Net.WebSockets/ref/System.Net.WebSockets.cs b/src/System.Net.WebSockets/ref/System.Net.WebSockets.cs
index 126887bc2e..c174799633 100644
--- a/src/System.Net.WebSockets/ref/System.Net.WebSockets.cs
+++ b/src/System.Net.WebSockets/ref/System.Net.WebSockets.cs
@@ -29,7 +29,7 @@ namespace System.Net.WebSockets
public static System.ArraySegment<byte> CreateClientBuffer(int receiveBufferSize, int sendBufferSize) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public static System.Net.WebSockets.WebSocket CreateClientWebSocket(System.IO.Stream innerStream, string subProtocol, int receiveBufferSize, int sendBufferSize, System.TimeSpan keepAliveInterval, bool useZeroMaskingKey, System.ArraySegment<byte> internalBuffer) { throw null; }
- public static System.Net.WebSockets.WebSocket CreateFromStream(System.IO.Stream stream, bool isServer, string subProtocol, System.TimeSpan keepAliveInterval, System.Memory<byte> buffer=default(System.Memory<byte>)) { throw null; }
+ public static System.Net.WebSockets.WebSocket CreateFromStream(System.IO.Stream stream, bool isServer, string subProtocol, System.TimeSpan keepAliveInterval) { throw null; }
public static System.ArraySegment<byte> CreateServerBuffer(int receiveBufferSize) { throw null; }
public abstract void Dispose();
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
diff --git a/src/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs b/src/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs
index 64a8192275..27ae87c6a8 100644
--- a/src/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs
+++ b/src/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs
@@ -135,9 +135,8 @@ namespace System.Net.WebSockets
/// <param name="isServer"><code>true</code> if this is the server-side of the connection; <code>false</code> if it's the client side.</param>
/// <param name="subProtocol">The agreed upon sub-protocol that was used when creating the connection.</param>
/// <param name="keepAliveInterval">The keep-alive interval to use, or <see cref="Timeout.InfiniteTimeSpan"/> to disable keep-alives.</param>
- /// <param name="buffer">A scratch buffer that may be used by the implementation for any purpose.</param>
/// <returns>The created <see cref="WebSocket"/>.</returns>
- public static WebSocket CreateFromStream(Stream stream, bool isServer, string subProtocol, TimeSpan keepAliveInterval, Memory<byte> buffer = default)
+ public static WebSocket CreateFromStream(Stream stream, bool isServer, string subProtocol, TimeSpan keepAliveInterval)
{
if (stream == null)
{
@@ -161,7 +160,7 @@ namespace System.Net.WebSockets
0));
}
- return ManagedWebSocket.CreateFromConnectedStream(stream, isServer, subProtocol, keepAliveInterval, buffer);
+ return ManagedWebSocket.CreateFromConnectedStream(stream, isServer, subProtocol, keepAliveInterval);
}
[EditorBrowsable(EditorBrowsableState.Never)]
@@ -211,12 +210,10 @@ namespace System.Net.WebSockets
SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, 0));
}
- Memory<byte> internalMemoryBuffer =
- internalBuffer.Count >= receiveBufferSize ? internalBuffer :
- receiveBufferSize >= ManagedWebSocket.MaxMessageHeaderLength ? new byte[receiveBufferSize] :
- Memory<byte>.Empty; // let ManagedWebSocket create it
+ // Ignore useZeroMaskingKey. ManagedWebSocket doesn't currently support that debugging option.
+ // Ignore internalBuffer. ManagedWebSocket uses its own small buffer for headers/control messages.
- return ManagedWebSocket.CreateFromConnectedStream(innerStream, false, subProtocol, keepAliveInterval, internalMemoryBuffer);
+ return ManagedWebSocket.CreateFromConnectedStream(innerStream, false, subProtocol, keepAliveInterval);
}
}
}
diff --git a/src/System.Net.WebSockets/tests/WebSocketTests.netcoreapp.cs b/src/System.Net.WebSockets/tests/WebSocketTests.netcoreapp.cs
index a95bb7e319..59e1e2e049 100644
--- a/src/System.Net.WebSockets/tests/WebSocketTests.netcoreapp.cs
+++ b/src/System.Net.WebSockets/tests/WebSocketTests.netcoreapp.cs
@@ -29,17 +29,6 @@ namespace System.Net.WebSockets.Tests
WebSocket.CreateFromStream(new MemoryStream(), true, "subProtocol", TimeSpan.FromSeconds(-2)));
}
- [Theory]
- [InlineData(0)]
- [InlineData(1)]
- [InlineData(14)]
- [InlineData(4096)]
- public void CreateFromStream_ValidBufferSizes_Succeed(int bufferSize)
- {
- Assert.NotNull(WebSocket.CreateFromStream(new MemoryStream(), false, null, Timeout.InfiniteTimeSpan, new byte[bufferSize]));
- Assert.NotNull(WebSocket.CreateFromStream(new MemoryStream(), true, null, Timeout.InfiniteTimeSpan, new byte[bufferSize]));
- }
-
[Fact]
public void ValueWebSocketReceiveResult_Ctor_InvalidArguments_Throws()
{
diff --git a/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs b/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs
index 1670ceada6..27d9bdb824 100644
--- a/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs
+++ b/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs
@@ -92,16 +92,6 @@ namespace System.Runtime.Serialization
Initialize(type, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, null, false);
}
- public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace,
- IEnumerable<Type> knownTypes,
- int maxItemsInObjectGraph,
- bool ignoreExtensionDataObject,
- bool preserveObjectReferences,
- DataContractResolver dataContractResolver)
- {
- Initialize(type, rootName, rootNamespace, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, /*dataContractSurrogate,*/ dataContractResolver, false);
- }
-
public DataContractSerializer(Type type, DataContractSerializerSettings settings)
{
if (settings == null)
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs b/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs
index 88fc758431..5c81a051bd 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationReader.cs
@@ -693,7 +693,7 @@ namespace System.Xml.Serialization
{
if (special.TypeDesc.Kind == TypeKind.Node)
{
- value = Document.CreateTextNode(ReadString());
+ value = Document.CreateTextNode(Reader.ReadString());
}
else
{
@@ -706,11 +706,11 @@ namespace System.Xml.Serialization
{
if (text.Mapping.TypeDesc.CollapseWhitespace)
{
- value = CollapseWhitespace(ReadString());
+ value = CollapseWhitespace(Reader.ReadString());
}
else
{
- value = ReadString();
+ value = Reader.ReadString();
}
}
else
@@ -721,7 +721,7 @@ namespace System.Xml.Serialization
}
else
{
- value = WritePrimitive(text.Mapping, (state) => ((ReflectionXmlSerializationReader)state).ReadString(), this);
+ value = WritePrimitive(text.Mapping, (state) => ((ReflectionXmlSerializationReader)state).Reader.ReadString(), this);
}
}
}
@@ -1832,7 +1832,7 @@ namespace System.Xml.Serialization
Func<object, string> functor = (state) =>
{
var reader = (ReflectionXmlSerializationReader)state;
- return reader.CollapseWhitespace(reader.ReadString());
+ return reader.CollapseWhitespace(reader.Reader.ReadString());
};
o = WriteEnumMethod(enumMapping, functor, this);
ReadEndElement();
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSchemaImporter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSchemaImporter.cs
index 6d4dc7c57e..b3d3af2471 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSchemaImporter.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSchemaImporter.cs
@@ -37,19 +37,6 @@ namespace System.Xml.Serialization
/// </devdoc>
public XmlSchemaImporter(XmlSchemas schemas, CodeIdentifiers typeIdentifiers) : base(schemas, CodeGenerationOptions.GenerateProperties, new ImportContext(typeIdentifiers, false)) { }
- /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.XmlSchemaImporter2"]/*' />
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- public XmlSchemaImporter(XmlSchemas schemas, CodeIdentifiers typeIdentifiers, CodeGenerationOptions options) : base(schemas, options, new ImportContext(typeIdentifiers, false)) { }
-
- /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.XmlSchemaImporter3"]/*' />
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- public XmlSchemaImporter(XmlSchemas schemas, CodeGenerationOptions options, ImportContext context) : base(schemas, options, context) { }
-
-
/// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportDerivedTypeMapping"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs
index 17a11a2cf5..3e349e4340 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs
@@ -1428,40 +1428,6 @@ namespace System.Xml.Serialization
Array.Copy(a, b, length);
return b;
}
- // This is copied from Core's XmlReader.ReadString, as it is not exposed in the Contract.
- protected virtual string ReadString()
- {
- if (Reader.ReadState != ReadState.Interactive)
- {
- return string.Empty;
- }
- Reader.MoveToElement();
- if (Reader.NodeType == XmlNodeType.Element)
- {
- if (Reader.IsEmptyElement)
- {
- return string.Empty;
- }
- else if (!Reader.Read())
- {
- throw new InvalidOperationException(SR.Xml_InvalidOperation);
- }
- if (Reader.NodeType == XmlNodeType.EndElement)
- {
- return string.Empty;
- }
- }
- string result = string.Empty;
- while (IsTextualNode(Reader.NodeType))
- {
- result += Reader.Value;
- if (!Reader.Read())
- {
- break;
- }
- }
- return result;
- }
// 0x6018
private static uint s_isTextualNodeBitmap = (1 << (int)XmlNodeType.Text) | (1 << (int)XmlNodeType.CDATA) | (1 << (int)XmlNodeType.Whitespace) | (1 << (int)XmlNodeType.SignificantWhitespace);
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs
index 25fdb4df57..d9f998ba0f 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs
@@ -807,7 +807,7 @@ namespace System.Xml.Serialization
#if !FEATURE_SERIALIZATION_UAPAOT
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
[ResourceExposure(ResourceScope.None)]
- public static bool GenerateSerializer(Type[] types, XmlMapping[] mappings, Stream stream)
+ internal static bool GenerateSerializer(Type[] types, XmlMapping[] mappings, Stream stream)
{
if (types == null || types.Length == 0)
return false;
diff --git a/src/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryContext.cs b/src/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryContext.cs
index 2a747d6e2a..783692d486 100644
--- a/src/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryContext.cs
+++ b/src/System.Private.Xml/src/System/Xml/Xsl/Runtime/XmlQueryContext.cs
@@ -328,9 +328,7 @@ namespace System.Xml.Xsl.Runtime
XsltMessageEncounteredEventHandler onMessage = (_argList != null) ? _argList.xsltMessageEncountered : null;
if (onMessage != null)
- onMessage(this, new XmlILQueryEventArgs(message));
- else
- Console.WriteLine(message);
+ onMessage(this, new XmlILQueryEventArgs(message));
}
}
diff --git a/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/MessageAction.cs b/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/MessageAction.cs
index 4910cb122e..6c57672caf 100644
--- a/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/MessageAction.cs
+++ b/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/MessageAction.cs
@@ -56,8 +56,7 @@ namespace System.Xml.Xsl.XsltOld
case ProcessingChildren:
TextOnlyOutput recOutput = processor.PopOutput() as TextOnlyOutput;
- Debug.Assert(recOutput != null);
- Console.WriteLine(recOutput.Writer.ToString());
+ Debug.Assert(recOutput != null);
if (_Terminate)
{
diff --git a/src/System.Private.Xml/tests/Writers/RwFactory/CXmlDriverVariation.cs b/src/System.Private.Xml/tests/Writers/RwFactory/CXmlDriverVariation.cs
index f90abf777f..4f00d99d1f 100644
--- a/src/System.Private.Xml/tests/Writers/RwFactory/CXmlDriverVariation.cs
+++ b/src/System.Private.Xml/tests/Writers/RwFactory/CXmlDriverVariation.cs
@@ -58,8 +58,7 @@ namespace System.Xml.Tests
res = (tagVARIATION_STATUS)HandleException(e);
}
catch (Exception e)
- {
- Console.WriteLine(e);
+ {
res = (tagVARIATION_STATUS)HandleException(e);
}
diff --git a/src/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/TC_SchemaSet_Compile.cs b/src/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/TC_SchemaSet_Compile.cs
index b360f5bd19..43fde8b0fa 100644
--- a/src/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/TC_SchemaSet_Compile.cs
+++ b/src/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/TC_SchemaSet_Compile.cs
@@ -85,6 +85,7 @@ namespace System.Xml.Tests
Assert.True(false);
}
+ [ActiveIssue(27740, TestPlatforms.AnyUnix)]
[Fact]
//[Variation(Desc = "TFS_470021 Unexpected local particle qualified name when chameleon schema is added to set")]
public void TFS_470021()
diff --git a/src/System.Private.Xml/tests/XmlSchema/XmlSchemaValidatorApi/ValidateMisc.cs b/src/System.Private.Xml/tests/XmlSchema/XmlSchemaValidatorApi/ValidateMisc.cs
index 31e44a8e33..707709f43c 100644
--- a/src/System.Private.Xml/tests/XmlSchema/XmlSchemaValidatorApi/ValidateMisc.cs
+++ b/src/System.Private.Xml/tests/XmlSchema/XmlSchemaValidatorApi/ValidateMisc.cs
@@ -893,6 +893,7 @@ namespace System.Xml.Tests
}
//TFS_538324
+ [ActiveIssue(27740, TestPlatforms.AnyUnix)]
[Fact]
public void XSDValidationGeneratesInvalidError_1()
{
@@ -919,6 +920,7 @@ namespace System.Xml.Tests
}
//TFS_538324
+ [ActiveIssue(27740, TestPlatforms.AnyUnix)]
[Fact]
public void XSDValidationGeneratesInvalidError_2()
{
diff --git a/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XslCompiledTransform.cs b/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XslCompiledTransform.cs
index 0c6dfaf71d..2f2649b529 100644
--- a/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XslCompiledTransform.cs
+++ b/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XslCompiledTransform.cs
@@ -609,18 +609,13 @@ namespace System.Xml.Tests
AppContext.SetSwitch("Switch.System.Xml.AllowDefaultResolver", true);
string expected = @"<?xml version=""1.0"" encoding=""utf-8""?><result>123</result>";
+ string fileName = GetType().Name + "_" + Path.GetRandomFileName();
+ string testFile = Path.Combine(Path.GetTempPath(), fileName);
+ string xmlFile = FullFilePath(fileName);
// copy file on the local machine
try
{
- string tempPath = Path.GetTempPath();
- string testFile = Path.Combine(tempPath, "xmlResolver_document_function.xml");
- if (File.Exists(testFile))
- {
- File.SetAttributes(testFile, FileAttributes.Normal);
- File.Delete(testFile);
- }
- string xmlFile = FullFilePath("xmlResolver_document_function.xml");
File.Copy(xmlFile, testFile, true);
}
catch (Exception e)
@@ -629,6 +624,14 @@ namespace System.Xml.Tests
_output.WriteLine("Could not copy file to local. Some other issues prevented this test from running");
return; //TEST_SKIPPED;
}
+ finally
+ {
+ if (File.Exists(testFile))
+ {
+ File.SetAttributes(testFile, FileAttributes.Normal);
+ File.Delete(testFile);
+ }
+ }
// copy file on the local machine (this is now done with createAPItestfiles.js, see Oasys scenario.)
if (LoadXSL("xmlResolver_document_function_absolute_uri.xsl", xslInputType, readerType) == 1)
@@ -2522,18 +2525,13 @@ namespace System.Xml.Tests
AppContext.SetSwitch("Switch.System.Xml.AllowDefaultResolver", true);
string expected = @"<?xml version=""1.0"" encoding=""utf-8""?><result>123</result>";
+ string fileName = GetType().Name + "_" + Path.GetRandomFileName();
+ string testFile = Path.Combine(Path.GetTempPath(), fileName);
+ string xmlFile = FullFilePath(fileName);
// copy file on the local machine
try
{
- string tempPath = Path.GetTempPath();
- string testFile = Path.Combine(tempPath, "xmlResolver_document_function.xml");
- if (File.Exists(testFile))
- {
- File.SetAttributes(testFile, FileAttributes.Normal);
- File.Delete(testFile);
- }
- string xmlFile = FullFilePath("xmlResolver_document_function.xml");
File.Copy(xmlFile, testFile, true);
}
catch (Exception e)
@@ -2542,6 +2540,14 @@ namespace System.Xml.Tests
_output.WriteLine("Could not copy file to local. Some other issues prevented this test from running");
return; //TEST_SKIPPED;
}
+ finally
+ {
+ if (File.Exists(testFile))
+ {
+ File.SetAttributes(testFile, FileAttributes.Normal);
+ File.Delete(testFile);
+ }
+ }
if (LoadXSL("xmlResolver_document_function_absolute_uri.xsl", xslInputType, readerType) == 1)
{
diff --git a/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltApiV2.cs b/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltApiV2.cs
index e06d0a74e2..f5c7c15859 100644
--- a/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltApiV2.cs
+++ b/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltApiV2.cs
@@ -76,7 +76,7 @@ namespace System.Xml.Tests
static XsltApiTestCaseBase2()
{
// Replace absolute URI in xmlResolver_document_function.xml based on the environment
- string targetFile = Path.Combine(Path.GetTempPath(), "xmlResolver_document_function.xml");
+ string targetFile = Path.Combine(Path.GetTempPath(), typeof(XsltApiTestCaseBase2) + "_" + Path.GetRandomFileName());
string xslFile = Path.Combine("TestFiles", FilePathUtil.GetTestDataPath(), "XsltApiV2", "xmlResolver_document_function_absolute_uri.xsl");
XmlDocument doc = new XmlDocument();
doc.Load(xslFile);
diff --git a/src/System.Private.Xml/tests/Xslt/XslTransformApi/XSLTransform.cs b/src/System.Private.Xml/tests/Xslt/XslTransformApi/XSLTransform.cs
index 010efa92a2..3ef33bd4fc 100644
--- a/src/System.Private.Xml/tests/Xslt/XslTransformApi/XSLTransform.cs
+++ b/src/System.Private.Xml/tests/Xslt/XslTransformApi/XSLTransform.cs
@@ -49,7 +49,7 @@ namespace System.Xml.Tests
public class XsltApiTestCaseBase : FileCleanupTestBase
{
private const string XmlResolverDocumentName = "xmlResolver_document_function.xml";
- private static readonly string s_temporaryResolverDocumentFullName = Path.Combine(Path.GetTempPath(), "XslTransformApi", XmlResolverDocumentName);
+ private static readonly string s_temporaryResolverDocumentFullName = Path.Combine(Path.GetTempPath(), typeof(XsltApiTestCaseBase) + "_" + Path.GetRandomFileName());
private static readonly object s_temporaryResolverDocumentLock = new object();
// Generic data for all derived test cases
diff --git a/src/System.Runtime.Caching/src/MatchingRefApiCompatBaseline.txt b/src/System.Runtime.Caching/src/MatchingRefApiCompatBaseline.txt
deleted file mode 100644
index ad5de574e0..0000000000
--- a/src/System.Runtime.Caching/src/MatchingRefApiCompatBaseline.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Compat issues with assembly System.Runtime.Caching:
-TypesMustExist : Type 'System.Runtime.Caching.Configuration.CachingSectionGroup' does not exist in the implementation but it does exist in the contract.
-TypesMustExist : Type 'System.Runtime.Caching.Configuration.MemoryCacheElement' does not exist in the implementation but it does exist in the contract.
-TypesMustExist : Type 'System.Runtime.Caching.Configuration.MemoryCacheSection' does not exist in the implementation but it does exist in the contract.
-TypesMustExist : Type 'System.Runtime.Caching.Configuration.MemoryCacheSettingsCollection' does not exist in the implementation but it does exist in the contract.
-Total Issues: 4
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/CachingSectionGroup.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/CachingSectionGroup.cs
index e9a6219214..c18f96a83d 100644
--- a/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/CachingSectionGroup.cs
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/CachingSectionGroup.cs
@@ -7,7 +7,7 @@ using System.Configuration;
namespace System.Runtime.Caching.Configuration
{
- public sealed class CachingSectionGroup : ConfigurationSectionGroup
+ internal sealed class CachingSectionGroup : ConfigurationSectionGroup
{
public CachingSectionGroup()
{
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheElement.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheElement.cs
index cba10e3936..c0e1997c24 100644
--- a/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheElement.cs
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheElement.cs
@@ -8,7 +8,7 @@ using System.Configuration;
namespace System.Runtime.Caching.Configuration
{
- public sealed class MemoryCacheElement : ConfigurationElement
+ internal sealed class MemoryCacheElement : ConfigurationElement
{
private static ConfigurationPropertyCollection s_properties;
private static readonly ConfigurationProperty s_propName;
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheSection.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheSection.cs
index 06afa86dd9..20b8cc60cb 100644
--- a/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheSection.cs
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheSection.cs
@@ -21,7 +21,7 @@ namespace System.Runtime.Caching.Configuration
</system.caching>
*/
- public sealed class MemoryCacheSection : ConfigurationSection
+ internal sealed class MemoryCacheSection : ConfigurationSection
{
private static ConfigurationPropertyCollection s_properties;
private static readonly ConfigurationProperty s_propNamedCaches;
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheSettingsCollection.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheSettingsCollection.cs
index f35e5625f4..ba976621c6 100644
--- a/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheSettingsCollection.cs
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/Configuration/MemoryCacheSettingsCollection.cs
@@ -9,7 +9,7 @@ namespace System.Runtime.Caching.Configuration
{
[ConfigurationCollection(typeof(MemoryCacheElement),
CollectionType = ConfigurationElementCollectionType.AddRemoveClearMap)]
- public sealed class MemoryCacheSettingsCollection : ConfigurationElementCollection
+ internal sealed class MemoryCacheSettingsCollection : ConfigurationElementCollection
{
private static ConfigurationPropertyCollection s_properties;
diff --git a/src/System.Runtime.Serialization.Xml/src/MatchingRefApiCompatBaseline.txt b/src/System.Runtime.Serialization.Xml/src/MatchingRefApiCompatBaseline.txt
deleted file mode 100644
index cd47ce98d8..0000000000
--- a/src/System.Runtime.Serialization.Xml/src/MatchingRefApiCompatBaseline.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Compat issues with assembly System.Runtime.Serialization.Xml:
-MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializer..ctor(System.Type, System.Xml.XmlDictionaryString, System.Xml.XmlDictionaryString, System.Collections.Generic.IEnumerable<System.Type>, System.Int32, System.Boolean, System.Boolean, System.Runtime.Serialization.DataContractResolver)' does not exist in the implementation but it does exist in the contract.
-Total Issues: 1
diff --git a/src/System.Runtime/ref/System.Runtime.cs b/src/System.Runtime/ref/System.Runtime.cs
index 66fee8c70e..a7801dd2be 100644
--- a/src/System.Runtime/ref/System.Runtime.cs
+++ b/src/System.Runtime/ref/System.Runtime.cs
@@ -1685,6 +1685,7 @@ namespace System
public readonly partial struct Memory<T>
{
private readonly object _dummy;
+ public Memory(System.Buffers.MemoryManager<T> manager, int start, int length) { throw null; }
public Memory(T[] array) { throw null; }
public Memory(T[] array, int start, int length) { throw null; }
public static System.Memory<T> Empty { get { throw null; } }
@@ -1692,6 +1693,8 @@ namespace System
public int Length { get { throw null; } }
public System.Span<T> Span { get { throw null; } }
public void CopyTo(System.Memory<T> destination) { }
+ [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
+ public static System.Memory<T> CreateFromPinnedArray(T[] array, int start, int length) { throw null; }
public bool Equals(System.Memory<T> other) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public override bool Equals(object obj) { throw null; }
@@ -1701,7 +1704,6 @@ namespace System
public static implicit operator System.ReadOnlyMemory<T> (System.Memory<T> memory) { throw null; }
public static implicit operator System.Memory<T> (T[] array) { throw null; }
public System.Buffers.MemoryHandle Pin() { throw null; }
- public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.Memory<T> Slice(int start) { throw null; }
public System.Memory<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
@@ -1949,7 +1951,6 @@ namespace System
public static implicit operator System.ReadOnlyMemory<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (T[] array) { throw null; }
public System.Buffers.MemoryHandle Pin() { throw null; }
- public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
@@ -3704,35 +3705,35 @@ namespace System
}
namespace System.Buffers
{
- public partial interface IRetainable
+ public partial interface IMemoryOwner<T> : System.IDisposable
+ {
+ System.Memory<T> Memory { get; }
+ }
+ public partial interface IPinnable
{
- bool Release();
- void Retain();
+ System.Buffers.MemoryHandle Pin(int elementIndex);
+ void Unpin();
}
public partial struct MemoryHandle : System.IDisposable
{
private object _dummy;
[System.CLSCompliantAttribute(false)]
- public unsafe MemoryHandle(System.Buffers.IRetainable retainable, void* pointer = null, System.Runtime.InteropServices.GCHandle handle = default(System.Runtime.InteropServices.GCHandle)) { throw null; }
- public bool HasPointer { get { throw null; } }
+ public unsafe MemoryHandle(void* pointer, System.Runtime.InteropServices.GCHandle handle = default(System.Runtime.InteropServices.GCHandle), System.Buffers.IPinnable pinnable = null) { throw null; }
[System.CLSCompliantAttribute(false)]
public unsafe void* Pointer { get { throw null; } }
public void Dispose() { }
}
- public abstract partial class OwnedMemory<T> : System.Buffers.IRetainable, System.IDisposable
+ public abstract partial class MemoryManager<T> : System.Buffers.IMemoryOwner<T>, System.Buffers.IPinnable, System.IDisposable
{
- protected OwnedMemory() { }
- public abstract bool IsDisposed { get; }
- protected abstract bool IsRetained { get; }
- public abstract int Length { get; }
- public System.Memory<T> Memory { get { throw null; } }
- public abstract System.Span<T> Span { get; }
- public void Dispose() { }
+ protected MemoryManager() { }
+ public virtual int Length { get { throw null; } }
+ public virtual System.Memory<T> Memory { get { throw null; } }
protected abstract void Dispose(bool disposing);
- public abstract System.Buffers.MemoryHandle Pin(int byteOffset = 0);
- public abstract bool Release();
- public abstract void Retain();
- protected internal abstract bool TryGetArray(out System.ArraySegment<T> segment);
+ public abstract System.Span<T> GetSpan();
+ public abstract System.Buffers.MemoryHandle Pin(int elementIndex = 0);
+ void System.IDisposable.Dispose() { }
+ protected internal virtual bool TryGetArray(out System.ArraySegment<T> segment) { throw null; }
+ public abstract void Unpin();
}
public delegate void ReadOnlySpanAction<T, in TArg>(System.ReadOnlySpan<T> span, TArg arg);
public delegate void SpanAction<T, in TArg>(System.Span<T> span, TArg arg);
@@ -6636,10 +6637,10 @@ namespace System.Runtime.CompilerServices
}
public static partial class RuntimeFeature
{
- public const string PortablePdb = "PortablePdb";
#if FEATURE_DEFAULT_INTERFACES
public const string DefaultImplementationsOfInterfaces = "DefaultImplementationsOfInterfaces";
#endif
+ public const string PortablePdb = "PortablePdb";
public static bool IsSupported(string feature) { throw null; }
}
public static partial class RuntimeHelpers
@@ -8002,9 +8003,9 @@ namespace System.Threading.Tasks
[System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(typeof(System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder))]
public readonly partial struct ValueTask : System.IEquatable<System.Threading.Tasks.ValueTask>
{
- internal readonly object _dummy;
- public ValueTask(System.Threading.Tasks.Task task) { throw null; }
+ private readonly object _dummy;
public ValueTask(System.Threading.Tasks.Sources.IValueTaskSource source, short token) { throw null; }
+ public ValueTask(System.Threading.Tasks.Task task) { throw null; }
public bool IsCanceled { get { throw null; } }
public bool IsCompleted { get { throw null; } }
public bool IsCompletedSuccessfully { get { throw null; } }
@@ -8015,16 +8016,16 @@ namespace System.Threading.Tasks
public bool Equals(System.Threading.Tasks.ValueTask other) { throw null; }
public System.Runtime.CompilerServices.ValueTaskAwaiter GetAwaiter() { throw null; }
public override int GetHashCode() { throw null; }
- public System.Threading.Tasks.ValueTask Preserve() { throw null; }
public static bool operator ==(System.Threading.Tasks.ValueTask left, System.Threading.Tasks.ValueTask right) { throw null; }
public static bool operator !=(System.Threading.Tasks.ValueTask left, System.Threading.Tasks.ValueTask right) { throw null; }
+ public System.Threading.Tasks.ValueTask Preserve() { throw null; }
}
[System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(typeof(System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<>))]
public readonly partial struct ValueTask<TResult> : System.IEquatable<System.Threading.Tasks.ValueTask<TResult>>
{
internal readonly TResult _result;
- public ValueTask(System.Threading.Tasks.Task<TResult> task) { throw null; }
public ValueTask(System.Threading.Tasks.Sources.IValueTaskSource<TResult> source, short token) { throw null; }
+ public ValueTask(System.Threading.Tasks.Task<TResult> task) { throw null; }
public ValueTask(TResult result) { throw null; }
public bool IsCanceled { get { throw null; } }
public bool IsCompleted { get { throw null; } }
@@ -8037,38 +8038,38 @@ namespace System.Threading.Tasks
public bool Equals(System.Threading.Tasks.ValueTask<TResult> other) { throw null; }
public System.Runtime.CompilerServices.ValueTaskAwaiter<TResult> GetAwaiter() { throw null; }
public override int GetHashCode() { throw null; }
- public System.Threading.Tasks.ValueTask<TResult> Preserve() { throw null; }
public static bool operator ==(System.Threading.Tasks.ValueTask<TResult> left, System.Threading.Tasks.ValueTask<TResult> right) { throw null; }
public static bool operator !=(System.Threading.Tasks.ValueTask<TResult> left, System.Threading.Tasks.ValueTask<TResult> right) { throw null; }
+ public System.Threading.Tasks.ValueTask<TResult> Preserve() { throw null; }
public override string ToString() { throw null; }
}
}
namespace System.Threading.Tasks.Sources
{
- [Flags]
- public enum ValueTaskSourceOnCompletedFlags
- {
- None,
- UseSchedulingContext = 0x1,
- FlowExecutionContext = 0x2,
- }
- public enum ValueTaskSourceStatus
- {
- Pending = 0,
- Succeeded = 1,
- Faulted = 2,
- Canceled = 3
- }
- public interface IValueTaskSource
+ public partial interface IValueTaskSource
{
+ void GetResult(short token);
System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token);
void OnCompleted(System.Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags);
- void GetResult(short token);
}
- public interface IValueTaskSource<out TResult>
+ public partial interface IValueTaskSource<out TResult>
{
+ TResult GetResult(short token);
System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token);
void OnCompleted(System.Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags);
- TResult GetResult(short token);
+ }
+ [System.FlagsAttribute]
+ public enum ValueTaskSourceOnCompletedFlags
+ {
+ FlowExecutionContext = 2,
+ None = 0,
+ UseSchedulingContext = 1,
+ }
+ public enum ValueTaskSourceStatus
+ {
+ Canceled = 3,
+ Faulted = 2,
+ Pending = 0,
+ Succeeded = 1,
}
}
diff --git a/src/System.Runtime/src/ApiCompatBaseline.uap.txt b/src/System.Runtime/src/ApiCompatBaseline.uap.txt
new file mode 100644
index 0000000000..4420be7a23
--- /dev/null
+++ b/src/System.Runtime/src/ApiCompatBaseline.uap.txt
@@ -0,0 +1,10 @@
+Compat issues with assembly System.Runtime:
+MembersMustExist : Member 'System.Memory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ReadOnlyMemory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Memory<T>..ctor(System.Buffers.MemoryManager<T>, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Memory<T>.CreateFromPinnedArray(T[], System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Buffers.MemoryHandle..ctor(System.Void*, System.Runtime.InteropServices.GCHandle, System.Buffers.IPinnable)' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Buffers.IMemoryOwner<T>' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Buffers.IPinnable' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Buffers.MemoryManager<T>' does not exist in the implementation but it does exist in the contract.
+Total Issues: 8
diff --git a/src/System.Runtime/src/ApiCompatBaseline.uapaot.txt b/src/System.Runtime/src/ApiCompatBaseline.uapaot.txt
index ba98be8651..4420be7a23 100644
--- a/src/System.Runtime/src/ApiCompatBaseline.uapaot.txt
+++ b/src/System.Runtime/src/ApiCompatBaseline.uapaot.txt
@@ -1,4 +1,10 @@
Compat issues with assembly System.Runtime:
MembersMustExist : Member 'System.Memory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'System.ReadOnlyMemory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
-Total Issues: 2
+MembersMustExist : Member 'System.Memory<T>..ctor(System.Buffers.MemoryManager<T>, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Memory<T>.CreateFromPinnedArray(T[], System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Buffers.MemoryHandle..ctor(System.Void*, System.Runtime.InteropServices.GCHandle, System.Buffers.IPinnable)' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Buffers.IMemoryOwner<T>' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Buffers.IPinnable' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Buffers.MemoryManager<T>' does not exist in the implementation but it does exist in the contract.
+Total Issues: 8
diff --git a/src/System.Runtime/src/System.Runtime.csproj b/src/System.Runtime/src/System.Runtime.csproj
index 1a80306018..428bbf0137 100644
--- a/src/System.Runtime/src/System.Runtime.csproj
+++ b/src/System.Runtime/src/System.Runtime.csproj
@@ -6,6 +6,7 @@
<AssemblyName>System.Runtime</AssemblyName>
<IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
<ILLinkClearInitLocals>true</ILLinkClearInitLocals>
+ <GenFacadesIgnoreMissingTypes Condition="'$(TargetGroup)'=='uapaot' OR '$(TargetGroup)' == 'uap'">true</GenFacadesIgnoreMissingTypes>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
diff --git a/src/System.Security.Cryptography.Csp/src/Internal/Cryptography/Helpers.cs b/src/System.Security.Cryptography.Csp/src/Internal/Cryptography/Helpers.cs
index 6ba101eddd..9e0d2b42b4 100644
--- a/src/System.Security.Cryptography.Csp/src/Internal/Cryptography/Helpers.cs
+++ b/src/System.Security.Cryptography.Csp/src/Internal/Cryptography/Helpers.cs
@@ -44,6 +44,20 @@ namespace Internal.Cryptography
return null;
}
+ public static byte[] TrimLargeIV(byte[] currentIV, int blockSizeInBits)
+ {
+ int blockSizeBytes = checked((blockSizeInBits + 7) / 8);
+
+ if (currentIV?.Length > blockSizeBytes)
+ {
+ byte[] tmp = new byte[blockSizeBytes];
+ Buffer.BlockCopy(currentIV, 0, tmp, 0, tmp.Length);
+ return tmp;
+ }
+
+ return currentIV;
+ }
+
public static bool IsLegalSize(this int size, KeySizes[] legalSizes)
{
for (int i = 0; i < legalSizes.Length; i++)
diff --git a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DESCryptoServiceProvider.Unix.cs b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DESCryptoServiceProvider.Unix.cs
index 790651581f..46a345b88c 100644
--- a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DESCryptoServiceProvider.Unix.cs
+++ b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DESCryptoServiceProvider.Unix.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
+using Internal.Cryptography;
namespace System.Security.Cryptography
{
@@ -26,9 +27,13 @@ namespace System.Security.Cryptography
}
public override ICryptoTransform CreateDecryptor() => _impl.CreateDecryptor();
- public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) => _impl.CreateDecryptor(rgbKey, rgbIV);
public override ICryptoTransform CreateEncryptor() => _impl.CreateEncryptor();
- public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) => _impl.CreateEncryptor(rgbKey, rgbIV);
+
+ public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) =>
+ _impl.CreateEncryptor(rgbKey, Helpers.TrimLargeIV(rgbIV, BlockSize));
+
+ public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) =>
+ _impl.CreateDecryptor(rgbKey, Helpers.TrimLargeIV(rgbIV, BlockSize));
protected override void Dispose(bool disposing)
{
diff --git a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RC2CryptoServiceProvider.Unix.cs b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RC2CryptoServiceProvider.Unix.cs
index a4360a81dc..4b9deafe56 100644
--- a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RC2CryptoServiceProvider.Unix.cs
+++ b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RC2CryptoServiceProvider.Unix.cs
@@ -29,9 +29,13 @@ namespace System.Security.Cryptography
}
public override ICryptoTransform CreateDecryptor() => _impl.CreateDecryptor();
- public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) => _impl.CreateDecryptor(rgbKey, rgbIV);
public override ICryptoTransform CreateEncryptor() => _impl.CreateEncryptor();
- public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) => _impl.CreateEncryptor(rgbKey, rgbIV);
+
+ public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) =>
+ _impl.CreateEncryptor(rgbKey, Helpers.TrimLargeIV(rgbIV, BlockSize));
+
+ public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) =>
+ _impl.CreateDecryptor(rgbKey, Helpers.TrimLargeIV(rgbIV, BlockSize));
protected override void Dispose(bool disposing)
{
diff --git a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/TripleDESCryptoServiceProvider.cs b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/TripleDESCryptoServiceProvider.cs
index 0026a960a6..07b1864810 100644
--- a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/TripleDESCryptoServiceProvider.cs
+++ b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/TripleDESCryptoServiceProvider.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
+using Internal.Cryptography;
namespace System.Security.Cryptography
{
@@ -63,12 +64,16 @@ namespace System.Security.Cryptography
public override KeySizes[] LegalBlockSizes => _impl.LegalBlockSizes;
public override KeySizes[] LegalKeySizes => _impl.LegalKeySizes;
public override ICryptoTransform CreateEncryptor() => _impl.CreateEncryptor();
- public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) => _impl.CreateEncryptor(rgbKey, rgbIV);
public override ICryptoTransform CreateDecryptor() => _impl.CreateDecryptor();
- public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) => _impl.CreateDecryptor(rgbKey, rgbIV);
public override void GenerateIV() => _impl.GenerateIV();
public override void GenerateKey() => _impl.GenerateKey();
+ public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) =>
+ _impl.CreateEncryptor(rgbKey, Helpers.TrimLargeIV(rgbIV, BlockSize));
+
+ public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) =>
+ _impl.CreateDecryptor(rgbKey, Helpers.TrimLargeIV(rgbIV, BlockSize));
+
protected override void Dispose(bool disposing)
{
if (disposing)
diff --git a/src/System.Security.Cryptography.Csp/tests/CreateTransformCompat.cs b/src/System.Security.Cryptography.Csp/tests/CreateTransformCompat.cs
new file mode 100644
index 0000000000..41d14ec3f4
--- /dev/null
+++ b/src/System.Security.Cryptography.Csp/tests/CreateTransformCompat.cs
@@ -0,0 +1,67 @@
+// 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 Xunit;
+
+namespace System.Security.Cryptography.Csp.Tests
+{
+ public static class CreateTransformCompat
+ {
+ [Theory]
+ [InlineData(typeof(AesCryptoServiceProvider), null)]
+ [InlineData(typeof(DESCryptoServiceProvider), 9)]
+ [InlineData(typeof(DESCryptoServiceProvider), 13)]
+ [InlineData(typeof(RC2CryptoServiceProvider), 9)]
+ [InlineData(typeof(RC2CryptoServiceProvider), 17)]
+ [InlineData(typeof(TripleDESCryptoServiceProvider), 9)]
+ [InlineData(typeof(TripleDESCryptoServiceProvider), 24)]
+ [InlineData(typeof(TripleDESCryptoServiceProvider), 31)]
+ public static void CreateTransform_IVTooBig(Type t, int? ivSizeBytes)
+ {
+ using (SymmetricAlgorithm alg = (SymmetricAlgorithm)Activator.CreateInstance(t))
+ {
+ alg.Mode = CipherMode.CBC;
+ byte[] key = alg.Key;
+
+ // If it isn't supposed to work
+ if (ivSizeBytes == null)
+ {
+ // badSize is in bytes, BlockSize is in bits.
+ // So badSize is 8 times as big as it should be.
+ int badSize = alg.BlockSize;
+ Assert.Throws<ArgumentException>(() => alg.CreateEncryptor(key, new byte[badSize]));
+ Assert.Throws<ArgumentException>(() => alg.CreateDecryptor(key, new byte[badSize]));
+
+ return;
+ }
+
+ int correctSize = alg.BlockSize / 8;
+ byte[] data = { 1, 2, 3, 4, 5 };
+
+ byte[] iv = new byte[ivSizeBytes.Value];
+
+ for (int i = 0; i < iv.Length; i++)
+ {
+ iv[i] = (byte)((byte.MaxValue - i) ^ correctSize);
+ }
+
+ byte[] correctIV = iv.AsSpan(0, correctSize).ToArray();
+
+ using (ICryptoTransform correctEnc = alg.CreateEncryptor(key, correctIV))
+ using (ICryptoTransform badIvEnc = alg.CreateEncryptor(key, iv))
+ using (ICryptoTransform badIvDec = alg.CreateDecryptor(key, iv))
+ {
+ byte[] encrypted = badIvEnc.TransformFinalBlock(data, 0, data.Length);
+ byte[] correctEncrypted = correctEnc.TransformFinalBlock(data, 0, data.Length);
+
+ Assert.Equal(correctEncrypted, encrypted);
+
+ byte[] decrypted1 = badIvDec.TransformFinalBlock(correctEncrypted, 0, correctEncrypted.Length);
+
+ Assert.Equal(data, decrypted1);
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj b/src/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj
index 4b0983cf44..ea0a3332a6 100644
--- a/src/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj
+++ b/src/System.Security.Cryptography.Csp/tests/System.Security.Cryptography.Csp.Tests.csproj
@@ -13,6 +13,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
+ <Compile Include="CreateTransformCompat.cs" />
<Compile Include="CspParametersTests.cs" />
<Compile Include="RSAImportExportCspBlobTests.cs" />
<Compile Include="RSACryptoServiceProviderBackCompat.cs" />
diff --git a/src/System.Security.Cryptography.X509Certificates/tests/ChainTests.cs b/src/System.Security.Cryptography.X509Certificates/tests/ChainTests.cs
index 95492b5ba3..7d34e05a18 100644
--- a/src/System.Security.Cryptography.X509Certificates/tests/ChainTests.cs
+++ b/src/System.Security.Cryptography.X509Certificates/tests/ChainTests.cs
@@ -642,7 +642,12 @@ namespace System.Security.Cryptography.X509Certificates.Tests
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
- expectedFlags = X509ChainStatusFlags.UntrustedRoot;
+ // For OSX alone expectedFlags here means OR instead of AND.
+ // Because the error code changed in 10.13.4 from UntrustedRoot to PartialChain
+ // and we handle that later in this test.
+ expectedFlags =
+ X509ChainStatusFlags.UntrustedRoot |
+ X509ChainStatusFlags.PartialChain;
}
else
{
@@ -670,6 +675,18 @@ namespace System.Security.Cryptography.X509Certificates.Tests
X509ChainStatusFlags.NoError,
(a, b) => a | b);
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ // If we're on 10.13.3 or older we get UntrustedRoot.
+ // If we're on 10.13.4 or newer we get PartialChain.
+ //
+ // So make the expectedValue be whichever of those two is set.
+ expectedFlags = (expectedFlags & allFlags);
+ // One of them has to be set.
+ Assert.NotEqual(X509ChainStatusFlags.NoError, expectedFlags);
+ // Continue executing now to ensure that no other unexpected flags were set.
+ }
+
Assert.Equal(expectedFlags, allFlags);
}
}
diff --git a/src/System.Threading.Thread/tests/ThreadTests.cs b/src/System.Threading.Thread/tests/ThreadTests.cs
index 091ed868d4..78ab0bbe3d 100644
--- a/src/System.Threading.Thread/tests/ThreadTests.cs
+++ b/src/System.Threading.Thread/tests/ThreadTests.cs
@@ -26,6 +26,11 @@ namespace System.Threading.Threads.Tests
[Fact]
public static void ConstructorTest()
{
+ const int SmallStackSize = 64 << 10; // 64 KB, currently accepted in all supported platforms, and is the PAL minimum
+ const int LargeStackSize = 2 << 20; // 2 MB, see https://github.com/dotnet/coreclr/issues/17170
+
+ int pageSizeBytes = Environment.SystemPageSize;
+
Action<Thread> startThreadAndJoin =
t =>
{
@@ -38,22 +43,25 @@ namespace System.Threading.Threads.Tests
{
// Try to stack-allocate an array to verify that close to the expected amount of stack space is actually
// available
- int bufferSizeBytes = Math.Max(16 << 10, stackSizeBytes - (64 << 10));
+ int bufferSizeBytes = Math.Max(16 << 10, stackSizeBytes - SmallStackSize);
unsafe
{
byte* buffer = stackalloc byte[bufferSizeBytes];
- Volatile.Write(ref buffer[0], 0xff);
+ for (int i = 0; i < bufferSizeBytes; i += pageSizeBytes)
+ {
+ Volatile.Write(ref buffer[i], 0xff);
+ }
Volatile.Write(ref buffer[bufferSizeBytes - 1], 0xff);
}
};
startThreadAndJoin(new Thread(() => verifyStackSize(0)));
startThreadAndJoin(new Thread(() => verifyStackSize(0), 0));
- startThreadAndJoin(new Thread(() => verifyStackSize(64 << 10), 64 << 10)); // 64 KB
- startThreadAndJoin(new Thread(() => verifyStackSize(16 << 20), 16 << 20)); // 16 MB
+ startThreadAndJoin(new Thread(() => verifyStackSize(SmallStackSize), SmallStackSize));
+ startThreadAndJoin(new Thread(() => verifyStackSize(LargeStackSize), LargeStackSize));
startThreadAndJoin(new Thread(state => verifyStackSize(0)));
startThreadAndJoin(new Thread(state => verifyStackSize(0), 0));
- startThreadAndJoin(new Thread(state => verifyStackSize(64 << 10), 64 << 10)); // 64 KB
- startThreadAndJoin(new Thread(state => verifyStackSize(16 << 20), 16 << 20)); // 16 MB
+ startThreadAndJoin(new Thread(state => verifyStackSize(SmallStackSize), SmallStackSize));
+ startThreadAndJoin(new Thread(state => verifyStackSize(LargeStackSize), LargeStackSize));
Assert.Throws<ArgumentNullException>(() => new Thread((ThreadStart)null));
Assert.Throws<ArgumentNullException>(() => new Thread((ThreadStart)null, 0));
diff --git a/src/System.Xml.XmlSerializer/ref/System.Xml.XmlSerializer.cs b/src/System.Xml.XmlSerializer/ref/System.Xml.XmlSerializer.cs
index 104b78a53d..ae074fa0ef 100644
--- a/src/System.Xml.XmlSerializer/ref/System.Xml.XmlSerializer.cs
+++ b/src/System.Xml.XmlSerializer/ref/System.Xml.XmlSerializer.cs
@@ -382,8 +382,8 @@ namespace System.Xml.Serialization
public System.Xml.XmlQualifiedName ExportTypeMapping(System.Xml.Serialization.XmlMembersMapping xmlMembersMapping) { throw null; }
public void ExportTypeMapping(System.Xml.Serialization.XmlTypeMapping xmlTypeMapping) { }
}
- public partial class XmlSchemaImporter
-//CodeDOM : System.Xml.Serialization.SchemaImporter
+ public partial class XmlSchemaImporter : SchemaImporter
+ //CodeDOM : System.Xml.Serialization.SchemaImporter
{
public XmlSchemaImporter(System.Xml.Serialization.XmlSchemas schemas) { }
//CODEDOM public XmlSchemaImporter(System.Xml.Serialization.XmlSchemas schemas, System.Xml.Serialization.CodeGenerationOptions options, System.CodeDom.Compiler.CodeDomProvider codeProvider, System.Xml.Serialization.ImportContext context) { }
@@ -402,6 +402,10 @@ namespace System.Xml.Serialization
public System.Xml.Serialization.XmlTypeMapping ImportSchemaType(System.Xml.XmlQualifiedName typeName, System.Type baseType, bool baseTypeCanBeIndirect) { throw null; }
public System.Xml.Serialization.XmlTypeMapping ImportTypeMapping(System.Xml.XmlQualifiedName name) { throw null; }
}
+ public abstract class SchemaImporter
+ {
+ internal SchemaImporter() { }
+ }
public partial class XmlSchemas : System.Collections.CollectionBase, System.Collections.Generic.IEnumerable<System.Xml.Schema.XmlSchema>, System.Collections.IEnumerable
{
public XmlSchemas() { }
diff --git a/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.netcoreapp.txt b/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.netcoreapp.txt
deleted file mode 100644
index b362774c2c..0000000000
--- a/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.netcoreapp.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Compat issues with assembly System.Xml.XmlSerializer:
-CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSchemaImporter' does not inherit from base type 'System.Xml.Serialization.SchemaImporter' in the implementation but it does in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeGenerationOptions, System.Xml.Serialization.ImportContext)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeIdentifiers, System.Xml.Serialization.CodeGenerationOptions)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSerializationReader.ReadString()' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.GenerateSerializer(System.Type[], System.Xml.Serialization.XmlMapping[], System.IO.Stream)' does not exist in the implementation but it does exist in the contract.
-Total Issues: 5
diff --git a/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uap.txt b/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uap.txt
deleted file mode 100644
index b362774c2c..0000000000
--- a/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uap.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Compat issues with assembly System.Xml.XmlSerializer:
-CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSchemaImporter' does not inherit from base type 'System.Xml.Serialization.SchemaImporter' in the implementation but it does in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeGenerationOptions, System.Xml.Serialization.ImportContext)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeIdentifiers, System.Xml.Serialization.CodeGenerationOptions)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSerializationReader.ReadString()' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.GenerateSerializer(System.Type[], System.Xml.Serialization.XmlMapping[], System.IO.Stream)' does not exist in the implementation but it does exist in the contract.
-Total Issues: 5
diff --git a/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uapaot.txt b/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uapaot.txt
index 52460f4dcd..34bf6b242e 100644
--- a/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uapaot.txt
+++ b/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uapaot.txt
@@ -1,10 +1,7 @@
Compat issues with assembly System.Xml.XmlSerializer:
-CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSchemaImporter' does not inherit from base type 'System.Xml.Serialization.SchemaImporter' in the implementation but it does in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeGenerationOptions, System.Xml.Serialization.ImportContext)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeIdentifiers, System.Xml.Serialization.CodeGenerationOptions)' does not exist in the implementation but it does exist in the contract.
-MembersMustExist : Member 'System.Xml.Serialization.XmlSerializationReader.ReadString()' does not exist in the implementation but it does exist in the contract.
+# Used by uap tooling for serializer generation
MembersMustExist : Member 'System.String System.Xml.Serialization.XmlSerializer.DefaultNamespace' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.Mode.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.Mode.set(System.Xml.Serialization.SerializationMode)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.SetXmlSerializerContract(System.Xml.Serialization.XmlSerializerImplementation)' does not exist in the implementation but it does exist in the contract.
-Total Issues: 8
+
diff --git a/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt b/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt
index 181752efce..5064bd41f5 100644
--- a/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt
+++ b/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt
@@ -12,6 +12,14 @@ TypesMustExist : Type 'System.Security.Cryptography.ECPoint' does not exist in t
Compat issues with assembly System.Runtime:
MembersMustExist : Member 'System.Memory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'System.ReadOnlyMemory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Memory<T>..ctor(System.Buffers.MemoryManager<T>, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Memory<T>.CreateFromPinnedArray(T[], System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Buffers.MemoryHandle..ctor(System.Void*, System.Runtime.InteropServices.GCHandle, System.Buffers.IPinnable)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Runtime.InteropServices.MemoryMarshal.TryGetMemoryManager<T, TManager>(System.ReadOnlyMemory<T>, TManager)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Runtime.InteropServices.MemoryMarshal.TryGetMemoryManager<T, TManager>(System.ReadOnlyMemory<T>, TManager, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Buffers.IMemoryOwner<T>' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Buffers.IPinnable' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Buffers.MemoryManager<T>' does not exist in the implementation but it does exist in the contract.
# Compat issues complaining about class vs delegate and class vs struct are because of a bug in APICompat tool where the implementation is picking
# the wrong core assembly. It is picking System.Runtime instead of System.Private.CoreLib, there isn't any straight forward way to fix so baselining.
diff --git a/tools-local/ILAsmVersion.txt b/tools-local/ILAsmVersion.txt
index 207183d0af..a1d8a641d8 100644
--- a/tools-local/ILAsmVersion.txt
+++ b/tools-local/ILAsmVersion.txt
@@ -1 +1 @@
-2.1.0-preview3-26329-01 \ No newline at end of file
+2.1.0-preview2-26403-07 \ No newline at end of file