@@ -24,6 +24,7 @@ internal partial class WebSocketsTransport : ITransport
24
24
private readonly TimeSpan _closeTimeout ;
25
25
private volatile bool _aborted ;
26
26
private readonly HttpConnectionOptions _httpConnectionOptions ;
27
+ private readonly CancellationTokenSource _stopCts = new CancellationTokenSource ( ) ;
27
28
28
29
private IDuplexPipe ? _transport ;
29
30
@@ -204,6 +205,8 @@ private async Task ProcessSocketAsync(WebSocket socket)
204
205
// Wait for send or receive to complete
205
206
var trigger = await Task . WhenAny ( receiving , sending ) ;
206
207
208
+ _stopCts . CancelAfter ( _closeTimeout ) ;
209
+
207
210
if ( trigger == receiving )
208
211
{
209
212
// We're waiting for the application to finish and there are 2 things it could be doing
@@ -213,22 +216,14 @@ private async Task ProcessSocketAsync(WebSocket socket)
213
216
// Cancel the application so that ReadAsync yields
214
217
_application . Input . CancelPendingRead ( ) ;
215
218
216
- using ( var delayCts = new CancellationTokenSource ( ) )
217
- {
218
- var resultTask = await Task . WhenAny ( sending , Task . Delay ( _closeTimeout , delayCts . Token ) ) ;
219
+ var resultTask = await Task . WhenAny ( sending , Task . Delay ( _closeTimeout , _stopCts . Token ) ) ;
219
220
220
- if ( resultTask != sending )
221
- {
222
- _aborted = true ;
221
+ if ( resultTask != sending )
222
+ {
223
+ _aborted = true ;
223
224
224
- // Abort the websocket if we're stuck in a pending send to the client
225
- socket . Abort ( ) ;
226
- }
227
- else
228
- {
229
- // Cancel the timeout
230
- delayCts . Cancel ( ) ;
231
- }
225
+ // Abort the websocket if we're stuck in a pending send to the client
226
+ socket . Abort ( ) ;
232
227
}
233
228
}
234
229
else
@@ -258,7 +253,7 @@ private async Task StartReceiving(WebSocket socket)
258
253
{
259
254
#if NETSTANDARD2_1 || NETCOREAPP
260
255
// Do a 0 byte read so that idle connections don't allocate a buffer when waiting for a read
261
- var result = await socket . ReceiveAsync ( Memory < byte > . Empty , CancellationToken . None ) ;
256
+ var result = await socket . ReceiveAsync ( Memory < byte > . Empty , _stopCts . Token ) ;
262
257
263
258
if ( result . MessageType == WebSocketMessageType . Close )
264
259
{
@@ -275,13 +270,13 @@ private async Task StartReceiving(WebSocket socket)
275
270
var memory = _application . Output . GetMemory ( ) ;
276
271
#if NETSTANDARD2_1 || NETCOREAPP
277
272
// Because we checked the CloseStatus from the 0 byte read above, we don't need to check again after reading
278
- var receiveResult = await socket . ReceiveAsync ( memory , CancellationToken . None ) ;
273
+ var receiveResult = await socket . ReceiveAsync ( memory , _stopCts . Token ) ;
279
274
#elif NETSTANDARD2_0 || NET461
280
275
var isArray = MemoryMarshal . TryGetArray < byte > ( memory , out var arraySegment ) ;
281
276
Debug . Assert ( isArray ) ;
282
277
283
278
// Exceptions are handled above where the send and receive tasks are being run.
284
- var receiveResult = await socket . ReceiveAsync ( arraySegment , CancellationToken . None ) ;
279
+ var receiveResult = await socket . ReceiveAsync ( arraySegment , _stopCts . Token ) ;
285
280
#else
286
281
#error TFMs need to be updated
287
282
#endif
@@ -400,7 +395,7 @@ private async Task StartSending(WebSocket socket)
400
395
try
401
396
{
402
397
// We're done sending, send the close frame to the client if the websocket is still open
403
- await socket . CloseOutputAsync ( error != null ? WebSocketCloseStatus . InternalServerError : WebSocketCloseStatus . NormalClosure , "" , CancellationToken . None ) ;
398
+ await socket . CloseOutputAsync ( error != null ? WebSocketCloseStatus . InternalServerError : WebSocketCloseStatus . NormalClosure , "" , _stopCts . Token ) ;
404
399
}
405
400
catch ( Exception ex )
406
401
{
@@ -452,6 +447,9 @@ public async Task StopAsync()
452
447
// Cancel any pending reads from the application, this should start the entire shutdown process
453
448
_application . Input . CancelPendingRead ( ) ;
454
449
450
+ // Start ungraceful close timer
451
+ _stopCts . CancelAfter ( _closeTimeout ) ;
452
+
455
453
try
456
454
{
457
455
await Running ;
@@ -465,6 +463,7 @@ public async Task StopAsync()
465
463
finally
466
464
{
467
465
_webSocket ? . Dispose ( ) ;
466
+ _stopCts . Dispose ( ) ;
468
467
}
469
468
470
469
Log . TransportStopped ( _logger , null ) ;
0 commit comments