private async void ProcessMessagesOnConnection(HybridConnectionStream connection, CancellationToken token) { try { try { try { while (!token.IsCancellationRequested) { IFeatureCollection features = await _featureSerializerManager.ReadAsync(connection, new[] { typeof(IHttpRequestFeature) }, token); PrepareDefaultFeatures(features); await _requestReceivedCallback(features, token); await _featureSerializerManager.WriteAsync(connection, features, new[] { typeof(IHttpResponseFeature) }, token); } } finally { await connection.ShutdownAsync(token); } } catch (IOException) { } catch (RelayException) { } } finally { await connection.CloseAsync(token); } }
public async Task Stop() { if (null != _hybridConnectionStream) { await _hybridConnectionStream.ShutdownAsync(CancellationToken.None); } }
private static async void ProcessMessagesOnConnection(HybridConnectionStream relayConnection, CancellationTokenSource cts) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("New session established..."); Console.ForegroundColor = ConsoleColor.White; // The connection is a fully bidrectional stream. // We put a stream reader and a stream writer over it // which allows us to read UTF-8 text that comes from // the sender and to write text replies back. var reader = new StreamReader(relayConnection); var writer = new StreamWriter(relayConnection) { AutoFlush = true }; // Write the line back to the client, prepending "Echo:" await writer.WriteLineAsync("Hello client from the server!"); while (!cts.IsCancellationRequested) { try { // Read a line of input until a newline is encountered var line = await reader.ReadLineAsync(); if (string.IsNullOrEmpty(line)) { // If there's no input data, we will signal that // we will no longer send data on this connection // and then break out of the processing loop. await relayConnection.ShutdownAsync(cts.Token); break; } // Output the line on the console Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("Received from client: " + line); Console.ForegroundColor = ConsoleColor.White; // Write the line back to the client, prepending "Echo:" await writer.WriteLineAsync($"Thanks for sending: {line}"); } catch (Exception ex) { // Catch an IO exception that is likely caused because // the client disconnected. Console.WriteLine("Looks like the client closed connection..."); break; } } Console.WriteLine("Session ended with client..."); // Closing the connection await relayConnection.CloseAsync(cts.Token); }
static async Task CloseConnection(HybridConnectionStream hybridConnectionStream) { using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1))) { await hybridConnectionStream.ShutdownAsync(cts.Token); await hybridConnectionStream.CloseAsync(cts.Token); } }
private static async void ProcessMessagesOnConnection(HybridConnectionStream relayConnection, CancellationTokenSource cts) { Console.WriteLine("New session"); // The connection is a fully bidrectional stream. // Put a stream reader and a stream writer over it. // This allows you to read UTF-8 text that comes from // the sender, and to write text replies back. var reader = new StreamReader(relayConnection); var writer = new StreamWriter(relayConnection) { AutoFlush = true }; while (!cts.IsCancellationRequested) { try { // Read a line of input until a newline is encountered. var line = await reader.ReadLineAsync(); if (string.IsNullOrEmpty(line)) { // If there's no input data, signal that // you will no longer send data on this connection. // Then, break out of the processing loop. await relayConnection.ShutdownAsync(cts.Token); break; } // Write the line on the console. Console.WriteLine(line); // Write the line back to the client, prepended with "Echo:" await writer.WriteLineAsync($"Echo: {line}"); } catch (IOException) { // Catch an I/O exception. This likely occurred when // the client disconnected. Console.WriteLine("Client closed connection"); break; } } Console.WriteLine("End session"); // Close the connection. await relayConnection.CloseAsync(cts.Token); }
public async Task CloseAsync(CancellationToken token) { try { if (_connection == null) { return; } await _connection.ShutdownAsync(token); await _connection.CloseAsync(token); } finally { IsOpen = false; GoodStatus = false; _connection = null; } }
private static async void ProcessMessagesOnConnection(HybridConnectionStream relayConnection, CancellationTokenSource cts) { Console.WriteLine("New session"); // The connection is a fully bidrectional stream, enabling the Listener //to echo the text from the Sender. var reader = new StreamReader(relayConnection); var writer = new StreamWriter(relayConnection) { AutoFlush = true }; while (!cts.IsCancellationRequested) { try { // Read a line of input until a newline is encountered var line = await reader.ReadLineAsync(); if (string.IsNullOrEmpty(line)) { await relayConnection.ShutdownAsync(cts.Token); break; } Console.WriteLine(line); // Echo the line back to the client await writer.WriteLineAsync($"Echo: {line}"); } catch (IOException) { Console.WriteLine("Client closed connection"); break; } } Console.WriteLine("End session"); // Close the connection await relayConnection.CloseAsync(cts.Token); }
private static async void ProcessMessagesOnConnection(HybridConnectionStream relayConnection, CancellationTokenSource cts) { Console.WriteLine("New Session"); var reader = new StreamReader(relayConnection); var writer = new StreamWriter(relayConnection) { AutoFlush = true }; while (!cts.IsCancellationRequested) { try { var line = reader.ReadLine(); if (string.IsNullOrEmpty(line)) { await relayConnection.ShutdownAsync(cts.Token); break; } Console.WriteLine(line); await writer.WriteLineAsync($"Echo: {line}"); } catch (IOException ex) { Console.WriteLine(ex.Message); break; } } Console.WriteLine("End session"); await relayConnection.CloseAsync(cts.Token); }
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); })); }
private IObservable <IMessage> _observableRelayStringLine(HybridConnectionStream connection, CancellationToken ct, TimeSpan timeout) => Observable.Create <IMessage>( obs => { _relayStateObserver.OnNext(RelayListenerConnectionState.Receiving); var reader = new StreamReader(connection); var writer = new StreamWriter(connection) { AutoFlush = true }; var readerObservable = Observable.FromAsync(reader.ReadLineAsync); var disposableText = Observable.While( () => !ct.IsCancellationRequested, readerObservable) .Subscribe(stringLine => { // If there's no input data, signal that // you will no longer send data on this connection. // Then, break out of the processing loop. Debug.WriteLine(stringLine); if (string.IsNullOrEmpty(stringLine)) { writer?.Dispose(); try { connection?.ShutdownAsync(ct)?.Wait(new CancellationTokenSource(timeout).Token); } catch (AggregateException) { // Ignore if connection already closed } obs.OnCompleted(); } obs.OnNext(new Message(stringLine, writer)); }, ex => { Debug.WriteLine(ex.ToString()); if (ex is IOException) { // Catch an I/O exception. This likely occurred when // the client disconnected. } else { obs.OnError(ex); } }, obs.OnCompleted); return(new CompositeDisposable( disposableText, Disposable.Create(() => { _relayStateObserver.OnNext(RelayListenerConnectionState.Listening); writer?.Dispose(); reader?.Dispose(); try { connection?.ShutdownAsync(ct)?.Wait(new CancellationTokenSource(timeout).Token); } catch (AggregateException) { // Ignore if connection already closed } }))); });
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); } }