public async Task Connect() { if (IsConnected()) { return; } tcp = new TcpClient { // Disable Nagle for HTTP/2 NoDelay = true }; await tcp.ConnectAsync(ConnectionSettings.Host, (int)ConnectionSettings.Port).ConfigureAwait(false); if (ConnectionSettings.UseTls) { sslStream = new SslStream(tcp.GetStream(), false, (sender, certificate, chain, sslPolicyErrors) => true); #if NETCOREAPP2_1 // .NET Core 2.1 introduces SslClientAuthenticationOptions // which allows us to set the SslApplicationProtocol (ALPN) which // for HTTP/2 is required, and should be set to h2 for direct to TLS connections // (h2c should be set for upgraded connections) var authOptions = new SslClientAuthenticationOptions { ApplicationProtocols = new List <SslApplicationProtocol> { SslApplicationProtocol.Http2 }, // ALPN h2 EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12, TargetHost = ConnectionSettings.Host, ClientCertificates = ConnectionSettings.Certificates ?? new X509CertificateCollection() }; await sslStream.AuthenticateAsClientAsync( authOptions, new CancellationToken(false)) .ConfigureAwait(false); #else // Fall back to no ALPN support for frameworks which don't support it await sslStream.AuthenticateAsClientAsync( ConnectionSettings.Host, ConnectionSettings.Certificates ?? new X509CertificateCollection(), System.Security.Authentication.SslProtocols.Tls12, false).ConfigureAwait(false); #endif clientStream = sslStream; } else { clientStream = tcp.GetStream(); } // Ensure we have a size for the stream '0' flowControlManager.GetWindowSize(0); // Send out preface data var prefaceData = System.Text.Encoding.ASCII.GetBytes(ConnectionPreface); await clientStream.WriteAsync(prefaceData, 0, prefaceData.Length).ConfigureAwait(false); await clientStream.FlushAsync().ConfigureAwait(false); // Start reading the stream on another thread var readTask = Task.Factory.StartNew(() => { try { Read(); } catch (Exception ex) { Log.Debug("Read error: " + ex); Disconnect(); } }, TaskCreationOptions.LongRunning); readTask.ContinueWith(t => { // TODO: Handle the error Disconnect(); }, TaskContinuationOptions.OnlyOnFaulted).Forget(); // Start a thread to handle writing queued frames to the stream var writeTask = Task.Factory.StartNew(Write, TaskCreationOptions.LongRunning); writeTask.ContinueWith(t => { // TODO: Handle the error Disconnect(); }, TaskContinuationOptions.OnlyOnFaulted).Forget(); // Send initial blank settings frame var s = new SettingsFrame(); if (ConnectionSettings.DisablePushPromise) { s.EnablePush = false; } await QueueFrame(s).ConfigureAwait(false); }
public async Task Connect() { if (IsConnected()) { return; } tcp = new TcpClient { // Disable Nagle for HTTP/2 NoDelay = true }; await tcp.ConnectAsync(ConnectionSettings.Host, (int)ConnectionSettings.Port).ConfigureAwait(false); if (ConnectionSettings.UseTls) { sslStream = new SslStream(tcp.GetStream(), false, (sender, certificate, chain, sslPolicyErrors) => true); await sslStream.AuthenticateAsClientAsync( ConnectionSettings.Host, ConnectionSettings.Certificates ?? new X509CertificateCollection(), System.Security.Authentication.SslProtocols.Tls12, false).ConfigureAwait(false); clientStream = sslStream; } else { clientStream = tcp.GetStream(); } // Ensure we have a size for the stream '0' flowControlManager.GetWindowSize(0); // Send out preface data var prefaceData = System.Text.Encoding.ASCII.GetBytes(ConnectionPreface); await clientStream.WriteAsync(prefaceData, 0, prefaceData.Length).ConfigureAwait(false); await clientStream.FlushAsync().ConfigureAwait(false); // Start reading the stream on another thread var readTask = Task.Factory.StartNew(() => { try { Read(); } catch (Exception ex) { Log.Debug("Read error: " + ex); Disconnect(); } }, TaskCreationOptions.LongRunning); readTask.ContinueWith(t => { // TODO: Handle the error Disconnect(); }, TaskContinuationOptions.OnlyOnFaulted).Forget(); // Start a thread to handle writing queued frames to the stream var writeTask = Task.Factory.StartNew(Write, TaskCreationOptions.LongRunning); writeTask.ContinueWith(t => { // TODO: Handle the error Disconnect(); }, TaskContinuationOptions.OnlyOnFaulted).Forget(); // Send initial blank settings frame var s = new SettingsFrame(); if (ConnectionSettings.DisablePushPromise) { s.EnablePush = false; } await QueueFrame(s).ConfigureAwait(false); }
public void Connect() { if (IsConnected()) { return; } tcp = new TcpClient(); // Disable Nagle for HTTP/2 tcp.NoDelay = true; tcp.Connect(ConnectionSettings.Host, (int)ConnectionSettings.Port); if (ConnectionSettings.UseTls) { sslStream = new SslStream(tcp.GetStream(), false, (sender, certificate, chain, sslPolicyErrors) => true); sslStream.AuthenticateAsClient( ConnectionSettings.Host, ConnectionSettings.Certificates ?? new X509CertificateCollection(), System.Security.Authentication.SslProtocols.Tls, false); clientStream = sslStream; } else { clientStream = tcp.GetStream(); } // Ensure we have a size for the stream '0' flowControlManager.GetWindowSize(0); // Send out preface data var prefaceData = System.Text.Encoding.ASCII.GetBytes(ConnectionPreface); clientStream.Write(prefaceData, 0, prefaceData.Length); clientStream.Flush(); // Start reading the stream on another thread var readTask = new Thread(() => { try { read(); } catch (Exception ex) { Log.Debug("Read error: " + ex); Disconnect(); } Disconnect(); }); readTask.Start(); // Start a thread to handle writing queued frames to the stream var writeTask = new Thread(() => { try { write(); } catch { Disconnect(); } }); writeTask.Start(); // Send initial blank settings frame var s = new SettingsFrame(); if (ConnectionSettings.DisablePushPromise) { s.EnablePush = false; } QueueFrame(s); }
IFrame dequeue() { IFrame result = null; semaphoreFrames.WaitOne(); foreach (var priority in PRIORITIES) { var frames = frameQueues [priority]; if (frames.Count > 0) { int frameIndex = -1; // counter of position in the loop // Loop until we find a frame that we can send (if so) foreach (var frame in frames) { frameIndex++; // we use this later to check for items in the queue prior to the current frame // Consider that we may need to skip data frames // if the flow control window is depleted or too small for the payload if (frame.Type == FrameType.Data) { // See if either the connection flow control or the frame's stream's flow control // window size has capacity for the data payload // if not, let's skip over this frame if (flowControlManager.GetWindowSize(0) - frame.PayloadLength < 0 || flowControlManager.GetWindowSize(frame.StreamIdentifier) - frame.PayloadLength < 0) { continue; } } else if (frame.Type == FrameType.Headers || frame.Type == FrameType.Continuation) { // If we have HEADERS or CONTINUATION frames these are considered trailers and could appear after // a DATA frame in the queue. // Problem is, if the DATA frame needs to be paused for flow control, // we also want to pause the trailing frames, so let's look and see // if the frame has any DATA frames still in the queue before it, from the same stream // if so, skip sending the trailers. if (AltLinq.Any(AltLinq.Take(frames, frameIndex), f => f.StreamIdentifier == frame.StreamIdentifier && f.Type == FrameType.Data)) { continue; } } // If we made it this far, we found a frame we can send // Let's keep it and stop looking for more in this list result = frame; break; } if (result != null) { // Remove the found item from the list frames.Remove(result); // exit the loop break; } } } semaphoreFrames.Release(); return(result); }
public async Task Connect() { if (IsConnected()) { return; } tcp = new TcpClient(); // Disable Nagle for HTTP/2 tcp.NoDelay = true; await tcp.ConnectAsync(ConnectionSettings.Host, (int)ConnectionSettings.Port).ConfigureAwait(false); try { if (ConnectionSettings.UseTls) { clientStream = await ConnectionSettings.CreateStream(tcp); } else { clientStream = tcp.GetStream(); } } catch { if (!IsConnected()) { tcp.Close(); } throw; } // Ensure we have a size for the stream '0' flowControlManager.GetWindowSize(0); // Send out preface data var prefaceData = System.Text.Encoding.ASCII.GetBytes(ConnectionPreface); await clientStream.WriteAsync(prefaceData, 0, prefaceData.Length).ConfigureAwait(false); await clientStream.FlushAsync().ConfigureAwait(false); // Start reading the stream on another thread var readTask = Task.Factory.StartNew(() => { try { read(); } catch (Exception ex) { Log.Debug("Read error: " + ex); Disconnect(); } }, TaskCreationOptions.LongRunning); readTask.ContinueWith(t => { // TODO: Handle the error Disconnect(); }, TaskContinuationOptions.OnlyOnFaulted).Forget(); // Start a thread to handle writing queued frames to the stream var writeTask = Task.Factory.StartNew <Task>(write, TaskCreationOptions.LongRunning); writeTask.ContinueWith(t => { // TODO: Handle the error Disconnect(); }, TaskContinuationOptions.OnlyOnFaulted).Forget(); // Send initial blank settings frame var s = new SettingsFrame(); if (ConnectionSettings.DisablePushPromise) { s.EnablePush = false; } await QueueFrame(s).ConfigureAwait(false); }