15
15
16
16
using System ;
17
17
using System . Buffers . Binary ;
18
- using System . Collections . Concurrent ;
19
18
using System . Diagnostics ;
20
19
using System . IO ;
21
20
using System . Net ;
@@ -46,7 +45,6 @@ internal sealed class BinaryConnection : IConnection
46
45
private ConnectionInitializerContext _connectionInitializerContext ;
47
46
private EndPoint _endPoint ;
48
47
private ConnectionDescription _description ;
49
- private readonly Dropbox _dropbox = new Dropbox ( ) ;
50
48
private bool _failedEventHasBeenRaised ;
51
49
private DateTime _lastUsedAtUtc ;
52
50
private DateTime _openedAtUtc ;
@@ -356,50 +354,6 @@ private IByteBuffer ReceiveBuffer(OperationContext operationContext)
356
354
}
357
355
}
358
356
359
- private IByteBuffer ReceiveBuffer ( OperationContext operationContext , int responseTo )
360
- {
361
- using ( var receiveLockRequest = new SemaphoreSlimRequest ( _receiveLock , operationContext . RemainingTimeout , operationContext . CancellationToken ) )
362
- {
363
- var messageTask = _dropbox . GetMessageAsync ( responseTo ) ;
364
- try
365
- {
366
- Task . WaitAny ( messageTask , receiveLockRequest . Task ) ;
367
- if ( messageTask . IsCompleted )
368
- {
369
- return _dropbox . RemoveMessage ( responseTo ) ; // also propagates exception if any
370
- }
371
-
372
- receiveLockRequest . Task . GetAwaiter ( ) . GetResult ( ) ; // propagate exceptions
373
- while ( true )
374
- {
375
- try
376
- {
377
- var buffer = ReceiveBuffer ( operationContext ) ;
378
- _dropbox . AddMessage ( buffer ) ;
379
- }
380
- catch ( Exception ex )
381
- {
382
- _dropbox . AddException ( ex ) ;
383
- }
384
-
385
- if ( messageTask . IsCompleted )
386
- {
387
- return _dropbox . RemoveMessage ( responseTo ) ; // also propagates exception if any
388
- }
389
-
390
- operationContext . ThrowIfTimedOutOrCanceled ( ) ;
391
- }
392
- }
393
- catch
394
- {
395
- var ignored = messageTask . ContinueWith (
396
- t => { _dropbox . RemoveMessage ( responseTo ) . Dispose ( ) ; } ,
397
- TaskContinuationOptions . OnlyOnRanToCompletion ) ;
398
- throw ;
399
- }
400
- }
401
- }
402
-
403
357
private async Task < IByteBuffer > ReceiveBufferAsync ( OperationContext operationContext )
404
358
{
405
359
try
@@ -425,50 +379,6 @@ private async Task<IByteBuffer> ReceiveBufferAsync(OperationContext operationCon
425
379
}
426
380
}
427
381
428
- private async Task < IByteBuffer > ReceiveBufferAsync ( OperationContext operationContext , int responseTo )
429
- {
430
- using ( var receiveLockRequest = new SemaphoreSlimRequest ( _receiveLock , operationContext . RemainingTimeout , operationContext . CancellationToken ) )
431
- {
432
- var messageTask = _dropbox . GetMessageAsync ( responseTo ) ;
433
- try
434
- {
435
- await Task . WhenAny ( messageTask , receiveLockRequest . Task ) . ConfigureAwait ( false ) ;
436
- if ( messageTask . IsCompleted )
437
- {
438
- return _dropbox . RemoveMessage ( responseTo ) ; // also propagates exception if any
439
- }
440
-
441
- await receiveLockRequest . Task . ConfigureAwait ( false ) ; // propagate exceptions
442
- while ( true )
443
- {
444
- try
445
- {
446
- var buffer = await ReceiveBufferAsync ( operationContext ) . ConfigureAwait ( false ) ;
447
- _dropbox . AddMessage ( buffer ) ;
448
- }
449
- catch ( Exception ex )
450
- {
451
- _dropbox . AddException ( ex ) ;
452
- }
453
-
454
- if ( messageTask . IsCompleted )
455
- {
456
- return _dropbox . RemoveMessage ( responseTo ) ; // also propagates exception if any
457
- }
458
-
459
- operationContext . ThrowIfTimedOutOrCanceled ( ) ;
460
- }
461
- }
462
- catch
463
- {
464
- var ignored = messageTask . ContinueWith (
465
- t => { _dropbox . RemoveMessage ( responseTo ) . Dispose ( ) ; } ,
466
- TaskContinuationOptions . OnlyOnRanToCompletion ) ;
467
- throw ;
468
- }
469
- }
470
- }
471
-
472
382
public ResponseMessage ReceiveMessage (
473
383
OperationContext operationContext ,
474
384
int responseTo ,
@@ -482,8 +392,9 @@ public ResponseMessage ReceiveMessage(
482
392
try
483
393
{
484
394
helper . ReceivingMessage ( ) ;
485
- using ( var buffer = ReceiveBuffer ( operationContext , responseTo ) )
395
+ using ( var buffer = ReceiveBuffer ( operationContext ) )
486
396
{
397
+ EnsureResponseToIsCorrect ( buffer , responseTo ) ;
487
398
var message = helper . DecodeMessage ( operationContext , buffer , encoderSelector ) ;
488
399
helper . ReceivedMessage ( buffer , message ) ;
489
400
return message ;
@@ -497,7 +408,9 @@ public ResponseMessage ReceiveMessage(
497
408
}
498
409
}
499
410
500
- public async Task < ResponseMessage > ReceiveMessageAsync ( OperationContext operationContext , int responseTo ,
411
+ public async Task < ResponseMessage > ReceiveMessageAsync (
412
+ OperationContext operationContext ,
413
+ int responseTo ,
501
414
IMessageEncoderSelector encoderSelector ,
502
415
MessageEncoderSettings messageEncoderSettings )
503
416
{
@@ -508,8 +421,9 @@ public async Task<ResponseMessage> ReceiveMessageAsync(OperationContext operatio
508
421
try
509
422
{
510
423
helper . ReceivingMessage ( ) ;
511
- using ( var buffer = await ReceiveBufferAsync ( operationContext , responseTo ) . ConfigureAwait ( false ) )
424
+ using ( var buffer = await ReceiveBufferAsync ( operationContext ) . ConfigureAwait ( false ) )
512
425
{
426
+ EnsureResponseToIsCorrect ( buffer , responseTo ) ;
513
427
var message = helper . DecodeMessage ( operationContext , buffer , encoderSelector ) ;
514
428
helper . ReceivedMessage ( buffer , message ) ;
515
429
return message ;
@@ -523,6 +437,23 @@ public async Task<ResponseMessage> ReceiveMessageAsync(OperationContext operatio
523
437
}
524
438
}
525
439
440
+ private IByteBuffer EnsureResponseToIsCorrect ( IByteBuffer message , int responseTo )
441
+ {
442
+ var receivedResponseTo = GetResponseTo ( message ) ;
443
+ if ( receivedResponseTo != responseTo )
444
+ {
445
+ throw new InvalidOperationException ( $ "Expected responseTo to be { responseTo } but was { receivedResponseTo } .") ; // should not be reached
446
+ }
447
+
448
+ return message ;
449
+
450
+ int GetResponseTo ( IByteBuffer message )
451
+ {
452
+ var backingBytes = message . AccessBackingBytes ( 8 ) ;
453
+ return BitConverter . ToInt32 ( backingBytes . Array , backingBytes . Offset ) ;
454
+ }
455
+ }
456
+
526
457
private void SendBuffer ( OperationContext operationContext , IByteBuffer buffer )
527
458
{
528
459
_sendLock . Wait ( operationContext . RemainingTimeout , operationContext . CancellationToken ) ;
@@ -770,47 +701,6 @@ private void ThrowOperationCanceledExceptionIfRequired(Exception exception)
770
701
}
771
702
772
703
// nested classes
773
- private class Dropbox
774
- {
775
- private readonly ConcurrentDictionary < int , TaskCompletionSource < IByteBuffer > > _messages = new ConcurrentDictionary < int , TaskCompletionSource < IByteBuffer > > ( ) ;
776
-
777
- // public methods
778
- public void AddException ( Exception exception )
779
- {
780
- foreach ( var taskCompletionSource in _messages . Values )
781
- {
782
- taskCompletionSource . TrySetException ( exception ) ; // has no effect on already completed tasks
783
- }
784
- }
785
-
786
- public void AddMessage ( IByteBuffer message )
787
- {
788
- var responseTo = GetResponseTo ( message ) ;
789
- var tcs = _messages . GetOrAdd ( responseTo , x => new TaskCompletionSource < IByteBuffer > ( ) ) ;
790
- tcs . TrySetResult ( message ) ;
791
- }
792
-
793
- public Task < IByteBuffer > GetMessageAsync ( int responseTo )
794
- {
795
- var tcs = _messages . GetOrAdd ( responseTo , _ => new TaskCompletionSource < IByteBuffer > ( ) ) ;
796
- return tcs . Task ;
797
- }
798
-
799
- public IByteBuffer RemoveMessage ( int responseTo )
800
- {
801
- TaskCompletionSource < IByteBuffer > tcs ;
802
- _messages . TryRemove ( responseTo , out tcs ) ;
803
- return tcs . Task . GetAwaiter ( ) . GetResult ( ) ; // RemoveMessage is only called when Task is complete
804
- }
805
-
806
- // private methods
807
- private int GetResponseTo ( IByteBuffer message )
808
- {
809
- var backingBytes = message . AccessBackingBytes ( 8 ) ;
810
- return BinaryPrimitives . ReadInt32LittleEndian ( new ReadOnlySpan < byte > ( backingBytes . Array , backingBytes . Offset , 4 ) ) ;
811
- }
812
- }
813
-
814
704
private class OpenConnectionHelper
815
705
{
816
706
private readonly BinaryConnection _connection ;
0 commit comments