public RemoteRelayDataChannel(ILogger logger, RemoteDataChannelMetrics metrics, HybridConnectionStream dataChannel) { _log = logger.ForContext(GetType()); _dataChannel = dataChannel; _metrics = metrics; _writeLock = new SemaphoreSlim(1, 1); }
/// <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(); } }
/// <summary> /// Connect the stream to a accepted stream instance and start the producer /// </summary> /// <param name="stream"></param> internal bool TryConnect(HybridConnectionStream stream) { if (_open.IsCancellationRequested) { // Stream closed, but proxy tries to connect, reject return(false); } // Ensure previous producer task finishes if (_producerTask != null && !_producerTask.IsCompleted) { if (_streaming != null) { _streaming.Cancel(); try { _producerTask.Wait(); } catch (Exception) { return(false); } } } _codec.Stream = stream; _streaming = new CancellationTokenSource(); _producerTask = ReceiveProducerAsync(_streaming.Token); Tcs.TrySetResult(this); return(true); }
/// <summary> /// Read from the hybrid connection and process /// </summary> /// <param name="relayConnection"></param> /// <returns></returns> protected Task GetReads(HybridConnectionStream relayConnection) { var reads = Task.Run(async() => { // Initialize the stream reader over the connection _reader = new StreamReader(relayConnection); do { // Read a full line of UTF-8 text up to newline string line = await _reader.ReadLineAsync(); // if the string is empty or null, we are done. if (String.IsNullOrEmpty(line)) { break; } // process message OnIncomingMessage(new MessageEventArgs { Message = line }); }while (_runClient); }); return(reads); }
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); } }
private async void ProcessMessage(HybridConnectionStream relayConnection, CancellationTokenSource cts) { // Bi-directional streams for read and write to the relay var reader = new StreamReader(relayConnection); var writer = new StreamWriter(relayConnection) { AutoFlush = true }; while (!cts.IsCancellationRequested) { // Read a message in input from the relay var message = await reader.ReadToEndAsync(); // Resolve address by invoking a service on the GIS server GisObject gisObject = JsonConvert.DeserializeObject <GisObject>(message); await new GisServer().ResolveAddressAsync(gisObject); // Write the message back to the relay message = JsonConvert.SerializeObject(gisObject); await writer.WriteLineAsync(message); } await relayConnection.CloseAsync(cts.Token); }
static async Task TestStreaming(HybridConnectionListener listener, RelayConnectionStringBuilder connectionString, TraceSource traceSource) { traceSource.TraceInformation("Testing Streaming (WebSocket) mode"); RunAcceptPump(listener); var client = new HybridConnectionClient(connectionString.ToString()); var requestBytes = Encoding.UTF8.GetBytes("<data>Request payload from sender</data>"); HybridConnectionStream stream = await client.CreateConnectionAsync(); string connectionName = $"S:HybridConnectionStream({stream.TrackingContext.TrackingId})"; RelayTraceSource.TraceInfo($"{connectionName} initiated"); RunConnectionPump(stream, connectionName); for (int i = 0; i < 2; i++) { await stream.WriteAsync(requestBytes, 0, requestBytes.Length); RelayTraceSource.TraceVerbose($"{connectionName} wrote {requestBytes.Length} bytes"); } using (var closeCts = new CancellationTokenSource(TimeSpan.FromSeconds(5))) { RelayTraceSource.TraceVerbose($"{connectionName} closing"); await stream.CloseAsync(closeCts.Token); RelayTraceSource.TraceInfo($"{connectionName} closed"); } await Task.Delay(TimeSpan.FromMilliseconds(100)); }
public RelayTunnel Create(HybridConnectionStream stream, ILocalDataChannelFactory localFactory) { var tunnel = new RelayTunnel(_log, _metrics, stream, localFactory, OnTunnelCompleted); _tunnels[tunnel] = tunnel; return(tunnel); }
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 async Task <GisObject> ReadFromRelay(HybridConnectionStream relayConnection) { // Read the GIS object from the hybrid connection var reader = new StreamReader(relayConnection); string message = await reader.ReadToEndAsync(); GisObject gisObject = JsonConvert.DeserializeObject <GisObject>(message); return(gisObject); }
private async Task SendToRelay(HybridConnectionStream relayConnection, GisObject gisObject) { // Write the GIS object to the hybrid connection var writer = new StreamWriter(relayConnection) { AutoFlush = true }; string message = JsonConvert.SerializeObject(gisObject); await writer.WriteAsync(message); }
public override async Task <RelayEpoxyConnection> ConnectToAsync(string address, CancellationToken ct) { logger.Site().Information("Connecting to {0}.", address); HybridConnectionStream socket = await ConnectClientSocketAsync(new Uri(address)); var connection = RelayEpoxyConnection.MakeClientConnection(this, socket, logger, metrics); await connection.StartAsync(); return(connection); }
private void EnsureDownlinkPump(HybridConnectionStream stream) { _dataChannel = new RemoteRelayDataChannel(_log, _metrics.Remote, stream); _downlinkPump = new DownlinkPump(_log, _dataChannel); _metrics.RemoteEstablishedTunnels.Increment(); _log.Verbose("Downlink pump is created and starting"); _downlinkPump.RunAsync().ContinueWith(OnDownlinkPumpCompleted); }
/// <summary> /// We run two concurrent loops on the connection. One reads input from the console and writes it to the connection /// with a stream writer. The other reads lines of input from the connection with a stream reader and writes them to the console. /// Entering a blank line will shut down the write task after sending it to the server. The server will then cleanly shut down /// the connection which will terminate the read task. /// </summary> /// <returns></returns> protected async Task RunAsync() { // Initiate the connection _relayConnection = await _client.CreateConnectionAsync(); var reads = GetReads(_relayConnection); // Wait for both tasks to complete await Task.WhenAll(reads); await _relayConnection.CloseAsync(CancellationToken.None); }
public async Task OpenAsync(CancellationToken token) { if (_connection != null) { throw new InvalidOperationException("Connection already open"); } _connection = await _client.CreateConnectionAsync(); token.ThrowIfCancellationRequested(); IsOpen = true; }
public RelayTunnel(ILogger logger, TunnelMetrics metrics, HybridConnectionStream relayStream, ILocalDataChannelFactory localFactory, TunnelCompleted tunnelCompleted) { _log = logger.ForContext(GetType()); _uplinkPumps = new ConcurrentDictionary <object, UplinkPump>(); _localDataChannelFactory = localFactory; _tunnelCompleted = tunnelCompleted; _metrics = metrics; _relayDataChannel = new RemoteRelayDataChannel(logger, metrics.Remote, relayStream); _downlinkPump = new DownlinkPump(logger, _relayDataChannel, CreateLocalDataChannel); }
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); }
void EnsureConnection() { lock (connectLock) { if (dataChannel == null) { multiplexedOutputStream = new ThrottledQueueBufferedStream(10); QueueBufferedStream multiplexedInputStream = new QueueBufferedStream(); dataChannelFactory = new HybridConnectionClient(endpointVia, tokenProvider); dataChannel = dataChannelFactory.CreateConnectionAsync().GetAwaiter().GetResult(); try { var preambleWriter = new BinaryWriter(dataChannel); preambleWriter.Write("np:" + toPipe); rawInputPump = new StreamBufferWritePump(dataChannel, multiplexedInputStream.Write); rawInputPump.BeginRunPump(RawInputPumpCompleted, false); inputPump = new MultiplexConnectionInputPump(multiplexedInputStream.Read, CorrelateConnection, null); inputPump.Run(false); outputPump = new StreamBufferWritePump(multiplexedOutputStream, WriteToDataChannel); outputPump.BeginRunPump(MultiplexPumpCompleted, null); } catch (AuthorizationFailedException af) { Trace.TraceError("Authorization failed: {0}", af.Message); if (dataChannel != null) { DataChannelClose(); dataChannel = null; } throw; } catch (Exception ex) { Trace.TraceError("Unable to establish data channel: {0}", ex.Message); if (dataChannel != null) { DataChannelClose(); dataChannel = null; } throw; } } } }
async Task AcceptAsync(CancellationToken t) { logger.Site().Information("Accepting connections on {0}", ListenEndpoint); while (!t.IsCancellationRequested) { HybridConnectionStream connectionStream = null; try { connectionStream = await listener.AcceptConnectionAsync(); logger.Site().Debug("Accepted connection from {0}.", listener.Address); var connection = RelayEpoxyConnection.MakeServerConnection( parentTransport, this, serviceHost, connectionStream, logger, metrics); lock (connectionsLock) { connections.Add(connection); } await connection.StartAsync(); logger.Site().Debug("Started server-side connection for {0}", connection); } catch (AuthenticationException ex) { logger.Site().Error(ex, "Failed to authenticate remote connection from {0}", connectionStream); ShutdownSocketSafe(connectionStream); } catch (SocketException ex) { logger.Site().Error(ex, "Accept failed with error {0}.", ex.SocketErrorCode); ShutdownSocketSafe(connectionStream); } catch (ObjectDisposedException) { ShutdownSocketSafe(connectionStream); } } logger.Site().Information("Shutting down connection on {0}", ListenEndpoint); }
internal static RelayEpoxyConnection MakeClientConnection( RelayEpoxyTransport parentTransport, HybridConnectionStream networkStream, Logger logger, Metrics metrics) { const RelayEpoxyListener parentListener = null; return(new RelayEpoxyConnection( ConnectionType.Client, parentTransport, parentListener, new ServiceHost(logger), networkStream, logger, metrics)); }
internal static RelayEpoxyConnection MakeServerConnection( RelayEpoxyTransport parentTransport, RelayEpoxyListener parentListener, ServiceHost serviceHost, HybridConnectionStream networkStream, Logger logger, Metrics metrics) { return(new RelayEpoxyConnection( ConnectionType.Server, parentTransport, parentListener, serviceHost, networkStream, logger, metrics)); }
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; } }
public async Task HandleConnectionAsync(HybridConnectionStream hybridConnectionStream) { UdpClient client = null; if (config.BindAddress != null) { var computerProperties = IPGlobalProperties.GetIPGlobalProperties(); var unicastAddresses = computerProperties.GetUnicastAddresses(); IList <IPAddress> ipAddresses = null; ipAddresses = IPAddress.TryParse(config.BindAddress, out var ipAddress) ? new[] { ipAddress } : Dns.GetHostEntry(config.BindAddress).AddressList; List <IPAddress> eligibleAddresses = new List <IPAddress>(); eligibleAddresses.AddRange(from hostAddress in ipAddresses where IPAddress.IsLoopback(hostAddress) select hostAddress); eligibleAddresses.AddRange(from unicastAddress in unicastAddresses join hostAddress in ipAddresses on unicastAddress.Address equals hostAddress where !IPAddress.IsLoopback(hostAddress) select hostAddress); // pick one of those eligible endpoints client = new UdpClient(new IPEndPoint(eligibleAddresses[rnd.Next(eligibleAddresses.Count)], 0)); } else { client = new UdpClient(); } using (client) { client.Connect(targetServer, targetPort); CancellationTokenSource socketAbort = new CancellationTokenSource(maxIdleTime); await Task.WhenAll( Send(hybridConnectionStream, client, socketAbort) .ContinueWith((t) => socketAbort.Cancel(), TaskContinuationOptions.OnlyOnFaulted), Receive(hybridConnectionStream, client, socketAbort) .ContinueWith((t) => socketAbort.Cancel(), TaskContinuationOptions.OnlyOnFaulted)); } }
static void Main(string[] args) { HybridConnectionClient client = new HybridConnectionClient("Endpoint=sb://relayzs.servicebus.windows.net/;SharedAccessKeyName=sas;SharedAccessKey=WBhKG1Fb51sYz4I1Nsv/mZsLhnru+O08YQxeq+SyRfo=;EntityPath=hybirdconn1"); Task <HybridConnectionStream> task = client.CreateConnectionAsync(); while (!task.IsCompleted) { } HybridConnectionStream stream = task.Result; StreamWriter writer = new StreamWriter(stream); StreamReader reader = new StreamReader(stream); writer.WriteLine("Hello Server!"); writer.Flush(); String line = reader.ReadLine(); Console.WriteLine(line); reader.Close(); writer.Close(); }
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); }
public async Task HandleConnectionAsync(HybridConnectionStream hybridConnectionStream) { using (TcpClient client = new TcpClient()) { client.NoDelay = true; client.SendBufferSize = client.ReceiveBufferSize = 65536; client.SendTimeout = 60000; if (config.BindAddress != null) { var computerProperties = IPGlobalProperties.GetIPGlobalProperties(); var unicastAddresses = computerProperties.GetUnicastAddresses(); IList <IPAddress> ipAddresses = null; ipAddresses = IPAddress.TryParse(config.BindAddress, out var ipAddress) ? new[] { ipAddress } : Dns.GetHostEntry(config.BindAddress).AddressList; List <IPAddress> eligibleAddresses = new List <IPAddress>(); eligibleAddresses.AddRange(from hostAddress in ipAddresses where IPAddress.IsLoopback(hostAddress) select hostAddress); eligibleAddresses.AddRange(from unicastAddress in unicastAddresses join hostAddress in ipAddresses on unicastAddress.Address equals hostAddress where !IPAddress.IsLoopback(hostAddress) select hostAddress); // pick one of those eligible endpoints client.Client.Bind(new IPEndPoint(eligibleAddresses[rnd.Next(eligibleAddresses.Count)], 0)); } await client.ConnectAsync(targetServer, targetPort); var tcpstream = client.GetStream(); CancellationTokenSource socketAbort = new CancellationTokenSource(); await Task.WhenAll( StreamPump.RunAsync(hybridConnectionStream, tcpstream, () => client.Client.Shutdown(SocketShutdown.Send), socketAbort.Token) .ContinueWith((t) => socketAbort.Cancel(), TaskContinuationOptions.OnlyOnFaulted), StreamPump.RunAsync(tcpstream, hybridConnectionStream, () => hybridConnectionStream.Shutdown(), socketAbort.Token)) .ContinueWith((t) => socketAbort.Cancel(), TaskContinuationOptions.OnlyOnFaulted); } }
private HybridConnectionStream CreateConnection() { if (null == _hybridConnectionStream) { lock (_syncRoot) { if (null == _hybridConnectionStream) { try { _hybridConnectionStream = _hybridConnectionClient.CreateConnectionAsync().Result; } catch (Exception e) { _logger.LogError(e, $"Unable to create hybrid connection for {_relayNamespace}/{_connectionName}"); } } } } return(_hybridConnectionStream); }
RelayEpoxyConnection( ConnectionType connectionType, RelayEpoxyTransport parentTransport, RelayEpoxyListener parentListener, ServiceHost serviceHost, HybridConnectionStream networkStream, Logger logger, Metrics metrics) { Debug.Assert(parentTransport != null); Debug.Assert(connectionType != ConnectionType.Server || parentListener != null, "Server connections must have a listener"); Debug.Assert(serviceHost != null); Debug.Assert(networkStream != null); this.connectionType = connectionType; this.parentTransport = parentTransport; this.parentListener = parentListener; this.serviceHost = serviceHost; this.networkStream = networkStream; responseMap = new ResponseMap(); state = State.Created; startTask = new TaskCompletionSource <bool>(); stopTask = new TaskCompletionSource <bool>(); shutdownTokenSource = new CancellationTokenSource(); // start at -1 or 0 so the first conversation ID is 1 or 2. prevConversationId = (connectionType == ConnectionType.Client) ? -1 : 0; //ConnectionMetrics.local_endpoint = LocalEndPoint.ToString(); //ConnectionMetrics.remote_endpoint = RemoteEndPoint.ToString(); this.logger = logger; this.metrics = metrics; }
void DataChannelClose() { foreach (MultiplexedTcpConnection connection in new List <MultiplexedTcpConnection>(connections.Values)) { try { lock (connectionLock) { connections.Remove(connection.Id); } connection.Dispose(); } catch (Exception ex) { Trace.TraceError("Error shutting down multiplex connection: {0}", ex.Message); } } if (dataChannel != null) { dataChannel.Close(); dataChannel = null; } }