Example #1
0
        /// <summary>
        /// Create an send-side HybridConnectionStream, send N bytes to it, receive N bytes response from it,
        /// then close the HybridConnectionStream.
        /// </summary>
        async Task RunEchoClientAsync(HybridConnectionStream clientStream, int byteCount)
        {
            var cancelSource = new CancellationTokenSource(TimeSpan.FromSeconds(20));

            try
            {
                byte[] sendBuffer = this.CreateBuffer(byteCount, new[] { (byte)(byteCount % byte.MaxValue) });
                await clientStream.WriteAsync(sendBuffer, 0, sendBuffer.Length, cancelSource.Token);

                byte[] readBuffer = new byte[sendBuffer.Length + 10];
                int    bytesRead  = await clientStream.ReadAsync(readBuffer, 0, readBuffer.Length, cancelSource.Token);

                Assert.Equal(sendBuffer.Length, bytesRead);

                await clientStream.CloseAsync(cancelSource.Token);
            }
            catch (Exception e)
            {
                TestUtility.Log($"[byteCount={byteCount}] {e.GetType().Name}: {e.Message}");
                await clientStream.CloseAsync(cancelSource.Token);

                throw;
            }
            finally
            {
                cancelSource.Dispose();
            }
        }
        static async void RunConnectionPump(HybridConnectionStream stream, string connectionName, bool echoBytes = false)
        {
            try
            {
                var buffer = new byte[256];
                while (true)
                {
                    int read = await stream.ReadAsync(buffer, 0, buffer.Length);

                    RelayTraceSource.TraceVerbose($"{connectionName} received {read} bytes: \"{Encoding.UTF8.GetString(buffer, 0, read)}\"");
                    if (read == 0)
                    {
                        using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
                        {
                            RelayTraceSource.TraceVerbose($"{connectionName} closing");
                            await stream.CloseAsync(cts.Token);

                            RelayTraceSource.TraceInfo($"{connectionName} closed");
                        }

                        return;
                    }

                    if (echoBytes)
                    {
                        await stream.WriteAsync(buffer, 0, read);

                        RelayTraceSource.TraceVerbose($"{connectionName} echoed {read} bytes");
                    }
                }
            }
            catch (Exception exception)
            {
                RelayTraceSource.TraceException(exception, nameof(RunConnectionPump));
            }
        }
        private Task OnNewClient(Guid streamId, HybridConnectionStream stream, CancellationToken token)
        {
            return(Task.Factory.StartNew(async() =>
            {
                var buffer = new byte[65536];

                while (true)
                {
                    var id = Guid.Empty;
                    int remotePort = 0;
                    var count = 0;
                    Int32 controlCommand = ControlCommands.Forward;
                    Int32 frameSize = 0;
                    Int32 bytesRead = 0;
                    var memStream = new MemoryStream();

                    // read control command
                    count = await stream.ReadAsync(buffer, 0, sizeof(Int32));
                    if (0 == count || token.IsCancellationRequested)
                    {
                        break;
                    }

                    controlCommand = BitConverter.ToInt32(new ArraySegment <byte>(buffer, 0, sizeof(Int32)).ToArray(), 0);

                    if (ControlCommands.Forward == controlCommand)
                    {
                        // read forwarding preamble
                        count = await stream.ReadAsync(buffer, 0, 16 + sizeof(Int32) + sizeof(Int32));

                        if (0 == count || token.IsCancellationRequested)
                        {
                            break;
                        }

                        id = new Guid(new ArraySegment <byte>(buffer, 0, 16).ToArray());
                        remotePort = BitConverter.ToInt32(new ArraySegment <byte>(buffer, 16, sizeof(Int32)).ToArray(), 0);
                        frameSize = BitConverter.ToInt32(new ArraySegment <byte>(buffer, 16 + sizeof(Int32), sizeof(Int32)).ToArray(), 0);

                        if (!_validPorts.Contains(remotePort))
                        {
                            _logger.LogError($"Connection on port {remotePort} not allowed for hybrid connectio  {_connectionName}.");

                            stream.Close();
                        }

                        while (true)
                        {
                            var length = frameSize - bytesRead > buffer.Length ? buffer.Length : frameSize - bytesRead;
                            count = await stream.ReadAsync(buffer, 0, length);

                            if (0 == count || token.IsCancellationRequested)
                            {
                                break;
                            }

                            bytesRead += count;
                            await memStream.WriteAsync(buffer, 0, count);

                            if (bytesRead == frameSize)
                            {
                                await _demultiplexer.Demultiplex(streamId, id, remotePort, memStream.ToArray());
                                break;
                            }
                        }

                        if (0 == count || token.IsCancellationRequested)
                        {
                            break;
                        }
                    }
                    else
                    {
                        count = await stream.ReadAsync(buffer, 0, 16);
                        if (0 == count || token.IsCancellationRequested)
                        {
                            break;
                        }

                        id = new Guid(new ArraySegment <byte>(buffer, 0, 16).ToArray());

                        await _demultiplexer.ClientConnectionClosed(streamId, id);
                    }
                }

                lock (_syncRoot)
                {
                    _hybridConnectionStreams.Remove(streamId);
                }

                await stream.ShutdownAsync(_cts.Token);
            }));
        }
Example #4
0
        async Task HandleRelayConnectionAsync(HybridConnectionStream hybridConnectionStream)
        {
            try
            {
                using (hybridConnectionStream)
                {
                    string portName = null;

                    hybridConnectionStream.WriteTimeout = 60000;

                    // read and write 4-byte header
                    // we don't do anything with this version preamble just yet; it really
                    // is insurance for when we might have to break protocol.
                    var versionPreamble = new byte[3];
                    for (int read = 0; read < versionPreamble.Length;)
                    {
                        var r = await hybridConnectionStream.ReadAsync(versionPreamble, read,
                                                                       versionPreamble.Length - read);

                        if (r == 0)
                        {
                            await hybridConnectionStream.ShutdownAsync(CancellationToken.None);

                            return;
                        }

                        read += r;
                    }

                    // version 1.0 and stream mode (0)
                    if (versionPreamble[0] == 1 && versionPreamble[1] == 0 &&
                        (versionPreamble[2] == 0 || versionPreamble[2] == 1))
                    {
                        // For version 1.0, the version preamble is followed by a single byte
                        // length indicator and then that number of bytes with of UTF-8 encoded
                        // port-name string.
                        var portNameBuffer = new byte[256];
                        var r = await hybridConnectionStream.ReadAsync(portNameBuffer, 0, 1);

                        if (r == 0)
                        {
                            await hybridConnectionStream.ShutdownAsync(CancellationToken.None);

                            return;
                        }

                        for (int read = 0; read < portNameBuffer[0];)
                        {
                            r = await hybridConnectionStream.ReadAsync(portNameBuffer, read + 1,
                                                                       portNameBuffer[0] - read);

                            if (r == 0)
                            {
                                await hybridConnectionStream.ShutdownAsync(CancellationToken.None);

                                return;
                            }

                            read += r;
                        }

                        portName = Encoding.UTF8.GetString(portNameBuffer, 1, portNameBuffer[0]);
                    }
                    else
                    {
                        // if we don't understand the version, we write a 0.0 version preamble back and shut down the connection
                        versionPreamble = new byte[] { 0, 0, 0 };
                        await hybridConnectionStream.WriteAsync(versionPreamble, 0, versionPreamble.Length);
                        await CloseConnection(hybridConnectionStream);

                        return;
                    }

                    if (remoteForwarders.TryGetValue(portName, out var forwarder))
                    {
                        if (forwarder is UdpRemoteForwarder && versionPreamble[2] != 1)
                        {
                            // bad datagram indicator
                            versionPreamble = new byte[] { 0, 0, 1 };
                            await hybridConnectionStream.WriteAsync(versionPreamble, 0, versionPreamble.Length);
                            await CloseConnection(hybridConnectionStream);

                            return;
                        }
                        else if (!(forwarder is UdpRemoteForwarder) && versionPreamble[2] == 1)
                        {
                            // mismatch
                            versionPreamble = new byte[] { 0, 0, 255 };
                            await hybridConnectionStream.WriteAsync(versionPreamble, 0, versionPreamble.Length);
                            await CloseConnection(hybridConnectionStream);

                            return;
                        }

                        // write out 1.0 and handle the stream
                        versionPreamble = new byte[] { 1, 0, versionPreamble[2] };
                        await hybridConnectionStream.WriteAsync(versionPreamble, 0, versionPreamble.Length);

                        await forwarder.HandleConnectionAsync(hybridConnectionStream);
                        await CloseConnection(hybridConnectionStream);
                    }
                    else
                    {
                        await CloseConnection(hybridConnectionStream);
                    }
                }
            }
            catch (Exception e)
            {
                BridgeEventSource.Log.HandledExceptionAsWarning(activity, e);
            }
        }