Пример #1
0
        private void OnHttpConnection(IAsyncResult asyncResult)
        {
            if (!running)
            {
                return;
            }

            try
            {
                // Accept client
                HttpListenerContext context = httpListener.EndGetContext(asyncResult);

                IPEndPoint clientEndPoint = context.Request.RemoteEndPoint;
                HostInfo   clientInfo     = new HostInfo(clientEndPoint.Address.ToString(), (ushort)clientEndPoint.Port);

                new Thread(() =>
                {
                    // Connect to main server
                    HostInfo mainTargetInfo = targetBalancer(clientInfo);
                    if (mainTargetInfo == null)
                    {
                        return;
                    }

                    HostConnected?.Invoke(this, clientInfo);

                    // Create a HttpWebRequest
                    Func <HostInfo, HttpWebRequest> requestBuilder = (HostInfo target) =>
                    {
                        Uri uri = new Uri(new Uri($"http://{target.Hostname}:{target.Port}"), context.Request.RawUrl);
                        HttpWebRequest request = WebRequest.CreateHttp(uri);

                        // Copy headers
                        string xff = "";

                        foreach (string key in context.Request.Headers.Keys)
                        {
                            string value = context.Request.Headers[key];

                            switch (key.ToLower())
                            {
                            case "connection":
                                {
                                    switch (value.ToLower())
                                    {
                                    case "keep-alive": request.KeepAlive = true; break;

                                    case "close": break;

                                    default: request.Connection = value; break;
                                    }

                                    break;
                                }

                            case "host": break;

                            case "accept": request.Accept = value; break;

                            case "user-agent": request.UserAgent = value; break;

                            case "x-forwarded-for": xff = value; break;

                            case "content-length": request.ContentLength = int.Parse(value); break;

                            case "content-type": request.ContentType = value; break;

                            case "referer": request.Referer = value; break;

                            default:
                                request.Headers.Add(key, value);
                                break;
                            }
                        }

                        request.Method = context.Request.HttpMethod;
                        request.Host   = $"{target.Hostname}:{target.Port}";
                        request.Headers["X-Forwarded-For"] = string.IsNullOrEmpty(xff) ? clientInfo.Hostname : $"{xff}, {clientInfo.Hostname}";

                        return(request);
                    };

                    try
                    {
                        // Copy stream if needed
                        Stream requestStream = context.Request.InputStream;

                        HostInfo[] otherTargets = targetCloner(clientInfo).ToArray();
                        if (otherTargets.Length > 0)
                        {
                            MemoryStream bufferedStream = new MemoryStream();
                            requestStream.CopyTo(bufferedStream);
                            requestStream = bufferedStream;

                            requestStream.Seek(0, SeekOrigin.Begin);
                        }

                        // Execute request and copy stream
                        HttpWebRequest mainTargetRequest = requestBuilder(mainTargetInfo);

                        if (context.Request.HttpMethod != "GET")
                        {
                            using (Stream mainTargetStream = mainTargetRequest.GetRequestStream())
                                requestStream.CopyTo(mainTargetStream);
                        }

                        // Send request to secondary targets
                        new Thread(() =>
                        {
                            foreach (HostInfo target in otherTargets)
                            {
                                HttpWebRequest targetRequest = requestBuilder(target);

                                if (context.Request.HttpMethod != "GET")
                                {
                                    requestStream.Seek(0, SeekOrigin.Begin);

                                    using (Stream targetStream = targetRequest.GetRequestStream())
                                        requestStream.CopyTo(targetStream);
                                }

                                try
                                {
                                    targetRequest.GetResponse();
                                }
                                catch { }
                            }
                        }).Start();

                        HttpWebResponse mainTargetResponse;

                        try
                        {
                            mainTargetResponse = mainTargetRequest.GetResponse() as HttpWebResponse;
                        }
                        catch (WebException e)
                        {
                            mainTargetResponse = e.Response as HttpWebResponse;
                        }

                        // Copy headers
                        foreach (string key in mainTargetResponse.Headers.Keys)
                        {
                            string value = mainTargetResponse.Headers[key];

                            switch (key.ToLower())
                            {
                            case "transfer-encoding": break;

                            case "content-length": context.Response.ContentLength64 = int.Parse(value); break;

                            default:
                                context.Response.Headers.Add(key, value);
                                break;
                            }
                        }

                        context.Response.StatusCode = (int)mainTargetResponse.StatusCode;

                        try
                        {
                            using (Stream mainTargetStream = mainTargetResponse.GetResponseStream())
                                mainTargetStream.CopyTo(context.Response.OutputStream);
                        }
                        catch (Exception e)
                        {
                            logger.Warn($"Error while writing HTTP response. The client might have disconnected. " + e);
                        }

                        context.Response.Close();
                    }
                    catch (Exception e)
                    {
                        logger.Warn($"Error while processing HTTP client. " + e);
                    }
                    finally
                    {
                        HostDisconnected?.Invoke(this, clientInfo);
                    }
                }).Start();
            }
            catch (Exception e)
            {
                logger.Warn($"Error while processing HTTP client. " + e);
            }

            httpListener.BeginGetContext(OnHttpConnection, null);
        }
Пример #2
0
        public bool ProcessOneMessages()
        {
            NetIncomingMessage im;

            if (SocketClient != null && (im = SocketClient.ReadMessage()) != null)
            {
                switch (im.MessageType)
                {
                case NetIncomingMessageType.DebugMessage:
                case NetIncomingMessageType.ErrorMessage:
                case NetIncomingMessageType.WarningMessage:
                case NetIncomingMessageType.VerboseDebugMessage:
                    /*AddLogLine(im.ReadString());*/
                    break;

                case NetIncomingMessageType.StatusChanged:
                    NetConnectionStatus status = (NetConnectionStatus)im.ReadByte();

                    string reason = im.ReadString();
                    //	AddLogLine(NetUtility.ToHexString(im.SenderConnection.RemoteUniqueIdentifier) + " " + status + ": " + reason);

                    if (status == NetConnectionStatus.Connected)
                    {
                        lock (Locker)
                            Connected = true;

                        //                          if(im.SenderConnection.RemoteHailMessage != null)
                        //                              AddLogLine("Remote hail: " + im.SenderConnection.RemoteHailMessage.ReadString());
                        if (HostConnected != null)
                        {
                            HostConnected.Invoke(this, EventArgs.Empty);
                        }
                    }
                    else if (status == NetConnectionStatus.Disconnected)
                    {
                        lock (Locker)
                            Connected = false;

                        if (HostDisconnected != null)
                        {
                            HostDisconnected.Invoke(this, EventArgs.Empty);
                        }
                    }
                    break;

                case NetIncomingMessageType.Data:
                {
                    NetworkMessage msg = MessageFactory.ParseMessage(im);
                    lock (PendingInboundMessages)
                        PendingInboundMessages.Add(msg);
                }
                break;

                default:
                    //AddLogLine("Unhandled type: " + im.MessageType + " " + im.LengthBytes + " bytes " + im.DeliveryMethod + "|" + im.SequenceChannel);
                    break;
                }
                if (SocketClient != null)
                {
                    SocketClient.Recycle(im);
                }

                return(true);
            }
            return(false);
        }
Пример #3
0
        private void OnTcpConnection(IAsyncResult asyncResult)
        {
            if (!running)
            {
                return;
            }

            try
            {
                // Accept client
                TcpClient client = tcpListener.EndAcceptTcpClient(asyncResult);

                IPEndPoint clientEndPoint = client.Client.RemoteEndPoint as IPEndPoint;
                HostInfo   clientInfo     = new HostInfo(clientEndPoint.Address.ToString(), (ushort)clientEndPoint.Port);

                new Thread(() =>
                {
                    // Connect to main server
                    HostInfo mainTargetInfo = targetBalancer(clientInfo);
                    if (mainTargetInfo == null)
                    {
                        return;
                    }

                    TargetConnection mainTarget;

                    HostConnected?.Invoke(this, clientInfo);

                    try
                    {
                        TcpClient mainTargetConnection = new TcpClient(mainTargetInfo.Hostname, mainTargetInfo.Port);
                        mainTarget = new TargetConnection(mainTargetInfo, mainTargetConnection, mainTargetConnection.GetStream());
                    }
                    catch (Exception e)
                    {
                        logger.Warn($"Could not connect to output {mainTargetInfo.Hostname}:{mainTargetInfo.Port}. Skipping connection. {e}");

                        HostDisconnected?.Invoke(this, clientInfo);
                        return;
                    }

                    Dictionary <HostInfo, TargetConnection> outputTargets = targetCloner(clientInfo).ToDictionary <HostInfo, HostInfo, TargetConnection>(t => t, t => null);

                    ClientConnection clientConnection = new ClientConnection(clientInfo, client, client.GetStream(), mainTarget, outputTargets);
                    activeConnections.Add(clientConnection);

                    // Connect to output targets
                    foreach (var outputInfo in clientConnection.OutputTargets.ToArray())
                    {
                        try
                        {
                            TcpClient outputClient = new TcpClient();

                            Task connectTask = outputClient.ConnectAsync(outputInfo.Key.Hostname, outputInfo.Key.Port);
                            if (!connectTask.Wait(Program.Timeout))
                            {
                                logger.Warn($"Could not connect to output {outputInfo.Key.Hostname}:{outputInfo.Key.Port} after {Program.Timeout}. Output will be skipped");
                                continue;
                            }

                            TargetConnection outputConnection = new TargetConnection(outputInfo.Key, outputClient, outputClient.GetStream());
                            clientConnection.OutputTargets[outputInfo.Key] = outputConnection;
                        }
                        catch (Exception e)
                        {
                            logger.Warn($"Could not connect to output {outputInfo.Key.Hostname}:{outputInfo.Key.Port}. Output will be skipped. {e}");
                        }
                    }

                    // Client > Target
                    new Thread(() =>
                    {
                        Exception exception = null;

                        try
                        {
                            byte[] buffer = new byte[bufferSize];

                            while (true)
                            {
                                int read = clientConnection.Stream.Read(buffer, 0, buffer.Length);
                                if (read == 0)
                                {
                                    break;
                                }

                                foreach (var targetInfo in outputTargets.ToArray())
                                {
                                    if (targetInfo.Value == null)
                                    {
                                        continue;
                                    }

                                    ulong totalSize = (ulong)targetInfo.Value.Buffers.Count * bufferSize + bufferSize;
                                    if (totalSize > Program.BufferSize)
                                    {
                                        logger.Warn($"Output target {targetInfo.Key.Hostname}:{targetInfo.Key.Port} has reach its maximum buffer size. Output will be skipped");

                                        outputTargets[targetInfo.Key] = null;
                                        Try(targetInfo.Value.Connection.Close);

                                        continue;
                                    }

                                    targetInfo.Value.Buffers.Enqueue(new ArraySegment <byte>(buffer, 0, read));
                                }

                                mainTarget.Stream.Write(buffer, 0, read);
                                mainTarget.Stream.Flush();

                                buffer = new byte[bufferSize];
                            }
                        }
                        catch (Exception e)
                        {
                            exception = e;
                        }
                        finally
                        {
                            Try(mainTarget.Connection.Close);

                            foreach (TargetConnection targetConnection in outputTargets.Values)
                            {
                                if (targetConnection != null)
                                {
                                    Try(targetConnection.Connection.Close);
                                }
                            }

                            lock (activeConnections)
                            {
                                if (activeConnections.Remove(clientConnection))
                                {
                                    if (exception != null)
                                    {
                                        if (!(exception is IOException) || !(exception.InnerException is SocketException))
                                        {
                                            logger.Warn("Exception while reading from client. " + exception);
                                        }
                                    }

                                    HostDisconnected?.Invoke(this, clientConnection.ClientInfo);
                                }
                            }
                        }
                    }).Start();

                    // Target > Client
                    new Thread(() =>
                    {
                        Exception exception = null;

                        try
                        {
                            byte[] buffer = new byte[bufferSize];

                            while (true)
                            {
                                int read = mainTarget.Stream.Read(buffer, 0, buffer.Length);
                                if (read == 0)
                                {
                                    break;
                                }

                                clientConnection.Stream.Write(buffer, 0, read);
                                clientConnection.Stream.Flush();
                            }
                        }
                        catch (Exception e)
                        {
                            exception = e;
                        }
                        finally
                        {
                            Try(client.Close);

                            foreach (TargetConnection targetConnection in outputTargets.Values)
                            {
                                if (targetConnection != null)
                                {
                                    Try(targetConnection.Connection.Close);
                                }
                            }

                            lock (activeConnections)
                            {
                                if (activeConnections.Remove(clientConnection))
                                {
                                    if (exception != null)
                                    {
                                        if (!(exception is IOException) || !(exception.InnerException is SocketException))
                                        {
                                            logger.Warn("Exception while reading from target. " + exception);
                                        }
                                    }

                                    HostDisconnected?.Invoke(this, clientConnection.ClientInfo);
                                }
                            }
                        }
                    }).Start();

                    // Flush output target connections
                    byte[] readBuffer = new byte[bufferSize];

                    while (true)
                    {
                        int outputTargetCount = 0;
                        int dequeuedBuffers   = 0;

                        foreach (var outputInfo in clientConnection.OutputTargets.ToArray())
                        {
                            if (outputInfo.Value == null)
                            {
                                continue;
                            }

                            outputTargetCount++;

                            try
                            {
                                ArraySegment <byte> buffer;
                                while (outputInfo.Value.Buffers.TryDequeue(out buffer))
                                {
                                    dequeuedBuffers++;

                                    outputInfo.Value.Stream.Write(buffer.Array, buffer.Offset, buffer.Count);
                                    outputInfo.Value.Stream.Flush();
                                }

                                while (outputInfo.Value.Stream.DataAvailable)
                                {
                                    outputInfo.Value.Stream.Read(readBuffer, 0, readBuffer.Length);
                                }
                            }
                            catch
                            {
                                logger.Warn($"Could not send buffer to output target {outputInfo.Key.Hostname}:{outputInfo.Key.Port}. Output will be skipped");

                                outputTargets[outputInfo.Key] = null;
                                Try(outputInfo.Value.Connection.Close);

                                continue;
                            }
                        }

                        if (outputTargetCount == 0)
                        {
                            break;
                        }

                        if (dequeuedBuffers == 0)
                        {
                            Thread.Sleep(10);
                        }
                    }
                }).Start();
            }
            catch (Exception e)
            {
                logger.Warn($"Error while processing TCP client. " + e);
            }

            tcpListener.BeginAcceptTcpClient(OnTcpConnection, null);
        }