Ejemplo n.º 1
0
        public async Task StartAsync(Uri url, IDuplexPipe application, TransferMode requestedTransferMode, IConnection connection)
        {
            if (url == null)
            {
                throw new ArgumentNullException(nameof(url));
            }

            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            if (requestedTransferMode != TransferMode.Binary && requestedTransferMode != TransferMode.Text)
            {
                throw new ArgumentException("Invalid transfer mode.", nameof(requestedTransferMode));
            }

            _application = application;
            Mode         = requestedTransferMode;

            _logger.StartTransport(Mode.Value);

            await Connect(url);

            var sendTask    = SendMessages();
            var receiveTask = ReceiveMessages();

            // TODO: Handle TCP connection errors
            // https://github.com/SignalR/SignalR/blob/1fba14fa3437e24c204dfaf8a18db3fce8acad3c/src/Microsoft.AspNet.SignalR.Core/Owin/WebSockets/WebSocketHandler.cs#L248-L251
            Running = Task.WhenAll(sendTask, receiveTask).ContinueWith(t =>
            {
                _webSocket.Dispose();
                _logger.TransportStopped(t.Exception?.InnerException);

                _application.Output.Complete(t.Exception?.InnerException);
                _application.Input.Complete();

                return(t);
            }).Unwrap();
        }
Ejemplo n.º 2
0
        public async Task StartAsync(Uri url, TransferFormat transferFormat)
        {
            if (url == null)
            {
                throw new ArgumentNullException(nameof(url));
            }

            if (transferFormat != TransferFormat.Binary && transferFormat != TransferFormat.Text)
            {
                throw new ArgumentException($"The '{transferFormat}' transfer format is not supported by this transport.", nameof(transferFormat));
            }

            _webSocketMessageType = transferFormat == TransferFormat.Binary
                ? WebSocketMessageType.Binary
                : WebSocketMessageType.Text;

            var resolvedUrl = ResolveWebSocketsUrl(url);

            Log.StartTransport(_logger, transferFormat, resolvedUrl);

            if (_accessTokenFactory != null)
            {
                var accessToken = await _accessTokenFactory();

                _webSocket.Options.SetRequestHeader("Authorization", $"Bearer {accessToken}");
            }

            await _webSocket.ConnectAsync(resolvedUrl, CancellationToken.None);

            // Create the pipe pair (Application's writer is connected to Transport's reader, and vice versa)
            var options = ClientPipeOptions.DefaultOptions;
            var pair    = DuplexPipe.CreateConnectionPair(options, options);

            _transport   = pair.Transport;
            _application = pair.Application;

            // TODO: Handle TCP connection errors
            // https://github.com/SignalR/SignalR/blob/1fba14fa3437e24c204dfaf8a18db3fce8acad3c/src/Microsoft.AspNet.SignalR.Core/Owin/WebSockets/WebSocketHandler.cs#L248-L251
            Running = ProcessSocketAsync(_webSocket);
        }
        private async Task ProcessEventStream(string url, IDuplexPipe application, CancellationToken transportCtsToken)
        {
            Log.StartReceive(_logger);

            try
            {
                // Creates a task to represent the SSE js processing
                TaskCompletionSource <object> task = new TaskCompletionSource <object>();
                _jsTask = task;

                // Create connection
                ((IJSInProcessRuntime)JSRuntime.Current).Invoke <object>(
                    "BlazorSignalR.ServerSentEventsTransport.CreateConnection", url, new DotNetObjectRef(this));

                // If canceled, stop fake processing
                transportCtsToken.Register(() => { task.SetCanceled(); });

                // Wait until js side stops
                await task.Task;

                if (task.Task.IsCanceled)
                {
                    Log.ReceiveCanceled(_logger);
                }
            }
            catch (Exception ex)
            {
                _logger.LogDebug($"SSE JS Side error {ex.Message}");
                _error = ex;
            }
            finally
            {
                _application.Output.Complete(_error);

                Log.ReceiveStopped(_logger);

                // Close JS side SSE
                CloseSSE();
            }
        }
Ejemplo n.º 4
0
        public async Task ConvertUplink(IDuplexPipe client, IDuplexPipe server)
        {
            using var up = cryptoParameter.GetCrypto();
            var pmp  = new ProtocolMessagePipe(server);
            var salt = new SaltMessage(16, true);
            await pmp.WriteAsync(salt);

            var key = new byte[cryptoParameter.KeySize];

            HKDF.DeriveKey(HashAlgorithmName.SHA1, mainKey, key, salt.Salt.Span, _ssSubKeyInfo);
            up.Init(key, null);
            Memory <byte> nonce = new byte[cryptoParameter.NonceSize];

            nonce.Span.Fill(0);
            // TODO write salt with data
            while (true)
            {
                var result = await client.Input.ReadAsync();

                if (result.IsCanceled || result.IsCompleted)
                {
                    return;
                }

                // TODO compress into one chunk when possible

                foreach (var item in result.Buffer)
                {
                    foreach (var i in SplitBigChunk(item))
                    {
                        await pmp.WriteAsync(new AeadBlockMessage(up, nonce, cryptoParameter)
                        {
                            // in send routine, Data is readonly
                            Data = MemoryMarshal.AsMemory(i),
                        });
                    }
                }
                client.Input.AdvanceTo(result.Buffer.End);
            }
        }
Ejemplo n.º 5
0
        internal SocketConnection(Socket socket,
                                  MemoryPool <byte> memoryPool,
                                  PipeScheduler transportScheduler,
                                  ISocketsTrace trace,
                                  SocketSenderPool socketSenderPool,
                                  PipeOptions inputOptions,
                                  PipeOptions outputOptions,
                                  bool waitForData = true)
        {
            Debug.Assert(socket != null);
            Debug.Assert(memoryPool != null);
            Debug.Assert(trace != null);

            _socket           = socket;
            MemoryPool        = memoryPool;
            _trace            = trace;
            _waitForData      = waitForData;
            _socketSenderPool = socketSenderPool;

            LocalEndPoint  = _socket.LocalEndPoint;
            RemoteEndPoint = _socket.RemoteEndPoint;

            ConnectionClosed = _connectionClosedTokenSource.Token;

            // On *nix platforms, Sockets already dispatches to the ThreadPool.
            // Yes, the IOQueues are still used for the PipeSchedulers. This is intentional.
            // https://github.com/aspnet/KestrelHttpServer/issues/2573
            var awaiterScheduler = OperatingSystem.IsWindows() ? transportScheduler : PipeScheduler.Inline;

            _receiver = new SocketReceiver(awaiterScheduler);

            var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);

            _originalTransport = pair.Transport;
            Application        = pair.Application;

            Transport = new SocketDuplexPipe(this);

            InitializeFeatures();
        }
Ejemplo n.º 6
0
    public async Task UsePipe_Stream_PropagatesException()
    {
        var         stream = new MockInterruptedFullDuplexStream();
        IDuplexPipe pipe   = stream.UsePipe(cancellationToken: this.TimeoutToken);

        await Assert.ThrowsAsync <IOException>(async() =>
        {
            while (!this.TimeoutToken.IsCancellationRequested)
            {
                var readResult = await pipe.Input.ReadAsync(this.TimeoutToken);
                pipe.Input.AdvanceTo(readResult.Buffer.End);
            }
        });

        await Assert.ThrowsAsync <IOException>(async() =>
        {
            while (!this.TimeoutToken.IsCancellationRequested)
            {
                await pipe.Output.WriteAsync(new byte[1], this.TimeoutToken);
            }
        });
    }
Ejemplo n.º 7
0
        public async Task <bool> IsMyClient(IDuplexPipe pipe)
        {
            var result = await pipe.Input.ReadAsync();

            pipe.Input.AdvanceTo(result.Buffer.Start);
            var buffer = result.Buffer;

            if (buffer.Length < 3)
            {
                return(false);
            }
            if (buffer.First.Span[0] != 5)
            {
                return(false);
            }
            if (buffer.First.Span[1] == 0)
            {
                return(false);
            }
            // ver 5, has auth method
            return(true);
        }
Ejemplo n.º 8
0
            internal TService Create(
                IDuplexPipe pipe,
                IServiceProvider hostProvidedServices,
                ServiceActivationOptions serviceActivationOptions,
                IServiceBroker serviceBroker)
            {
                // Register this service broker globally (if it's the first we encounter) so it can be used by other
                // global services that need it.
                GlobalServiceBroker.RegisterServiceBroker(serviceBroker);

                var descriptor            = ServiceDescriptors.Instance.GetServiceDescriptorForServiceFactory(typeof(TService));
                var serviceHubTraceSource = (TraceSource)hostProvidedServices.GetService(typeof(TraceSource));
                var serverConnection      = descriptor.WithTraceSource(serviceHubTraceSource).ConstructRpcConnection(pipe);

                var args    = new ServiceConstructionArguments(hostProvidedServices, serviceBroker);
                var service = CreateService(args, descriptor, serverConnection, serviceActivationOptions.ClientRpcTarget);

                serverConnection.AddLocalRpcTarget(service);
                serverConnection.StartListening();

                return(service);
            }
Ejemplo n.º 9
0
        public WebSocketsTransport(WebSocketOptions options, IDuplexPipe application, HttpConnectionContext connection, ILoggerFactory loggerFactory)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            if (loggerFactory == null)
            {
                throw new ArgumentNullException(nameof(loggerFactory));
            }

            _options     = options;
            _application = application;
            _connection  = connection;
            _logger      = loggerFactory.CreateLogger <WebSocketsTransport>();
        }
Ejemplo n.º 10
0
        public async Task StartAsync(Uri url, TransferFormat transferFormat)
        {
            if (transferFormat != TransferFormat.Text)
            {
                throw new ArgumentException($"The '{transferFormat}' transfer format is not supported by this transport.", nameof(transferFormat));
            }

            Log.StartTransport(_logger, transferFormat);

            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.None);

                response.EnsureSuccessStatusCode();
            }
            catch
            {
                response?.Dispose();

                Log.TransportStopping(_logger);

                throw;
            }

            // Create the pipe pair (Application's writer is connected to Transport's reader, and vice versa)
            var options = ClientPipeOptions.DefaultOptions;
            var pair    = DuplexPipe.CreateConnectionPair(options, options);

            _transport   = pair.Transport;
            _application = pair.Application;

            Running = ProcessAsync(url, response);
        }
        public async Task StartAsync(Uri url, TransferFormat transferFormat)
        {
            if (url == null)
            {
                throw new ArgumentNullException(nameof(url));
            }

            if (transferFormat != TransferFormat.Binary && transferFormat != TransferFormat.Text)
            {
                throw new ArgumentException(
                          $"The '{transferFormat}' transfer format is not supported by this transport.",
                          nameof(transferFormat));
            }


            Log.StartTransport(_logger, transferFormat);

            // Create connection
            _startTask = new TaskCompletionSource <object>();
            await _jsRuntime.InvokeAsync <object>(
                "BlazorSignalR.WebSocketsTransport.CreateConnection", url.ToString(),
                transferFormat == TransferFormat.Binary, new DotNetObjectRef(this));

            await _startTask.Task;

            _startTask = null;

            Log.StartedTransport(_logger);

            // Create the pipe pair (Application's writer is connected to Transport's reader, and vice versa)
            PipeOptions options = ClientPipeOptions.DefaultOptions;

            DuplexPipe.DuplexPipePair pair = DuplexPipe.CreateConnectionPair(options, options);

            _transport   = pair.Transport;
            _application = pair.Application;

            Running = ProcessSocketAsync();
        }
Ejemplo n.º 12
0
        public Http1ConnectionTests()
        {
            _pipelineFactory = new MemoryPool();
            var pair = DuplexPipe.CreateConnectionPair(_pipelineFactory);

            _transport   = pair.Transport;
            _application = pair.Application;

            _serviceContext         = new TestServiceContext();
            _timeoutControl         = new Mock <ITimeoutControl>();
            _http1ConnectionContext = new Http1ConnectionContext
            {
                ServiceContext     = _serviceContext,
                ConnectionFeatures = new FeatureCollection(),
                MemoryPool         = _pipelineFactory,
                TimeoutControl     = _timeoutControl.Object,
                Application        = pair.Application,
                Transport          = pair.Transport
            };

            _http1Connection = new TestHttp1Connection(_http1ConnectionContext);
            _http1Connection.Reset();
        }
Ejemplo n.º 13
0
        /// <inheritdoc />
        public void Disconnect()
        {
            using var scope = this.logger.BeginScope(this.remoteEndPoint);
            if (this.disconnected)
            {
                this.logger.LogDebug("Connection already disconnected.");
                return;
            }

            this.logger.LogDebug("Disconnecting...");
            if (this.duplexPipe != null)
            {
                this.Source.Complete();
                this.Output.Complete();
                (this.duplexPipe as IDisposable)?.Dispose();
                this.duplexPipe = null;
            }

            this.logger.LogDebug("Disconnected");
            this.disconnected = true;

            this.Disconnected?.Invoke(this, System.EventArgs.Empty);
        }
        public HttpProtocolFeatureCollectionTests()
        {
            _memoryPool = KestrelMemoryPool.Create();
            var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
            var pair    = DuplexPipe.CreateConnectionPair(options, options);

            _transport   = pair.Transport;
            _application = pair.Application;

            _serviceContext         = new TestServiceContext();
            _http1ConnectionContext = new HttpConnectionContext
            {
                ServiceContext     = _serviceContext,
                ConnectionFeatures = new FeatureCollection(),
                MemoryPool         = _memoryPool,
                TimeoutControl     = Mock.Of <ITimeoutControl>(),
                Transport          = pair.Transport
            };

            _http1Connection = new TestHttp1Connection(_http1ConnectionContext);
            _http1Connection.Reset();
            _collection = _http1Connection;
        }
Ejemplo n.º 15
0
        public async Task ConnectAsync()
        {
            switch (_endPoint)
            {
            case IPEndPoint ipEndPoint:
                await _client.ConnectAsync(ipEndPoint.Address, ipEndPoint.Port);

                break;

            case DnsEndPoint dnsEndPoint:
                await _client.ConnectAsync(dnsEndPoint.Host, dnsEndPoint.Port);

                break;

            default:
                throw new NotSupportedException($"Unsupported endpoint type: {_endPoint.GetType().FullName}");
            }

            // Start processing
            _pipe = _client.GetStream().CreatePipe();

            _ = ReceiveLoop(_pipe.Input);
        }
Ejemplo n.º 16
0
    public async Task UsePipe_Stream_OneDirectionDoesNotDispose(bool completeOutput)
    {
        var         ms   = new HalfDuplexStream();
        IDuplexPipe pipe = ms.UsePipe(cancellationToken: this.TimeoutToken);

        if (completeOutput)
        {
            pipe.Output.Complete();
        }
        else
        {
            pipe.Input.Complete();
        }

        var timeout = ExpectedTimeoutToken;

        while (!ms.IsDisposed && !timeout.IsCancellationRequested)
        {
            await Task.Yield();
        }

        Assert.False(ms.IsDisposed);
    }
Ejemplo n.º 17
0
        public PipeSocket(Socket socket,
                          MemoryPool <byte> memoryPool,
                          PipeScheduler scheduler,
                          long?maxReadBufferSize  = null,
                          long?maxWriteBufferSize = null,
                          bool waitForData        = true)
        {
            _socket      = socket;
            MemoryPool   = memoryPool;
            _waitForData = waitForData;
            // On *nix platforms, Sockets already dispatches to the ThreadPool.
            // Yes, the IOQueues are still used for the PipeSchedulers. This is intentional.
            // https://github.com/aspnet/KestrelHttpServer/issues/2573
            // var awaiterScheduler = IsWindows ? scheduler : PipeScheduler.Inline;

            maxReadBufferSize ??= 0;
            maxWriteBufferSize ??= 0;

            var inputOptions  = new PipeOptions(MemoryPool, PipeScheduler.ThreadPool, scheduler, maxReadBufferSize.Value, maxReadBufferSize.Value / 2, useSynchronizationContext: false);
            var outputOptions = new PipeOptions(MemoryPool, scheduler, PipeScheduler.ThreadPool, maxWriteBufferSize.Value, maxWriteBufferSize.Value / 2, useSynchronizationContext: false);

            var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);


            Transport   = pair.Transport;
            Application = pair.Application;



            var awaiterScheduler = IsWindows ? scheduler : PipeScheduler.Inline;

            _receiver = new SocketReceiver(_socket, awaiterScheduler);
            _sender   = new SocketSender(_socket, awaiterScheduler);

            maxReadBufferSize ??= 0;
            maxWriteBufferSize ??= 0;
        }
Ejemplo n.º 18
0
        private static async Task PongServer(IDuplexPipe connection)
        {
            ArraySegment <byte> _ping = new ArraySegment <byte>(Encoding.ASCII.GetBytes("PING"));
            ArraySegment <byte> _pong = new ArraySegment <byte>(Encoding.ASCII.GetBytes("PING"));

            while (true)
            {
                var result = await connection.Input.ReadAsync();

                var inputBuffer = result.Buffer;

                if (inputBuffer.IsEmpty && result.IsCompleted)
                {
                    connection.Input.AdvanceTo(inputBuffer.End);
                    break;
                }

                if (inputBuffer.Length < 4)
                {
                    connection.Input.AdvanceTo(inputBuffer.Start, inputBuffer.End);
                }
                else
                {
                    bool isPing = inputBuffer.EqualsTo(_ping);
                    if (isPing)
                    {
                        await connection.Output.WriteAsync(_pong);
                    }
                    else
                    {
                        break;
                    }

                    connection.Input.AdvanceTo(inputBuffer.End);
                }
            }
        }
Ejemplo n.º 19
0
        public async Task AcceptWritablePipe(IDuplexPipe content, int lengthToWrite, CancellationToken cancellationToken)
        {
            // Assert that the pipe is not readable.
            ReadResult readResult = await content.Input.ReadAsync(cancellationToken);

            Assert.Equal(0, readResult.Buffer.Length);
            Assert.True(readResult.IsCompleted);

            const int ChunkSize    = 5;
            int       writtenBytes = 0;

            while (writtenBytes < lengthToWrite)
            {
                // Write in small chunks to verify that it needn't be written all at once.
                int bytesToWrite = Math.Min(lengthToWrite - writtenBytes, ChunkSize);
                await content.Output.WriteAsync(MemoryBuffer.AsMemory(writtenBytes, bytesToWrite), cancellationToken);

                await content.Output.FlushAsync(cancellationToken);

                writtenBytes += bytesToWrite;
            }

            content.Output.Complete();
        }
Ejemplo n.º 20
0
        public async Task WrappedStream_Success()
        {
            var bytesA = Encoding.ASCII.GetBytes("foo");
            var bytesB = Encoding.ASCII.GetBytes("bar");

            var stream = new MemoryStream();

            stream.Write(bytesA);
            stream.Position = 0;

            var con = new MockConnection();

            con.OnCreateStream = () => stream;

            IDuplexPipe pipe = con.Pipe;

            ReadResult res = await pipe.Input.ReadAsync();

            Assert.Equal(bytesA, res.Buffer.ToArray());

            await pipe.Output.WriteAsync(bytesB);

            Assert.Equal(bytesA.Concat(bytesB).ToArray(), stream.ToArray());
        }
Ejemplo n.º 21
0
        public WebSocketsServerTransport(WebSocketOptions options, IDuplexPipe application, HttpConnectionContext connection, ILoggerFactory loggerFactory)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (application == null)
            {
                throw new ArgumentNullException(nameof(application));
            }

            if (loggerFactory == null)
            {
                throw new ArgumentNullException(nameof(loggerFactory));
            }

            _options     = options;
            _application = application;
            _connection  = connection;

            // We create the logger with a string to preserve the logging namespace after the server side transport renames.
            _logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport");
        }
Ejemplo n.º 22
0
        public Task StartAsync(Uri url, TransferFormat transferFormat, CancellationToken cancellationToken)
        {
            if (transferFormat != TransferFormat.Text)
            {
                throw new ArgumentException(
                          $"The '{transferFormat}' transfer format is not supported by this transport.",
                          nameof(transferFormat));
            }

            Log.StartTransport(_logger, transferFormat);

            // Create pipe
            PipeOptions options = ClientPipeOptions.DefaultOptions;

            DuplexPipe.DuplexPipePair pair = DuplexPipe.CreateConnectionPair(options, options);

            _transport   = pair.Transport;
            _application = pair.Application;

            // Start streams
            Running = ProcessAsync(url, default);

            return(Task.CompletedTask);
        }
Ejemplo n.º 23
0
        /// <inheritdoc />
        public void Disconnect()
        {
            using (ThreadContext.Stacks["Connection"].Push(this.ToString()))
            {
                if (this.disconnected)
                {
                    this.log.Debug("Connection already disconnected.");
                    return;
                }

                this.log.Debug("Disconnecting...");
                if (this.duplexPipe != null)
                {
                    this.Source.Complete();
                    (this.duplexPipe as IDisposable)?.Dispose();
                    this.duplexPipe = null;
                }

                this.log.Debug("Disconnected");
                this.disconnected = true;

                this.Disconnected?.Invoke(this, System.EventArgs.Empty);
            }
        }
Ejemplo n.º 24
0
        private async Task Echo(IDuplexPipe connection)
        {
            while (true)
            {
                var result = await connection.Input.ReadAsync();

                var request = result.Buffer;

                if (request.IsEmpty && result.IsCompleted)
                {
                    connection.Input.AdvanceTo(request.End);
                    break;
                }

                var response = connection.Output;
                foreach (var memory in request)
                {
                    response.Write(memory.Span);
                }
                await response.FlushAsync();

                connection.Input.AdvanceTo(request.End);
            }
        }
Ejemplo n.º 25
0
            public Task StartAsync(Uri url, IDuplexPipe application, TransferFormat transferFormat, IConnection connection)
            {
                _application = application;
                tries++;
                Assert.True(QueryHelpers.ParseQuery(url.Query.ToString()).TryGetValue("id", out var id));
                if (prevConnectionId == null)
                {
                    prevConnectionId = id;
                }
                else
                {
                    Assert.True(prevConnectionId != id);
                    prevConnectionId = id;
                }

                if (tries < 3)
                {
                    throw new Exception();
                }
                else
                {
                    return(Task.CompletedTask);
                }
            }
 public SslDuplexPipe(IDuplexPipe transport, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func <Stream, SslStream> factory) :
     base(transport, readerOptions, writerOptions, factory)
 {
 }
 public SslDuplexPipe(IDuplexPipe transport, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions)
     : this(transport, readerOptions, writerOptions, s => new SslStream(s))
 {
 }
Ejemplo n.º 28
0
 internal ClientConnection(IDuplexPipe transport, EndPoint remoteEndPoint)
 {
     Transport      = transport;
     RemoteEndPoint = remoteEndPoint;
 }
 public MockConnectionContext(IDuplexPipe transport)
 {
     _transport = transport;
 }
Ejemplo n.º 30
0
 public DuplexPipePair(IDuplexPipe transport, IDuplexPipe application)
 {
     Transport   = transport;
     Application = application;
 }