예제 #1
0
        internal override async ValueTask <int> ReadAsync(Memory <byte> destination, CancellationToken cancellationToken = default)
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(this);
            }

            ThrowIfDisposed();

            if (!_canRead)
            {
                throw new InvalidOperationException("Reading is not allowed on stream.");
            }

            lock (_sync)
            {
                if (_readState == ReadState.ReadsCompleted)
                {
                    if (NetEventSource.IsEnabled)
                    {
                        NetEventSource.Exit(this);
                    }
                    return(0);
                }
                else if (_readState == ReadState.Aborted)
                {
                    throw _readErrorCode switch
                          {
                              -1 => new QuicOperationAbortedException(),
                              long err => new QuicStreamAbortedException(err)
                          };
                }
            }

            using CancellationTokenRegistration registration = cancellationToken.Register(() =>
            {
                bool shouldComplete = false;
                lock (_sync)
                {
                    if (_readState == ReadState.None)
                    {
                        shouldComplete = true;
                    }

                    _readState = ReadState.Aborted;
                }

                if (shouldComplete)
                {
                    _receiveResettableCompletionSource.CompleteException(new OperationCanceledException("Read was canceled", cancellationToken));
                }
            });

            // TODO there could potentially be a perf gain by storing the buffer from the inital read
            // This reduces the amount of async calls, however it makes it so MsQuic holds onto the buffers
            // longer than it needs to. We will need to benchmark this.
            int length = (int)await _receiveResettableCompletionSource.GetValueTask().ConfigureAwait(false);

            int actual = Math.Min(length, destination.Length);
예제 #2
0
        private uint HandleEventShutdownInitiatedByTransport(ConnectionEvent connectionEvent)
        {
            if (!_connected)
            {
                _connectTcs.CompleteException(new IOException("Connection has been shutdown."));
            }

            _acceptQueue.Writer.Complete();


            return(MsQuicStatusCodes.Success);
        }
예제 #3
0
        private async ValueTask <CancellationTokenRegistration> HandleWriteStartState(CancellationToken cancellationToken)
        {
            if (!_canWrite)
            {
                throw new InvalidOperationException("Writing is not allowed on stream.");
            }

            lock (_sync)
            {
                if (_sendState == SendState.Aborted)
                {
                    throw new OperationCanceledException("Sending has already been aborted on the stream");
                }
            }

            CancellationTokenRegistration registration = cancellationToken.Register(() =>
            {
                bool shouldComplete = false;
                lock (_sync)
                {
                    if (_sendState == SendState.None)
                    {
                        _sendState     = SendState.Aborted;
                        shouldComplete = true;
                    }
                }

                if (shouldComplete)
                {
                    _sendResettableCompletionSource.CompleteException(new OperationCanceledException("Write was canceled", cancellationToken));
                }
            });

            // Make sure start has completed
            if (!_started)
            {
                await _sendResettableCompletionSource.GetTypelessValueTask().ConfigureAwait(false);

                _started = true;
            }

            return(registration);
        }
예제 #4
0
        private async ValueTask <CancellationTokenRegistration> HandleWriteStartState(CancellationToken cancellationToken)
        {
            if (!_canWrite)
            {
                throw new InvalidOperationException("Writing is not allowed on stream.");
            }

            lock (_sync)
            {
                if (_sendState == SendState.Aborted)
                {
                    throw new OperationCanceledException("Sending has already been aborted on the stream");
                }
            }
            CancellationTokenRegistration registration = cancellationToken.Register(() =>
            {
                bool shouldComplete = false;
                lock (_sync)
                {
                    if (_sendState == SendState.None)
                    {
                        _sendState     = SendState.Aborted;
                        shouldComplete = true;
                    }
                }

                if (shouldComplete)
                {
                    _sendResettableCompletionSource.CompleteException(new OperationCanceledException("Write was canceled"));
                }
            });

            // Implicit start on first write.
            if (_started == StartState.None)
            {
                _started = StartState.Started;

                // TODO can optimize this by not having this method be async.
                await StartWritesAsync();
            }

            return(registration);
        }
        private uint HandleEventShutdownInitiatedByTransport(ConnectionEvent connectionEvent)
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(this);
            }

            if (!_connected)
            {
                _connectTcs.CompleteException(new IOException("Connection has been shutdown."));
            }

            _acceptQueue.Writer.Complete();

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Exit(this);
            }

            return(MsQuicStatusCodes.Success);
        }
예제 #6
0
        internal override async ValueTask WriteAsync(ReadOnlyMemory <byte> buffer, bool endStream, CancellationToken cancellationToken = default)
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(this);
            }

            ThrowIfDisposed();

            if (!_canWrite)
            {
                throw new InvalidOperationException("Writing is not allowed on stream.");
            }

            lock (_sync)
            {
                if (_sendState == SendState.Aborted)
                {
                    throw new OperationCanceledException("Sending has already been aborted on the stream");
                }
            }

            using CancellationTokenRegistration registration = cancellationToken.Register(() =>
            {
                bool shouldComplete = false;
                lock (_sync)
                {
                    if (_sendState == SendState.None)
                    {
                        _sendState     = SendState.Aborted;
                        shouldComplete = true;
                    }
                }

                if (shouldComplete)
                {
                    _sendResettableCompletionSource.CompleteException(new OperationCanceledException("Write was canceled"));
                }
            });

            // Implicit start on first write.
            if (_started == StartState.None)
            {
                _started = StartState.Started;
                await StartWritesAsync();
            }

            await SendAsync(buffer, endStream?QUIC_SEND_FLAG.FIN : QUIC_SEND_FLAG.NONE);

            lock (_sync)
            {
                if (_sendState == SendState.Finished)
                {
                    _sendState = SendState.None;
                }
            }

            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Exit(this);
            }
        }