public void FlushAsyncNotCompletedAfterCancellation()
        {
            var        onCompletedCalled = false;
            PipeWriter writableBuffer    = Pipe.Writer.WriteEmpty(MaximumSizeHigh);

            PipeAwaiter <FlushResult> awaitable = writableBuffer.FlushAsync();

            Assert.False(awaitable.IsCompleted);
            awaitable.OnCompleted(
                () => {
                onCompletedCalled = true;
                Assert.True(awaitable.IsCompleted);

                FlushResult flushResult = awaitable.GetResult();

                Assert.True(flushResult.IsCanceled);

                awaitable = writableBuffer.FlushAsync();
                Assert.False(awaitable.IsCompleted);
            });

            Pipe.Writer.CancelPendingFlush();
            Assert.True(onCompletedCalled);
        }
Пример #2
0
        private async ValueTask WriteBlockSignatures(CancellationToken ct)
        {
            FlushResult flushResult       = default;
            int         writtenSinceFlush = new SignatureHeader().Size;

            while (!flushResult.IsCompleted)
            {
                var readResult = await _reader.Buffer(_options.BlockLength, ct).ConfigureAwait(false);

                if (readResult.Buffer.IsEmpty)
                {
                    return;
                }
                var sig = ComputeSignature(readResult.Buffer);
                _reader.AdvanceTo(readResult.Buffer.End);
                writtenSinceFlush += _writer.Write(sig, _options);
                if (writtenSinceFlush >= _flushThreshhold)
                {
                    flushResult = await _writer.FlushAsync(ct).ConfigureAwait(false);

                    writtenSinceFlush = 0;
                }
            }
        }
    public async Task CancelPendingFlush()
    {
        var streamMock = new Mock <Stream>(MockBehavior.Strict);

        streamMock.SetupGet(s => s.CanWrite).Returns(true);
        var writeCompletedSource = new TaskCompletionSource <object?>();

        // Set up for either WriteAsync method to be called. We expect it will be Memory<T> on .NET Core 2.1 and byte[] on all the others.
#if SPAN_BUILTIN
        streamMock.Setup(s => s.WriteAsync(It.IsAny <ReadOnlyMemory <byte> >(), It.IsAny <CancellationToken>())).Returns(new ValueTask(writeCompletedSource.Task));
#else
        streamMock.Setup(s => s.WriteAsync(It.IsAny <byte[]>(), It.IsAny <int>(), It.IsAny <int>(), It.IsAny <CancellationToken>())).Returns(writeCompletedSource.Task);
#endif

        Stream?    stream = streamMock.Object;
        PipeWriter?writer = this.CreatePipeWriter(stream);
        writer.GetMemory(1);
        writer.Advance(1);
        ValueTask <FlushResult> flushTask = writer.FlushAsync();
        writer.CancelPendingFlush();
        writeCompletedSource.SetResult(null);
        FlushResult flushResult = await flushTask;
        Assert.True(flushResult.IsCanceled);
    }
Пример #4
0
    public async Task ReaderOnly()
    {
        var pipe   = new Pipe();
        var duplex = new DuplexPipe(pipe.Reader);

        // Our assert strategy is to verify our no-op writer behaves the same way as a completed writer.
        pipe.Writer.Complete();
        Assert.Throws <InvalidOperationException>(() => pipe.Writer.GetMemory());
        Assert.Throws <InvalidOperationException>(() => duplex.Output.GetMemory());

        Assert.Throws <InvalidOperationException>(() => pipe.Writer.GetSpan());
        Assert.Throws <InvalidOperationException>(() => duplex.Output.GetSpan());

        // System.IO.Pipelines stopped throwing when Advance(0) is called after completion,
        // But we still feel it's useful to throw since it's a read-only pipe.
        pipe.Writer.Advance(0);
        Assert.Throws <InvalidOperationException>(() => duplex.Output.Advance(0));

        FlushResult flushResult = await pipe.Writer.FlushAsync();

        Assert.False(flushResult.IsCompleted);
        flushResult = await duplex.Output.FlushAsync();

        Assert.False(flushResult.IsCompleted);

        pipe.Writer.CancelPendingFlush();
        duplex.Output.CancelPendingFlush();

#pragma warning disable CS0618 // Type or member is obsolete
        pipe.Writer.OnReaderCompleted((ex, s) => { }, null);
        duplex.Output.OnReaderCompleted((ex, s) => { }, null);
#pragma warning restore CS0618 // Type or member is obsolete

        pipe.Writer.Complete();
        duplex.Output.Complete();
    }
Пример #5
0
        public async Task ProcessAsync(CancellationToken cancellationToken = default)
        {
            var pipe   = new Pipe();
            var writer = pipe.Writer;

            ValueWebSocketReceiveResult receiveresult;

            do
            {
                // Allocate at least 512 bytes from the PipeWriter
                Memory <byte> memory = writer.GetMemory(512);
                try
                {
                    receiveresult = await _socket.ReceiveAsync(memory, cancellationToken);
                }
                catch (WebSocketException ex)
                {
                    _logger.LogWarning("WS {IP} error receiving data: {Message}", RemoteEndPoint, ex.Message);
                    break;
                }

                int bytesRead = receiveresult.Count;
                if (bytesRead == 0)
                {
                    break;
                }

                // Tell the PipeWriter how much was read from the Socket
                writer.Advance(bytesRead);

                // Make the data available to the PipeReader
                FlushResult flushResult = await writer.FlushAsync();

                if (flushResult.IsCompleted)
                {
                    // The PipeReader stopped reading
                    break;
                }

                LastActivityDate = DateTime.UtcNow;

                if (receiveresult.EndOfMessage)
                {
                    await ProcessInternal(pipe.Reader).ConfigureAwait(false);
                }
            } while (
                (_socket.State == WebSocketState.Open || _socket.State == WebSocketState.Connecting) &&
                receiveresult.MessageType != WebSocketMessageType.Close);

            Closed?.Invoke(this, EventArgs.Empty);

            if (_socket.State == WebSocketState.Open ||
                _socket.State == WebSocketState.CloseReceived ||
                _socket.State == WebSocketState.CloseSent)
            {
                await _socket.CloseAsync(
                    WebSocketCloseStatus.NormalClosure,
                    string.Empty,
                    cancellationToken).ConfigureAwait(false);
            }
        }
Пример #6
0
        private async Task ProcessEventStream(IDuplexPipe application, HttpResponseMessage response, CancellationToken cancellationToken)
        {
            Log.StartReceive(_logger);

            using (response)
                using (var stream = await response.Content.ReadAsStreamAsync())
                {
                    var options = new PipeOptions(pauseWriterThreshold: 0, resumeWriterThreshold: 0);
                    var reader  = PipeReaderFactory.CreateFromStream(options, stream, cancellationToken);

                    try
                    {
                        while (true)
                        {
                            var result = await reader.ReadAsync();

                            var buffer   = result.Buffer;
                            var consumed = buffer.Start;
                            var examined = buffer.End;

                            try
                            {
                                if (result.IsCanceled)
                                {
                                    Log.ReceiveCanceled(_logger);
                                    break;
                                }

                                if (!buffer.IsEmpty)
                                {
                                    Log.ParsingSSE(_logger, buffer.Length);

                                    var         parseResult = _parser.ParseMessage(buffer, out consumed, out examined, out var message);
                                    FlushResult flushResult = default;

                                    switch (parseResult)
                                    {
                                    case ServerSentEventsMessageParser.ParseResult.Completed:
                                        Log.MessageToApplication(_logger, message.Length);

                                        flushResult = await _application.Output.WriteAsync(message);

                                        _parser.Reset();
                                        break;

                                    case ServerSentEventsMessageParser.ParseResult.Incomplete:
                                        if (result.IsCompleted)
                                        {
                                            throw new FormatException("Incomplete message.");
                                        }
                                        break;
                                    }

                                    // We canceled in the middle of applying back pressure
                                    // or if the consumer is done
                                    if (flushResult.IsCanceled || flushResult.IsCompleted)
                                    {
                                        Log.EventStreamEnded(_logger);
                                        break;
                                    }
                                }
                                else if (result.IsCompleted)
                                {
                                    break;
                                }
                            }
                            finally
                            {
                                reader.AdvanceTo(consumed, examined);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        _error = ex;
                    }
                    finally
                    {
                        _application.Output.Complete(_error);

                        Log.ReceiveStopped(_logger);

                        reader.Complete();
                    }
                }
        }
Пример #7
0
        private static async Task AcceptAsync(Socket socket)
        {
            Console.WriteLine($"[{socket.RemoteEndPoint}]: connected");

            var  pipe    = new Pipe();
            Task writing = ReadFromSocketAsync(socket, pipe.Writer);
            Task reading = ReadFromPipeAsync(socket, pipe.Reader);

            async Task ReadFromSocketAsync(Socket s, PipeWriter writer)
            {
                const int minimumBufferSize = 512;

                while (true)
                {
                    Memory <byte> memory = writer.GetMemory(minimumBufferSize);
                    int           read   = await socket.ReceiveAsync(memory, SocketFlags.None);

                    if (read == 0)
                    {
                        break;
                    }
                    writer.Advance(read);
                    FlushResult result = await writer.FlushAsync();

                    if (result.IsCompleted)
                    {
                        break;
                    }
                }
                writer.Complete();
            }

            async Task ReadFromPipeAsync(Socket s, PipeReader reader)
            {
                while (true)
                {
                    ReadResult result = await reader.ReadAsync();

                    ReadOnlySequence <byte> buffer   = result.Buffer;
                    SequencePosition?       position = buffer.PositionOf((byte)'\n');

                    if (position != null)
                    {
                        ProcessLine(s, buffer.Slice(0, position.Value));
                        buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
                    }

                    reader.AdvanceTo(buffer.Start, buffer.End);

                    if (result.IsCompleted)
                    {
                        break;
                    }
                }

                reader.Complete();
            }

            await reading;
            await writing;

            Console.WriteLine($"[{socket.RemoteEndPoint}]: disconnected");
        }
Пример #8
0
        /// <summary>
        /// Enables efficiently reading a stream using <see cref="PipeReader"/>.
        /// </summary>
        /// <param name="stream">The stream to read from using a pipe.</param>
        /// <param name="sizeHint">A hint at the size of messages that are commonly transferred. Use 0 for a commonly reasonable default.</param>
        /// <param name="pipeOptions">Optional pipe options to use.</param>
        /// <param name="disposeWhenReaderCompleted">A task which, when complete, signals that this method should dispose of the <paramref name="stream"/>.</param>
        /// <param name="cancellationToken">A cancellation token that aborts reading from the <paramref name="stream"/>.</param>
        /// <returns>A <see cref="PipeReader"/>.</returns>
        /// <remarks>
        /// When the caller invokes <see cref="PipeReader.Complete(Exception)"/> on the result value,
        /// this leads to the associated <see cref="PipeWriter.Complete(Exception)"/> to be automatically called as well.
        /// </remarks>
        private static PipeReader UsePipeReader(this Stream stream, int sizeHint = 0, PipeOptions?pipeOptions = null, Task?disposeWhenReaderCompleted = null, CancellationToken cancellationToken = default)
        {
            Requires.NotNull(stream, nameof(stream));
            Requires.Argument(stream.CanRead, nameof(stream), "Stream must be readable.");

            var pipe = new Pipe(pipeOptions ?? PipeOptions.Default);

            // Notice when the pipe reader isn't listening any more, and terminate our loop that reads from the stream.
            // OBSOLETE API USAGE NOTICE: If at some point we need to stop relying on PipeWriter.OnReaderCompleted (since it is deprecated and may be removed later),
            //                            we can return a decorated PipeReader that calls us from its Complete method directly.
            var combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

#pragma warning disable CS0618 // Type or member is obsolete
            pipe.Writer.OnReaderCompleted((ex, state) => ((CancellationTokenSource)state).Cancel(), combinedTokenSource);

            // When this argument is provided, it provides a means to ensure we don't hang while reading from an I/O pipe
            // that doesn't respect the CancellationToken. Disposing a Stream while reading is a means to terminate the ReadAsync operation.
            if (disposeWhenReaderCompleted is object)
            {
                disposeWhenReaderCompleted.ContinueWith(
                    (_, s1) =>
                {
                    var tuple = (Tuple <Pipe, Stream>)s1;
                    tuple.Item1.Writer.OnReaderCompleted((ex, s2) => ((Stream)s2).Dispose(), tuple.Item2);
                },
                    Tuple.Create(pipe, stream),
                    cancellationToken,
                    TaskContinuationOptions.ExecuteSynchronously,
                    TaskScheduler.Default).Forget();
            }
#pragma warning restore CS0618 // Type or member is obsolete

            Task.Run(async delegate
            {
                while (!combinedTokenSource.Token.IsCancellationRequested)
                {
                    Memory <byte> memory = pipe.Writer.GetMemory(sizeHint);
                    try
                    {
                        int bytesRead = await stream.ReadAsync(memory, combinedTokenSource.Token).ConfigureAwait(false);
                        if (bytesRead == 0)
                        {
                            break;
                        }

                        pipe.Writer.Advance(bytesRead);
                    }
                    catch (OperationCanceledException)
                    {
                        break;
                    }
                    catch (ObjectDisposedException)
                    {
                        break;
                    }
                    catch (Exception ex)
                    {
                        // Propagate the exception to the reader.
                        await pipe.Writer.CompleteAsync(ex).ConfigureAwait(false);
                        return;
                    }

                    FlushResult result = await pipe.Writer.FlushAsync().ConfigureAwait(false);
                    if (result.IsCompleted)
                    {
                        break;
                    }
                }

                // Tell the PipeReader that there's no more data coming
                await pipe.Writer.CompleteAsync().ConfigureAwait(false);
            }).Forget();
            return(pipe.Reader);
        }
Пример #9
0
        private static async Task ProcessProtocolAsync(Socket socket)
        {
            var       pipe = new Pipe();
            const int minimumBufferSize = 1024;

            Memory <byte> memory    = pipe.Writer.GetMemory(minimumBufferSize);
            int           bytesRead = await socket.ReceiveAsync(memory, SocketFlags.None);

            pipe.Writer.Advance(bytesRead);
            FlushResult r = await pipe.Writer.FlushAsync();

            ReadResult result = await pipe.Reader.ReadAsync();

            ReadOnlySequence <byte> buffer = result.Buffer;
            var line = buffer.Slice(0, buffer.Length);
            var bs   = line.ToArray();

            switch (bs[3])
            {
            case 0x03:
                var    domainLength = bs[4];
                string domainName   = System.Text.Encoding.ASCII.GetString(bs, 5, domainLength);
                Console.WriteLine($"{domainName}");
                var ipadderss = Dns.GetHostAddresses(domainName).FirstOrDefault();
                Array.Reverse(bs, bytesRead - 2, 2);
                var    port   = BitConverter.ToInt16(bs, bytesRead - 2);
                Socket remote = new Socket(SocketType.Stream, ProtocolType.Tcp);

                var timeoutTask = Task.Delay(TimeSpan.FromSeconds(2));
                var rec         = remote.ConnectAsync(ipadderss, port);

                var completedTask = await Task.WhenAny(timeoutTask, rec);

                if (completedTask == timeoutTask)
                {
                    socket.Send(new byte[] { 5, 4 });
                    return;
                }

                List <byte> res = new List <byte>();
                res.Add(0x05);
                res.Add(0x00);
                res.Add(0x00);
                res.Add(0x01);
                IPEndPoint localEP = (IPEndPoint)socket.LocalEndPoint;
                res.AddRange(localEP.Address.MapToIPv4().GetAddressBytes());
                res.AddRange(BitConverter.GetBytes((ushort)IPAddress.HostToNetworkOrder(localEP.Port)));
                socket.Send(res.ToArray());

                try
                {
                    Task.WaitAny(ReplayToServer(socket, remote), ReplayToLcoal(remote, socket));
                }
                catch { }


                break;

            default:
                break;
            }
        }
Пример #10
0
        public void Start()
        {
            _processIncoming = Task.Run(async() =>
            {
                try
                {
                    while (true)
                    {
                        var result = _lastReadResult = await MockServicePipe.Input.ReadAsync();
                        if (result.IsCanceled || result.IsCompleted)
                        {
                            break;
                        }

                        var buffer = result.Buffer;

                        try
                        {
                            if (!buffer.IsEmpty)
                            {
                                while (_servicePro.TryParseMessage(ref buffer, out var message))
                                {
                                    // always enqueue so tests can peek and analyze any of these messages
                                    EnqueueMessage(message);

                                    // now react to some of the connection related stuff
                                    if (message is HandshakeRequestMessage)
                                    {
                                        var handshakeResponse = new HandshakeResponseMessage("");
                                        _servicePro.WriteMessage(handshakeResponse, MockServicePipe.Output);
                                        var flushResult = _lastFlushResult = await MockServicePipe.Output.FlushAsync();

                                        if (flushResult.IsCanceled || flushResult.IsCompleted)
                                        {
                                            _completedHandshake.TrySetResult(false);
                                        }
                                        else
                                        {
                                            // sending ack merely allows SDK side to proceed with establishing the connection
                                            // for this service connection to become available for hubs to send messages
                                            // we'd need to wait for SDK side service connection to change its status
                                            _completedHandshake.TrySetResult(true);
                                        }
                                        continue;
                                    }
                                    else if (message is ConnectionDataMessage cdm)
                                    {
                                        var payload = cdm.Payload;

                                        // do we know this client?
                                        var clientConnection = ClientConnections.Where(c => c.ConnectionId == cdm.ConnectionId).FirstOrDefault();
                                        if (clientConnection != null)
                                        {
                                            // is this client expecting handshake response?
                                            if (clientConnection.ExpectsClientHandshake)
                                            {
                                                // todo: maybe try parse first and then check if handshake is expected?
                                                if (HandshakeProtocol.TryParseResponseMessage(ref payload, out var response))
                                                {
                                                    clientConnection.ExpectsClientHandshake = false;
                                                    clientConnection.HandshakeCompleted.TrySetResult(response.Error);
                                                }
                                            }

                                            // There is no such goal to provide full message parsing capabilities here
                                            // But it is useful to know the hub invocation return result in some tests so there we have it.
                                            while (_signalRPro.TryParseMessage(ref payload, MockSvc.CurrentInvocationBinder, out HubMessage hubMessage))
                                            {
                                                clientConnection.EnqueueMessage(hubMessage);

                                                if (hubMessage is CloseMessage closeMsg)
                                                {
                                                    clientConnection.CloseMessageReceivedFromSdk = true;
                                                }
                                            }
                                        }
                                    }
                                    else if (message is ServicePingMessage ping && ping.IsFin())
                                    {
                                        var pong = RuntimeServicePingMessage.GetFinAckPingMessage();
                                        _servicePro.WriteMessage(pong, MockServicePipe.Output);
                                        var flushResult = _lastFlushResult = await MockServicePipe.Output.FlushAsync();

                                        //todo: do we care about this flush result?
                                    }
                                }
                            }
                        }
                        finally
                        {
                            MockServicePipe.Input.AdvanceTo(buffer.Start, buffer.End);
                        }
                    }
                }
                catch (Exception e)
                {
                    _processIncomingException = e;
                }
            });
        }
Пример #11
0
        async Task FillPipeAsync(Socket socket, PipeWriter writer, ClientManager clientManager)
        {
            try
            {
                const int minimumBufferSize = 4 * 1024;

                while (true)
                {
                    // Allocate at least 512 bytes from the PipeWriter
                    Memory <byte> memory = writer.GetMemory(minimumBufferSize);

                    if (MemoryMarshal.TryGetArray(memory, out ArraySegment <byte> arraySegment))
                    {
                        if (!socket.Connected)
                        {
                            break;
                        }

                        int bytesRead = await socket.ReceiveAsync(arraySegment, SocketFlags.None);

                        clientManager.AddToClientsBytesRecieved(bytesRead);

                        if (SocketServer.IsServerCounterEnabled)
                        {
                            PerfStatsColl.IncrementBytesReceivedPerSecStats(bytesRead);
                        }

                        if (bytesRead == 0)
                        {
                            DisposeClient(clientManager);
                            break;
                        }
                        // Tell the PipeWriter how much was read from the Socket
                        writer.Advance(bytesRead);
                    }


                    // Make the data available to the PipeReader
                    FlushResult result = await writer.FlushAsync();

                    if (result.IsCompleted)
                    {
                        break;
                    }
                }

                // Tell the PipeReader that there's no more data coming
                writer.Complete();
                DisposeClient(clientManager);
            }
            catch (SocketException so_ex)
            {
                if (ServerMonitor.MonitorActivity)
                {
                    ServerMonitor.LogClientActivity("ConMgr.RecvClbk", "Error :" + so_ex.ToString());
                }

                DisposeClient(clientManager);
            }
            catch (Exception e)
            {
                var clientIsDisposed = clientManager.IsDisposed;
                DisposeClient(clientManager);

                if (!clientIsDisposed)
                {
                    AppUtil.LogEvent(e.ToString(), EventLogEntryType.Error);
                }

                if (ServerMonitor.MonitorActivity)
                {
                    ServerMonitor.LogClientActivity("ConMgr.RecvClbk", "Error :" + e.ToString());
                }
                if (SocketServer.Logger.IsErrorLogsEnabled)
                {
                    SocketServer.Logger.NCacheLog.Error("ConnectionManager.ReceiveCallback", clientManager.ToString() + " Error " + e.ToString());
                }

                try
                {
                    if (Management.APILogging.APILogManager.APILogManger != null && Management.APILogging.APILogManager.EnableLogging)
                    {
                        APILogItemBuilder log = new APILogItemBuilder();
                        log.GenerateConnectionManagerLog(clientManager, e.ToString());
                    }
                }
                catch
                {
                }
            }
            finally
            {
                //  clientManager.StopCommandExecution();
                if (ServerMonitor.MonitorActivity)
                {
                    ServerMonitor.StopClientActivity(clientManager.ClientID);
                }
            }
        }
Пример #12
0
        public async Task RespondToWebSocketRequestAsync(WebSocket webSocket, CancellationToken token, PipeWriter pipeWriter)
        {
            if (!myIsPipelineImplementation)
            {
                ArraySegment <byte> buffer = new ArraySegment <byte>(new byte[myBufferSize]);
                try
                {
                    while (true)
                    {
                        WebSocketReceiveResult result = await webSocket.ReceiveAsync(buffer, token);

                        if (receivedMessages == 0)
                        {
                            Console.WriteLine($"Started!!");
                            stopwatch = Stopwatch.StartNew();
                            stopwatch.Start();
                        }
                        receivedMessages++;

                        if (myIsProtobufSerializationEnabled)
                        {
                            using (var stream = new MemoryStream(buffer.Array, 0, result.Count))
                            {
                                var person = Serializer.Deserialize <Person>(stream);
                            }
                        }
                        if (result.MessageType == WebSocketMessageType.Close)
                        {
                            _logger.LogInformation($"Client initiated close. Status: {result.CloseStatus} Description: {result.CloseStatusDescription}");
                            break;
                        }

                        if (result.Count > myBufferSize)
                        {
                            await webSocket.CloseAsync(WebSocketCloseStatus.MessageTooBig,
                                                       $"Web socket frame cannot exceed buffer size of {myBufferSize:#,##0} bytes. Send multiple frames instead.",
                                                       token);

                            break;
                        }
                        if (receivedMessages == Constants.NoOfIterations)
                        {
                            Console.WriteLine($"Completed in {stopwatch.Elapsed.TotalMilliseconds:#,##0.00} ms");
                        }

                        ArraySegment <byte> toSend = new ArraySegment <byte>(buffer.Array, buffer.Offset, result.Count);
                        await webSocket.SendAsync(toSend, WebSocketMessageType.Binary, true, token);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
            else
            {
                while (true)
                {
                    try
                    {
                        Memory <byte>          memory = pipeWriter.GetMemory(myBufferSize);
                        WebSocketReceiveResult result = await webSocket.ReceiveAsync(memory);

                        if (receivedMessages == 0)
                        {
                            Console.WriteLine($"Started!!");
                            stopwatch = Stopwatch.StartNew();
                            stopwatch.Start();
                            receivedMessages++;
                        }
                        if (result.MessageType == WebSocketMessageType.Close)
                        {
                            _logger.LogInformation($"Client initiated close. Status: {result.CloseStatus} Description: {result.CloseStatusDescription}");
                            break;
                        }

                        if (result.Count > myBufferSize)
                        {
                            await webSocket.CloseAsync(WebSocketCloseStatus.MessageTooBig,
                                                       $"Web socket frame cannot exceed buffer size of {myBufferSize:#,##0} bytes. Send multiple frames instead.",
                                                       token);

                            break;
                        }
                        pipeWriter.Advance(result.Count);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                        break;
                    }
                    // Make the data available to the PipeReader
                    FlushResult flushResult = await pipeWriter.FlushAsync();

                    if (flushResult.IsCompleted)
                    {
                        break;
                    }
                }
                // Signal to the reader that we're done writing
                pipeWriter.Complete();
            }
        }
Пример #13
0
        /// <summary>
        /// Forwards all bytes coming from a <see cref="PipeReader"/> to the specified <see cref="PipeWriter"/>.
        /// </summary>
        /// <param name="reader">The reader to get bytes from.</param>
        /// <param name="writer">The writer to copy bytes to. <see cref="PipeWriter.CompleteAsync(Exception)"/> will be called on this object when the reader completes or an error occurs.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <returns>
        /// A <see cref="Task"/> that completes when the <paramref name="reader"/> has finished producing bytes, or an error occurs.
        /// This <see cref="Task"/> never faults, since any exceptions are used to complete the <paramref name="writer"/>.
        /// </returns>
        /// <remarks>
        /// If an error occurs during reading or writing, the <paramref name="writer"/> and <paramref name="reader"/> are completed with the exception.
        /// </remarks>
        internal static Task LinkToAsync(this PipeReader reader, PipeWriter writer, CancellationToken cancellationToken = default)
        {
            Requires.NotNull(reader, nameof(reader));
            Requires.NotNull(writer, nameof(writer));

            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled(cancellationToken));
            }

            return(Task.Run(async delegate
            {
                try
                {
                    if (DuplexPipe.IsDefinitelyCompleted(reader))
                    {
                        await writer.CompleteAsync().ConfigureAwait(false);
                        return;
                    }

                    while (true)
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        ReadResult result = await reader.ReadAsync(cancellationToken).ConfigureAwait(false);
                        if (result.IsCanceled)
                        {
                            cancellationToken.ThrowIfCancellationRequested();
                            throw new OperationCanceledException(Strings.PipeReaderCanceled);
                        }

                        writer.Write(result.Buffer);
                        reader.AdvanceTo(result.Buffer.End);
                        result.ScrubAfterAdvanceTo();
                        FlushResult flushResult = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);

                        if (flushResult.IsCanceled)
                        {
                            cancellationToken.ThrowIfCancellationRequested();
                            throw new OperationCanceledException(Strings.PipeWriterFlushCanceled);
                        }

                        if (flushResult.IsCompleted)
                        {
                            // Break out of copy loop. The receiver doesn't care any more.
                            break;
                        }

                        if (result.IsCompleted)
                        {
                            await writer.CompleteAsync().ConfigureAwait(false);
                            break;
                        }
                    }

                    await reader.CompleteAsync().ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    await writer.CompleteAsync(ex).ConfigureAwait(false);
                    await reader.CompleteAsync(ex).ConfigureAwait(false);
                }
            }));
        }
    private Task WrapAsync(IShadowsocksCrypto decryptor, CancellationToken cancellationToken)
    {
        return(Task.Run(
                   async() =>
        {
            try
            {
                while (true)
                {
                    ReadResult result = await InternalReader.ReadAndCheckIsCanceledAsync(cancellationToken);
                    ReadOnlySequence <byte> buffer = result.Buffer;

                    try
                    {
                        while (!buffer.IsEmpty)
                        {
                            long oldLength = buffer.Length;

                            Memory <byte> memory = Writer.GetMemory(BufferSize);

                            int outLength = decryptor.DecryptTCP(ref buffer, memory.Span);

                            Writer.Advance(outLength);
                            if (outLength > 0)
                            {
                                FlushResult writerFlushResult = await Writer.FlushAsync(cancellationToken);
                                if (writerFlushResult.IsCompleted)
                                {
                                    goto NoData;
                                }
                            }

                            if (oldLength == buffer.Length)
                            {
                                break;
                            }
                        }

                        if (result.IsCompleted)
                        {
                            break;
                        }
                    }
                    finally
                    {
                        InternalReader.AdvanceTo(buffer.Start, buffer.End);
                    }
                }
                NoData:
                await Writer.CompleteAsync();
            }
            catch (Exception ex)
            {
                await Writer.CompleteAsync(ex);
            }
            finally
            {
                decryptor.Dispose();
            }
        },
                   default
                   ));
    }
Пример #15
0
 internal static bool HasMore(
     this FlushResult readResult)
 => readResult.IsCanceled == false &&
 readResult.IsCompleted == false;
Пример #16
0
        private async Task OpenConnection(IDuplexPipe application, Uri url, TaskCompletionSource <object> startTcs, CancellationToken cancellationToken)
        {
            Log.StartReceive(_logger);

            var request = new HttpRequestMessage(HttpMethod.Get, url);

            request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));

            HttpResponseMessage response = null;

            try
            {
                response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

                response.EnsureSuccessStatusCode();
                startTcs.TrySetResult(null);
            }
            catch (Exception ex)
            {
                response?.Dispose();
                Log.TransportStopping(_logger);
                startTcs.TrySetException(ex);
                return;
            }

            using (response)
                using (var stream = await response.Content.ReadAsStreamAsync())
                {
                    var pipeOptions    = new PipeOptions(pauseWriterThreshold: 0, resumeWriterThreshold: 0);
                    var pipelineReader = StreamPipeConnection.CreateReader(pipeOptions, stream);
                    var readCancellationRegistration = cancellationToken.Register(
                        reader => ((PipeReader)reader).CancelPendingRead(), pipelineReader);
                    try
                    {
                        while (true)
                        {
                            var result = await pipelineReader.ReadAsync();

                            var input = result.Buffer;
                            if (result.IsCanceled || (input.IsEmpty && result.IsCompleted))
                            {
                                Log.EventStreamEnded(_logger);
                                break;
                            }

                            var consumed = input.Start;
                            var examined = input.End;
                            try
                            {
                                Log.ParsingSSE(_logger, input.Length);
                                var         parseResult = _parser.ParseMessage(input, out consumed, out examined, out var buffer);
                                FlushResult flushResult = default;

                                switch (parseResult)
                                {
                                case ServerSentEventsMessageParser.ParseResult.Completed:
                                    Log.MessageToApp(_logger, buffer.Length);

                                    flushResult = await _application.Output.WriteAsync(buffer);

                                    _parser.Reset();
                                    break;

                                case ServerSentEventsMessageParser.ParseResult.Incomplete:
                                    if (result.IsCompleted)
                                    {
                                        throw new FormatException("Incomplete message.");
                                    }
                                    break;
                                }

                                // We canceled in the middle of applying back pressure
                                // or if the consumer is done
                                if (flushResult.IsCanceled || flushResult.IsCompleted)
                                {
                                    break;
                                }
                            }
                            finally
                            {
                                pipelineReader.AdvanceTo(consumed, examined);
                            }
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        Log.ReceiveCanceled(_logger);
                    }
                    catch (Exception ex)
                    {
                        _error = ex;
                    }
                    finally
                    {
                        _application.Output.Complete(_error);

                        readCancellationRegistration.Dispose();

                        Log.ReceiveStopped(_logger);
                    }
                }
        }