public static async Task RunSessionAsync(AppFunc app,
            Func<Http2ClientSession, Http2ServerSession, Task> sessionOperations)
        {
            DuplexStream clientStream = new DuplexStream();
            DuplexStream serverStream = clientStream.GetOpositeStream();

            Task clientTask, serverTask;
            using (Http2ClientSession clientSession = new Http2ClientSession(clientStream, false, CancellationToken.None, CancellationToken.None))
            {
                using (Http2ServerSession serverSession = new Http2ServerSession(app, new TransportInformation()))
                {
                    clientTask = clientSession.Start();
                    serverTask = serverSession.Start(serverStream, CancellationToken.None);

                    await sessionOperations(clientSession, serverSession);
                }
            }

            await clientTask;
            await serverTask;
        }
        public void ConnectionReset_StreamsAborted()
        {
            DuplexStream clientStream = new DuplexStream();
            DuplexStream serverStream = clientStream.GetOpositeStream();
            ManualResetEvent waitForRequest = new ManualResetEvent(false);
            ManualResetEvent waitForCancel = new ManualResetEvent(false);

            AppFunc app = environment =>
                {
                    OwinResponse response = new OwinResponse(environment);
                    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
                    response.CallCancelled.Register(() =>
                    {
                        waitForCancel.Set();
                        tcs.TrySetCanceled();
                    });
                    waitForRequest.Set();
                    return tcs.Task;
                };

            Task clientTask, serverTask;
            using (Http2ClientSession clientSession = new Http2ClientSession(clientStream, false, CancellationToken.None, CancellationToken.None))
            {
                using (Http2ServerSession serverSession = new Http2ServerSession(app, CreateTransportInfo()))
                {
                    clientTask = clientSession.Start();
                    serverTask = serverSession.Start(serverStream, CancellationToken.None);

                    IList<KeyValuePair<string, string>> requestPairs = GenerateHeaders("GET");
                    Http2ClientStream clientProtocolStream = clientSession.SendRequest(requestPairs, null, 3, false, CancellationToken.None);
                    Task<IList<KeyValuePair<string, string>>> responseTask = clientProtocolStream.GetResponseAsync();
                    waitForRequest.WaitOne();

                    clientStream.Abort();

                    Assert.Throws<AggregateException>(() => responseTask.Result);
                    Assert.Throws<AggregateException>(() => clientTask.Wait(1000));
                    Assert.True(serverTask.Wait(1000));
                    Assert.True(waitForCancel.WaitOne(1000));
                }
            }
        }
        private async void Listen()
        {
            _socket.Listen(backlog: 2);
            while (!_disposed)
            {
                Http2ServerSession session = null;
                Socket clientSocket = null;
                Stream stream = null;
                try
                {
                    clientSocket = await Task.Factory.FromAsync(_socket.BeginAccept, (Func<IAsyncResult, Socket>)_socket.EndAccept, null);
                    stream = new NetworkStream(clientSocket, ownsSocket: true);

                    X509Certificate clientCert = null;

                    if (_enableSsl)
                    {
                        SslStream sslStream = new SslStream(stream);
                        await sslStream.AuthenticateAsServerAsync(_serverCert, clientCertificateRequired: false, enabledSslProtocols: _sslProtocols, checkCertificateRevocation: false);
                        clientCert = sslStream.RemoteCertificate;
                        stream = sslStream;
                    }

                    // TODO: At this point we could read the first bit of the first byte received on this connection to determine if it is a HTTP/1.1 or 2.0 request.

                    IPEndPoint localEndPoint = (IPEndPoint)clientSocket.LocalEndPoint;
                    IPEndPoint remoteEndPoint = (IPEndPoint)clientSocket.RemoteEndPoint;

                    TransportInformation transportInfo = new TransportInformation()
                    {
                        ClientCertificate = clientCert,
                        LocalPort = localEndPoint.Port.ToString(CultureInfo.InvariantCulture),
                        RemotePort = remoteEndPoint.Port.ToString(CultureInfo.InvariantCulture),
                    };

                    // Side effect of using dual mode sockets, the IPv4 addresses look like 0::ffff:127.0.0.1.
                    if (localEndPoint.Address.IsIPv4MappedToIPv6)
                    {
                        transportInfo.LocalIpAddress = localEndPoint.Address.MapToIPv4().ToString();
                    }
                    else
                    {
                        transportInfo.LocalIpAddress = localEndPoint.Address.ToString();
                    }

                    if (remoteEndPoint.Address.IsIPv4MappedToIPv6)
                    {
                        transportInfo.RemoteIpAddress = remoteEndPoint.Address.MapToIPv4().ToString();
                    }
                    else
                    {
                        transportInfo.RemoteIpAddress = remoteEndPoint.Address.ToString();
                    }

                    session = new Http2ServerSession(_next, transportInfo);
                    // TODO: awaiting here will only let us accept the next connection/session after the current one finishes.
                    await session.Start(stream, CancellationToken.None);
                }
                catch (ProtocolViolationException)
                {
                    // Handshake failure, most likely do to receiving a HTTP/1.1 text request.
                }
                catch (SocketException)
                {
                    // Disconnect?
                }
                catch (ObjectDisposedException)
                {
                    Dispose();
                }
                catch (Exception)
                {
                    Dispose();
                    throw;
                }
                finally
                {
                    if (session != null)
                    {
                        session.Dispose();
                    }

                    if (stream != null)
                    {
                        stream.Dispose();
                    }

                    if (clientSocket != null)
                    {
                        clientSocket.Dispose();
                    }
                }
            }
        }