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);
        }
Example #2
0
        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);
        }
Example #5
0
        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);
        }