private static void StartRemoteConnection(ConnectToRemoteState state)
        {
            if (state.RequestMethod.Equals("CONNECT", StringComparison.InvariantCultureIgnoreCase))
            {
                // handle SSL response for CONNECT
                HandleSslConnect(state);
                return;
            }

            var remoteip = GetRemoteIp(state.RemoteHost); // TODO: handle SocketError.HostNotFound
            if (remoteip == null)
            {
                WriteLog(state.Session, 0, "ERR");
                return;
            }

            var remoteClient = new TcpClient();

            var remoteConnectionState = new RemoteConnectionState
            {
                Session = state.Session,
                ClientStream = state.ClientStream,
                Client = state.Client,
                MessageStream = state.MessageStream,
                RemoteClient = remoteClient,
                RemoteHost = state.RemoteHost,
                IsSsl = state.IsSsl
            };

            remoteClient.BeginConnect(remoteip, state.RemotePort, ConnectToRemote.Run, remoteConnectionState);
        }
        private static void HandleSslConnect(ConnectToRemoteState state)
        {
            var connectStreamWriter = new StreamWriter(state.ClientStream);
            connectStreamWriter.WriteLine("HTTP/1.0 200 Connection established");
            connectStreamWriter.WriteLine("Timestamp: {0}", DateTime.Now);
            connectStreamWriter.WriteLine("Proxy-agent: GOS Proxy Service");
            connectStreamWriter.WriteLine();
            connectStreamWriter.Flush();

            var sslStream = new SslStream(state.ClientStream, false);
            try
            {
                var certProvider = new CertificateProvider();

                bool created;
                var certificate = certProvider.LoadOrCreateCertificate(state.RemoteHost, out created);
                sslStream.AuthenticateAsServer(certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, true);
            }
            catch (Exception ex)
            {
                WriteLog(state.Session, 0, "ERR", ex.Message);
                sslStream.Close();
                state.ClientStream.Close();
                connectStreamWriter.Close();
                return;
            }

            var nstate = new ClientConnectionState
            {
                Session = state.Session,
                Client = state.Client,
                ClientStream = sslStream,
                ClientStreamBase = (NetworkStream)state.ClientStream,
                Buffer = new byte[Globals.BufferSize],
                MessageStream = new MemoryStream(),
                IsSsl = true,
            };

            try
            {
                sslStream.BeginRead(nstate.Buffer, 0, nstate.Buffer.Length, ReadFromClient.Run, nstate);
            }
            catch (Exception ex)
            {
                WriteLog(state.Session, 0, "ERR", ex.Message);
                sslStream.Close();
                state.ClientStream.Close();
            }
        }
        public static void Run(IAsyncResult asyncResult)
        {
            var state = asyncResult.AsyncState as ClientConnectionState;

            if (state != null)
            {
                int read;
                try
                {
                    read = state.ClientStream.EndRead(asyncResult);
                }
                catch (Exception ex)
                {
                    WriteLog(state.Session, 0, "ERR", ex.Message);
                    state.ClientStreamBase.Close();
                    state.ClientStream.Close();
                    return;
                }
                state.MessageStream.Write(state.Buffer, 0, read);

                if (state.ClientStreamBase.DataAvailable)
                {
                    state.ClientStream.BeginRead(state.Buffer, 0, state.Buffer.Length, ReadFromClient.Run, state);
                }
                else
                {
                    if (read == 0)
                    {
                        state.ClientStream.Close();
                        return;
                    }

                    var messageHeader = ParseClientMessage(state.MessageStream);
                    if (messageHeader == null)
                    {
                        state.ClientStream.Close();
                        state.ClientStreamBase.Close();
                        return;
                    }

                    state.ClientMessageHeader = messageHeader;
                    state.Session.TargetUrl = state.ClientMessageHeader.RemoteUri.ToString();
                    state.Session.Protocoll = state.ClientMessageHeader.Protocol;

                    // TODO: filter the data from the client
                    var connectState = new ConnectToRemoteState
                    {
                        Session = state.Session,
                        RemotePort = state.ClientMessageHeader.RemoteUri.Port,
                        RemoteHost = state.ClientMessageHeader.RemoteUri.Host,
                        RequestMethod = state.ClientMessageHeader.Method,
                        Client = state.Client,
                        ClientStream = state.ClientStream,
                        MessageStream = state.MessageStream,
                        IsSsl = state.IsSsl
                    };

                    StartRemoteConnection(connectState);
                }
            }
        }