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); }
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); }
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); }