4
4
using System . IO ;
5
5
using System . Security . Cryptography . X509Certificates ;
6
6
using System . Threading ;
7
+ using System . Security . Authentication ;
7
8
using System . Threading . Tasks ;
8
9
9
10
using Xunit ;
@@ -112,33 +113,34 @@ public async Task Dispose_ParallelWithHandshake_ThrowsODE()
112
113
113
114
await Parallel . ForEachAsync ( System . Linq . Enumerable . Range ( 0 , 10000 ) , cts . Token , async ( i , token ) =>
114
115
{
115
- ( SslStream client , SslStream server ) = TestHelper . GetConnectedSslStreams ( ) ;
116
- using ( client )
117
- using ( server )
118
- using ( X509Certificate2 serverCertificate = Configuration . Certificates . GetServerCertificate ( ) )
119
- using ( X509Certificate2 clientCertificate = Configuration . Certificates . GetClientCertificate ( ) )
116
+ // use real Tcp streams to avoid specific behavior of ConnectedStreams when concurrently disposed
117
+ ( Stream clientStream , Stream serverStream ) = TestHelper . GetConnectedTcpStreams ( ) ;
118
+
119
+ using SslStream client = new SslStream ( clientStream ) ;
120
+ using SslStream server = new SslStream ( serverStream ) ;
121
+ using X509Certificate2 serverCertificate = Configuration . Certificates . GetServerCertificate ( ) ;
122
+ using X509Certificate2 clientCertificate = Configuration . Certificates . GetClientCertificate ( ) ;
123
+
124
+ SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions ( )
120
125
{
121
- SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions ( )
122
- {
123
- TargetHost = Guid . NewGuid ( ) . ToString ( "N" ) ,
124
- RemoteCertificateValidationCallback = ( sender , certificate , chain , sslPolicyErrors ) => true ,
125
- } ;
126
+ TargetHost = Guid . NewGuid ( ) . ToString ( "N" ) ,
127
+ RemoteCertificateValidationCallback = ( sender , certificate , chain , sslPolicyErrors ) => true ,
128
+ } ;
126
129
127
- SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions ( )
128
- {
129
- ServerCertificate = serverCertificate ,
130
- } ;
130
+ SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions ( )
131
+ {
132
+ ServerCertificate = serverCertificate ,
133
+ } ;
131
134
132
- var clientTask = Task . Run ( ( ) => client . AuthenticateAsClientAsync ( clientOptions , cts . Token ) ) ;
133
- var serverTask = Task . Run ( ( ) => server . AuthenticateAsServerAsync ( serverOptions , cts . Token ) ) ;
135
+ var clientTask = Task . Run ( ( ) => client . AuthenticateAsClientAsync ( clientOptions , cts . Token ) ) ;
136
+ var serverTask = Task . Run ( ( ) => server . AuthenticateAsServerAsync ( serverOptions , cts . Token ) ) ;
134
137
135
- // Dispose the instances while the handshake is in progress.
136
- client . Dispose ( ) ;
137
- server . Dispose ( ) ;
138
+ // Dispose the instances while the handshake is in progress.
139
+ client . Dispose ( ) ;
140
+ server . Dispose ( ) ;
138
141
139
- await ValidateExceptionAsync ( clientTask ) ;
140
- await ValidateExceptionAsync ( serverTask ) ;
141
- }
142
+ await ValidateExceptionAsync ( clientTask ) ;
143
+ await ValidateExceptionAsync ( serverTask ) ;
142
144
} ) ;
143
145
144
146
static async Task ValidateExceptionAsync ( Task task )
@@ -147,9 +149,12 @@ static async Task ValidateExceptionAsync(Task task)
147
149
{
148
150
await task ;
149
151
}
150
- // either we disposed the stream, or the other side does and we get unexpected EOF
151
- catch ( Exception ex ) when ( ex is ObjectDisposedException or IOException )
152
+ catch ( Exception ex ) when ( ex
153
+ is ObjectDisposedException // disposed locally
154
+ or IOException // disposed remotely (received unexpected EOF)
155
+ or AuthenticationException ) // disposed wrapped in AuthenticationException or error from platform library
152
156
{
157
+ // expected
153
158
return ;
154
159
}
155
160
}
0 commit comments