/// <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(); } }
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); }
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); } }
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)); }
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); } }
/// <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); }
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); }
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)); } }
public async Task CloseRelayStreamAsync() { await _relayStream.CloseAsync(CancellationToken.None); }
internal static async Task VerifySendAsync(RelayConnectionStringBuilder connectionString, int number, string httpMethod, string requestData, TraceSource traceSource) { Uri hybridHttpUri = new Uri($"https://{connectionString.Endpoint.GetComponents(UriComponents.HostAndPort, UriFormat.SafeUnescaped)}/{connectionString.EntityPath}"); var tokenProvider = GetTokenProvider(connectionString); if (string.Equals("WS", httpMethod, StringComparison.OrdinalIgnoreCase) || string.Equals("WEBSOCKET", httpMethod, StringComparison.OrdinalIgnoreCase)) { var client = new HybridConnectionClient(connectionString.ToString()); var requestBytes = Encoding.UTF8.GetBytes(requestData ?? string.Empty); HybridConnectionStream stream = await client.CreateConnectionAsync(); string connectionName = $"S:HybridConnectionStream({stream.TrackingContext.TrackingId})"; RelayTraceSource.TraceInfo($"{connectionName} initiated"); RunConnectionPump(stream, connectionName); for (int i = 0; i < number; i++) { await stream.WriteAsync(requestBytes, 0, requestBytes.Length); RelayTraceSource.TraceVerbose($"{connectionName} wrote {requestBytes.Length} bytes"); } await Task.Delay(TimeSpan.FromSeconds(1)); using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5))) { RelayTraceSource.TraceVerbose($"{connectionName} closing"); await stream.CloseAsync(cts.Token); RelayTraceSource.TraceInfo($"{connectionName} closed"); } return; } string token = null; if (tokenProvider != null) { token = (await tokenProvider.GetTokenAsync(hybridHttpUri.AbsoluteUri, TimeSpan.FromDays(2))).TokenString; } var stopwatch = new Stopwatch(); using (var client = new HttpClient { BaseAddress = hybridHttpUri }) { client.DefaultRequestHeaders.ExpectContinue = false; for (int i = 0; i < number; i++) { stopwatch.Restart(); var httpRequest = new HttpRequestMessage(); if (token != null) { httpRequest.Headers.Add("ServiceBusAuthorization", token); } httpRequest.Method = new HttpMethod(httpMethod); if (requestData != null) { httpRequest.Content = new StringContent(requestData); } LogHttpRequest(httpRequest, client, traceSource); using (HttpResponseMessage response = await client.SendAsync(httpRequest)) { LogHttpResponse(response, traceSource); } traceSource.TraceInformation($"Elapsed: {stopwatch.ElapsedMilliseconds} ms"); } } }
static async Task Main(string[] args) { string hostAddress; string hybridConnectionName; string clientId = null; string tenantId = null; string clientSecret = null; RbacAuthenticationOption option; if (args.Length == 2) { option = RbacAuthenticationOption.ManagedIdentity; hostAddress = args[0]; hybridConnectionName = args[1]; } else if (args.Length == 3) { option = RbacAuthenticationOption.UserAssignedIdentity; hostAddress = args[0]; hybridConnectionName = args[1]; clientId = args[2]; } else if (args.Length == 5) { option = RbacAuthenticationOption.AAD; hostAddress = args[0]; hybridConnectionName = args[1]; clientId = args[2]; tenantId = args[3]; clientSecret = args[4]; } else { Console.WriteLine("Please run with parameters of the following format for the corresponding RBAC authentication method:"); Console.WriteLine("System Managed Identity: [HostAddress] [HybridConnectionName]"); Console.WriteLine("User Assigned Identity: [HostAddress] [HybridConnectionName] [ClientId]"); Console.WriteLine("Azure Active Directory: [HostAddress] [HybridConnectionName] [ClientId] [TenantId] [ClientSecret]"); Console.WriteLine("Press <Enter> to exit..."); Console.ReadLine(); return; } TokenProvider tokenProvider = null; switch (option) { case RbacAuthenticationOption.ManagedIdentity: tokenProvider = TokenProvider.CreateManagedIdentityTokenProvider(); break; case RbacAuthenticationOption.UserAssignedIdentity: var managedCredential = new ManagedIdentityCredential(clientId); tokenProvider = TokenProvider.CreateManagedIdentityTokenProvider(managedCredential); break; case RbacAuthenticationOption.AAD: tokenProvider = GetAadTokenProvider(clientId, tenantId, clientSecret); break; } var hybridConnectionUri = new Uri($"{hostAddress}/{hybridConnectionName}"); HybridConnectionListener listener = null; try { // The HybridConnection should be already created through Azure Portal or other means Console.WriteLine($"Creating the Relay listener instance with RBAC option: {option}"); listener = new HybridConnectionListener(hybridConnectionUri, tokenProvider); await listener.OpenAsync(TimeSpan.FromSeconds(10)); Console.WriteLine("Created and connected the Relay listener instance."); Console.WriteLine($"Creating the Relay sender instance with RBAC option: {option}"); var sender = new HybridConnectionClient(hybridConnectionUri, tokenProvider); var createSenderTask = sender.CreateConnectionAsync(); var listenerAcceptTask = listener.AcceptConnectionAsync(); using (HybridConnectionStream senderStream = await createSenderTask) using (HybridConnectionStream listenerStream = await listenerAcceptTask) { Console.WriteLine("Created and connected the Relay sender instance."); var senderCloseTask = senderStream.CloseAsync(CancellationToken.None); await listenerStream.CloseAsync(CancellationToken.None); await senderCloseTask; } // Configure a RequestHandler for HTTP request/response mode listener.RequestHandler = (context) => { context.Response.StatusCode = HttpStatusCode.OK; using (var sw = new StreamWriter(context.Response.OutputStream)) { sw.WriteLine("hello!"); } // The context must be closed to complete sending the response context.Response.Close(); }; Console.WriteLine($"Sending a HTTP request by setting the token in request header with RBAC option: {option}"); SecurityToken token = await tokenProvider.GetTokenAsync(hybridConnectionUri.AbsoluteUri, TimeSpan.FromMinutes(30)); var request = new HttpRequestMessage(); request.Headers.Add(HttpRequestHeader.Authorization.ToString(), token.TokenString); var requestUri = new UriBuilder(hybridConnectionUri) { Scheme = "https" }.Uri; using (HttpClient client = new HttpClient { BaseAddress = requestUri }) { using (var response = await client.SendAsync(request)) { Console.WriteLine($"Response status code: {response.StatusCode}. Response reason phrase: {response.ReasonPhrase}"); } } Console.WriteLine($"Sending a HTTP request by setting the token in query string with RBAC option: {option}"); token = await tokenProvider.GetTokenAsync(hybridConnectionUri.AbsoluteUri, TimeSpan.FromMinutes(30)); request = new HttpRequestMessage(); requestUri = new UriBuilder(requestUri) { Query = $"?sb-hc-token={token.TokenString}" }.Uri; using (HttpClient client = new HttpClient { BaseAddress = requestUri }) { using (var response = await client.SendAsync(request)) { Console.WriteLine($"Response status code: {response.StatusCode}. Response reason phrase: {response.ReasonPhrase}"); } } Console.WriteLine("Press <Enter> to exit..."); Console.ReadLine(); } finally { if (listener != null) { await listener.CloseAsync(); } } }