### Bash HTTP API Request for Router Addresses Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Demonstrates how to request router and realm server addresses using `curl`. Includes examples for a GET request and a CORS preflight OPTIONS request. The expected JSON response format is also shown. ```bash # Request router information curl -X GET http://router-manager:5000/get_router \ -H "Accept: application/json" # Response (JSON) { "Realms": [ "192.168.1.10:7777", "192.168.1.11:7777" ], "Routers": [ "203.0.113.1:8080", "203.0.113.2:8080", "203.0.113.3:8080" ] } # CORS preflight support curl -X OPTIONS http://router-manager:5000/get_router \ -H "Access-Control-Request-Method: GET" \ -H "Access-Control-Request-Headers: Content-Type" # Returns: # Access-Control-Allow-Origin: * # Access-Control-Allow-Methods: GET, POST # Access-Control-Max-Age: 1728000 ``` -------------------------------- ### GET /get_router - Retrieve Router and Realm Addresses Source: https://context7.com/et-packages/cn.etetet.router/llms.txt This endpoint retrieves and returns the available router and realm server addresses, which are essential for clients to establish a connection to the game servers. ```APIDOC ## GET /get_router - Retrieve Router and Realm Addresses ### Description Returns available router and realm server addresses for client connection. ### Method GET ### Endpoint /get_router ### Query Parameters None ### Request Body None ### Request Example ```bash curl -X GET http://router-manager:5000/get_router \ -H "Accept: application/json" ``` ### Response #### Success Response (200) - **Realms** (array of strings) - A list of realm server addresses. - **Routers** (array of strings) - A list of router server addresses. #### Response Example ```json { "Realms": [ "192.168.1.10:7777", "192.168.1.11:7777" ], "Routers": [ "203.0.113.1:8080", "203.0.113.2:8080", "203.0.113.3:8080" ] } ``` ### CORS Support #### OPTIONS /get_router Handles CORS preflight requests. #### Request Example ```bash curl -X OPTIONS http://router-manager:5000/get_router \ -H "Access-Control-Request-Method: GET" \ -H "Access-Control-Request-Headers: Content-Type" ``` #### Response Example ``` Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST Access-Control-Max-Age: 1728000 ``` ``` -------------------------------- ### C# HTTP Handler for /get_router API Endpoint Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Server-side implementation for handling GET requests to the /get_router endpoint. It retrieves available realm and router server configurations and returns them as a JSON response with CORS headers. Dependencies include System.Net, ET.Server, and HttpListenerContext. ```csharp // Server-side handler implementation using System.Net; using ET.Server; [HttpHandler(SceneType.RouterManager, "/get_router")] public class HttpGetRouterHandler : IHttpHandler { public async ETTask Handle(Scene scene, HttpListenerContext context) { // Build response with available servers HttpGetRouterResponse response = HttpGetRouterResponse.Create(); // Add realm servers (using internal IP for cloud servers) List realms = StartSceneConfigCategory.Instance .GetBySceneType(SceneType.Realm); foreach (StartSceneConfig config in realms) { response.Realms.Add(config.InnerIPPort.ToString()); } // Add router servers (using external IP for client access) List routers = StartSceneConfigCategory.Instance .GetBySceneType(SceneType.Router); foreach (StartSceneConfig config in routers) { string address = $"{config.StartProcessConfig.OuterIP}:{config.Port}"; response.Routers.Add(address); } // Send JSON response with CORS headers HttpListenerResponse httpResponse = context.Response; httpResponse.AppendHeader("Access-Control-Allow-Origin", "*"); httpResponse.StatusCode = 200; httpResponse.ContentEncoding = Encoding.UTF8; byte[] bytes = MongoHelper.ToJson(response).ToUtf8(); httpResponse.ContentLength64 = bytes.Length; await httpResponse.OutputStream.WriteAsync(bytes, 0, bytes.Length); } } ``` -------------------------------- ### Initialize Router Server (C#) Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Sets up the RouterComponent on game server startup for the router scene. It configures the external and internal IP endpoints for the router, allowing it to listen for external connections and forward traffic to internal game servers. Dependencies include ET.Server namespaces and StartSceneConfig/StartProcessConfig. ```csharp using System.Net; using ET.Server; [Invoke(SceneType.Router)] public class FiberInit_Router : AInvokeHandler { public override async ETTask Handle(FiberInit fiberInit) { Scene root = fiberInit.Fiber.Root; StartSceneConfig sceneConfig = StartSceneConfigCategory.Instance.Get((int)root.Id); StartProcessConfig processConfig = StartProcessConfigCategory.Instance.Get(sceneConfig.Process); // For development: use OuterIPPort // For cloud: use InnerIPPort with firewall port mapping IPEndPoint outerEndPoint = NetworkHelper.ToIPEndPoint( $ירת"{processConfig.OuterIP}:{sceneConfig.Port}" ); root.AddComponent( outerEndPoint, // e.g., "203.0.113.1:8080" processConfig.InnerIP // e.g., "192.168.1.5" ); Log.Console($"Router create: {root.Fiber.Id}"); await ETTask.CompletedTask; } } ``` -------------------------------- ### Initialize Router Component in C# Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Demonstrates how to initialize the RouterComponent on server startup. This involves creating a scene, retrieving process configurations, defining the external endpoint, and adding the RouterComponent with outer and inner network addresses. The component automatically manages transports, packet forwarding, timeouts, and node lifecycles. ```csharp using System.Net; using ET.Server; // Initialize router on server startup Scene routerScene = root.AddChild(); StartProcessConfig processConfig = StartProcessConfigCategory.Instance.Get(processId); IPEndPoint outerEndPoint = NetworkHelper.ToIPEndPoint($"{processConfig.OuterIP}:8080"); // Add router component with outer address and inner IP RouterComponent router = routerScene.AddComponent( outerEndPoint, // External client-facing endpoint processConfig.InnerIP // Internal server network IP ); // Router automatically handles: // - TCP/UDP transport creation // - Packet forwarding between outer/inner networks // - Connection timeout checks (every 1 second) // - RouterNode lifecycle management ``` -------------------------------- ### Initial Connection - RouterSYN/RouterACK Handshake (C#) Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Establishes a new connection between a client and an internal server via a router. It involves a four-step handshake: RouterSYN, RouterACK, SYN, and ACK. This process validates new connections, assigns inner connection IDs, and sets up the router for bidirectional messaging. It uses specific byte packet structures for control messages. ```csharp // CLIENT SIDE - Initiate connection byte[] synPacket = new byte[13 + addressBytes.Length]; synPacket[0] = KcpProtocalType.RouterSYN; BitConverter.GetBytes(outerConn).CopyTo(synPacket, 1); // 12345 BitConverter.GetBytes(0u).CopyTo(synPacket, 5); // innerConn = 0 initially BitConverter.GetBytes(connectId).CopyTo(synPacket, 9); // 98765 Encoding.UTF8.GetBytes("192.168.1.100:5555").CopyTo(synPacket, 13); // Send to router via TCP/UDP // ROUTER - Receives RouterSYN // 1. Validates packet length >= 13 bytes // 2. Checks innerConn == 0 (new connection) // 3. Creates RouterNode with outerConn as ID // 4. Validates connection ID matches // 5. Sends RouterACK back to client byte[] ackPacket = new byte[9]; ackPacket[0] = KcpProtocalType.RouterACK; BitConverter.GetBytes(0u).CopyTo(ackPacket, 1); // innerConn still 0 BitConverter.GetBytes(outerConn).CopyTo(ackPacket, 5); // 12345 // Send to client // CLIENT - Receives RouterACK, now sends SYN to establish session byte[] sessionSyn = new byte[9]; sessionSyn[0] = KcpProtocalType.SYN; BitConverter.GetBytes(outerConn).CopyTo(sessionSyn, 1); // 12345 BitConverter.GetBytes(innerConn).CopyTo(sessionSyn, 5); // 0 (will be assigned) // Send to router // ROUTER - Forwards SYN to internal server with client IP // INTERNAL SERVER - Assigns innerConn and sends ACK byte[] serverAck = new byte[9]; serverAck[0] = KcpProtocalType.ACK; BitConverter.GetBytes(67890u).CopyTo(serverAck, 1); // innerConn assigned BitConverter.GetBytes(outerConn).CopyTo(serverAck, 5); // 12345 // Sent to router via UDP // ROUTER - Forwards ACK to client, sets node.Status = RouterStatus.Msg // Connection now active for bidirectional messaging ``` -------------------------------- ### Initialize RouterManager HTTP Server (C#) Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Sets up an HTTP endpoint for router discovery within the RouterManager scene. This component allows clients to fetch a list of available router servers. It depends on ET.Server and includes TimerComponent and HttpComponent. ```csharp using ET.Server; [Invoke(SceneType.RouterManager)] public class FiberInit_RouterManager : AInvokeHandler { public override async ETTask Handle(FiberInit fiberInit) { Scene root = fiberInit.Fiber.Root; // Add timer for async operations root.AddComponent(); // Get HTTP port from scene configuration StartSceneConfig sceneConfig = StartSceneConfigCategory.Instance.Get((int)root.Id); // Start HTTP server on all interfaces root.AddComponent( $"http://*:{sceneConfig.Port}/" ); // Example: http://*:5000/ - listens on all network interfaces port 5000 // Handles GET /get_router via HttpGetRouterHandler await ETTask.CompletedTask; } } ``` -------------------------------- ### Connection Termination FIN Protocol - C# Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Implements graceful connection termination using the FIN protocol for KCP connections. It covers packet creation and router handling for both client-initiated and server-initiated disconnects. This ensures resources are cleaned up properly on both ends. ```csharp // CLIENT-INITIATED DISCONNECT byte[] finPacket = new byte[13]; finPacket[0] = KcpProtocalType.FIN; BitConverter.GetBytes(outerConn).CopyTo(finPacket, 1); // 12345 BitConverter.GetBytes(innerConn).CopyTo(finPacket, 5); // 67890 BitConverter.GetBytes(0).CopyTo(finPacket, 9); // Error code (optional) // Send to router // ROUTER - Receives client FIN // 1. Validates length == 13 bytes // 2. Finds RouterNode by outerConn // 3. Validates innerConn matches // 4. Updates LastRecvOuterTime // 5. Forwards to internal server routerComponent.InnerSocket.Send(finPacket, 0, 13, node.InnerIpEndPoint, ChannelType.Accept); // RouterNode remains until server confirms // SERVER-INITIATED DISCONNECT byte[] serverFin = new byte[13]; serverFin[0] = KcpProtocalType.FIN; BitConverter.GetBytes(innerConn).CopyTo(serverFin, 1); // 67890 BitConverter.GetBytes(outerConn).CopyTo(serverFin, 5); // 12345 BitConverter.GetBytes(0).CopyTo(serverFin, 9); // Send to router // ROUTER - Receives server FIN // 1. Validates length == 13 bytes // 2. Finds RouterNode by outerConn // 3. Validates innerConn matches // 4. Updates LastRecvInnerTime // 5. Forwards to client node.KcpTransport.Send(serverFin, 0, 13, node.OuterIpEndPoint, ChannelType.Accept); // RouterNode will be cleaned up by timeout checker ``` -------------------------------- ### RouterNode - Connection Session Entity in C# Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Illustrates the structure and usage of a RouterNode, representing a single routed connection session. It shows how to access connection details like status, IDs, network endpoints, timing information, and handshake counters. RouterNodes are automatically created upon client connection and managed by the RouterComponent. ```csharp // RouterNode is automatically created when client connects // Example internal structure showing key connection tracking public void ExampleRouterNodeUsage() { RouterComponent router = scene.GetComponent(); // Get existing connection by outer connection ID uint outerConnId = 12345; RouterNode node = router.GetChild(outerConnId); if (node != null) { // Check connection status bool isSyncing = node.Status == RouterStatus.Sync; // In handshake bool isActive = node.Status == RouterStatus.Msg; // Active messaging // Connection identifiers uint clientConn = node.OuterConn; // Client-side connection ID uint serverConn = node.InnerConn; // Server-side connection ID uint connectionId = node.ConnectId; // Unique connection identifier // Network endpoints IPEndPoint clientAddress = node.OuterIpEndPoint; // Client address IPEndPoint serverAddress = node.InnerIpEndPoint; // Internal server address string serverAddr = node.InnerAddress; // "192.168.1.100:5555" // Timing and rate limiting long lastClientPacket = node.LastRecvOuterTime; long lastServerPacket = node.LastRecvInnerTime; int packetsThisSecond = node.LimitCountPerSecond; // Max 1000/sec // Handshake tracking int routerSyncs = node.RouterSyncCount; // Max 40 before error int synAttempts = node.SyncCount; // Max 20 before error } } ``` -------------------------------- ### Bidirectional Message Forwarding with KCP Router - C# Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Demonstrates sending application messages between client and server through a KCP router. It includes packet construction for client-to-server and server-to-client messages, along with the router's logic for validation and forwarding. Dependencies include BitConverter for byte manipulation and KcpProtocalType enum. ```csharp // CLIENT TO SERVER - Send game message byte[] clientMsg = new byte[9 + gameDataLength]; clientMsg[0] = KcpProtocalType.MSG; BitConverter.GetBytes(outerConn).CopyTo(clientMsg, 1); // 12345 BitConverter.GetBytes(innerConn).CopyTo(clientMsg, 5); // 67890 Array.Copy(gameData, 0, clientMsg, 9, gameDataLength); // Send to router // ROUTER - Receives from client // 1. Validates length >= 9 // 2. Finds RouterNode by outerConn (12345) // 3. Validates innerConn matches node.InnerConn (67890) // 4. Validates node.Status == RouterStatus.Msg // 5. Checks rate limit via CheckOuterCount() // 6. Updates node.LastRecvOuterTime // 7. Forwards entire packet to node.InnerIpEndPoint routerComponent.InnerSocket.Send( packet, 0, packetLength, node.InnerIpEndPoint, ChannelType.Connect ); // SERVER TO CLIENT - Send response byte[] serverMsg = new byte[9 + responseDataLength]; serverMsg[0] = KcpProtocalType.MSG; BitConverter.GetBytes(innerConn).CopyTo(serverMsg, 1); // 67890 BitConverter.GetBytes(outerConn).CopyTo(serverMsg, 5); // 12345 Array.Copy(responseData, 0, serverMsg, 9, responseDataLength); // Send to router via UDP // ROUTER - Receives from server // 1. Finds RouterNode by outerConn (12345) // 2. Validates innerConn matches (67890) // 3. Validates node.Status == RouterStatus.Msg // 4. Updates node.LastRecvInnerTime // 5. Forwards to node.OuterIpEndPoint via appropriate transport node.KcpTransport.Send( packet, 0, packetLength, node.OuterIpEndPoint, ChannelType.Accept ); ``` -------------------------------- ### Reconnection - RouterReconnectSYN/RouterReconnectACK (C#) Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Restores an existing session after a network interruption. This process uses saved outerConn and innerConn IDs to re-establish the connection through a potentially different router. It includes validation steps on the router and internal server to ensure the connection ID and address match the original session, preventing hijacking. ```csharp // CLIENT SIDE - Reconnect with saved connection IDs byte[] reconnectPacket = new byte[13 + addressBytes.Length]; reconnectPacket[0] = KcpProtocalType.RouterReconnectSYN; BitConverter.GetBytes(outerConn).CopyTo(reconnectPacket, 1); // 12345 (saved) BitConverter.GetBytes(innerConn).CopyTo(reconnectPacket, 5); // 67890 (saved) BitConverter.GetBytes(connectId).CopyTo(reconnectPacket, 9); // 98765 (saved) Encoding.UTF8.GetBytes("192.168.1.100:5555").CopyTo(reconnectPacket, 13); // Send to router (may be different router than original) // ROUTER - Receives RouterReconnectSYN // 1. Validates outerConn and innerConn match existing RouterNode // 2. Validates connectId matches (prevents hijacking) // 3. Validates InnerAddress matches // 4. Checks RouterSyncCount < 40 (anti-spam) // 5. Forwards to internal server byte[] innerReconnect = new byte[9]; innerReconnect[0] = KcpProtocalType.RouterReconnectSYN; BitConverter.GetBytes(outerConn).CopyTo(innerReconnect, 1); BitConverter.GetBytes(innerConn).CopyTo(innerReconnect, 5); // Send to internal server UDP endpoint // INTERNAL SERVER - Validates and sends RouterReconnectACK byte[] reconnectAck = new byte[9]; reconnectAck[0] = KcpProtocalType.RouterReconnectACK; BitConverter.GetBytes(innerConn).CopyTo(reconnectAck, 1); // 67890 BitConverter.GetBytes(outerConn).CopyTo(reconnectAck, 5); // 12345 // Send to router // ROUTER - Forwards RouterReconnectACK to client, sets Status = Msg // Session restored, can resume messaging ``` -------------------------------- ### Rate Limiting with CheckOuterCount in C# Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Explains the rate limiting mechanism used to prevent network flooding. The `CheckOuterCount` method, called automatically for incoming packets, enforces a limit of 1000 packets per second per connection. Exceeding this limit results in an error and connection termination. ```csharp using ET.Server; // Called automatically for every packet from external client public static void ProcessIncomingPacket(RouterNode node, byte[] packet, long currentTime) { // Check if packet is within rate limit bool allowed = node.CheckOuterCount(currentTime); if (!allowed) { // Rate limit exceeded: >1000 packets in 1 second RouterComponent router = node.GetParent(); router.OnError(node.Id, ErrorCode.ERR_KcpRouterTooManyPackets); // Connection will be terminated return; } // Packet is within limits, forward to internal server // ... forwarding logic } // Example rate counter behavior // Time 0ms: packet 1 -> LimitCountPerSecond = 1 // Time 500ms: packet 2 -> LimitCountPerSecond = 2 // Time 1001ms: packet 3 -> LimitCountPerSecond resets to 1 // Time 1002ms: packets 4-1003 -> LimitCountPerSecond = 1000 // Time 1003ms: packet 1004 -> Returns false, connection terminated ``` -------------------------------- ### C# Connection Timeout Check for Router Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Monitors and removes stale connections to prevent resource exhaustion. It processes up to 10 connections per second, checking for timeouts during handshake or active messaging states. Re-queues valid connections for subsequent checks. Dependencies include ET.Server namespace and RouterComponent. ```csharp using ET.Server; // Called every 1 second by RouterComponent.Update() public static void MonitorConnections(RouterComponent router, long currentTime) { // Process up to 10 connections per check cycle int checkCount = Math.Min(router.checkTimeout.Count, 10); for (int i = 0; i < checkCount; i++) { uint nodeId = router.checkTimeout.Dequeue(); RouterNode node = router.GetChild(nodeId); if (node == null) { continue; } if (node.Status == RouterStatus.Sync) { // During handshake: 10 second timeout if (currentTime > node.LastRecvOuterTime + 10_000) { router.OnError(nodeId, ErrorCode.ERR_KcpRouterConnectFail); continue; // Connection removed } } else if (node.Status == RouterStatus.Msg) { // During active messaging: session timeout + 10 seconds long maxIdleTime = SessionIdleCheckerComponentSystem.SessionTimeoutTime + 10_000; if (currentTime > node.LastRecvOuterTime + maxIdleTime) { router.OnError(nodeId, ErrorCode.ERR_KcpRouterTimeout); continue; // Connection removed } } // Still valid, re-queue for next check router.checkTimeout.Enqueue(nodeId); } } ``` -------------------------------- ### KCP Router Error Codes Definition - C# Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Defines package-specific error codes for connection failures within the KCP router. These codes help identify the cause of connection issues, such as timeouts, reconnections, and rate limiting. The base calculation ensures uniqueness within the router package. ```csharp namespace ET; public static partial class ErrorCode { // Base calculation: ERR_WithException + (PackageType.Router * 1000) + error_num // Where PackageType.Router = 15, so base = ERR_WithException + 15000 public const int ERR_KcpRouterConnectFail = 15001; // Handshake timeout: no response within 10 seconds during RouterStatus.Sync public const int ERR_KcpRouterTimeout = 15002; // Session timeout: no packets received for (SessionTimeout + 10 seconds) public const int ERR_KcpRouterSame = 15003; // Reconnect failed: ConnectId mismatch indicates different connection public const int ERR_KcpRouterRouterSyncCountTooMuchTimes = 15004; // Attack detected: >40 RouterSYN/RouterReconnectSYN packets sent public const int ERR_KcpRouterTooManyPackets = 15005; // Rate limit exceeded: >1000 packets per second from client public const int ERR_KcpRouterSyncCountTooMuchTimes = 15006; // Attack detected: >20 SYN packets during session establishment } // Usage in connection monitoring if (node.RouterSyncCount > 40) { router.OnError(node.Id, ErrorCode.ERR_KcpRouterRouterSyncCountTooMuchTimes); // Logs: "router node remove: {outerConn} {innerConn} 15004" // RouterNode disposed and removed from component } ``` -------------------------------- ### Connection Timeout Check Source: https://context7.com/et-packages/cn.etetet.router/llms.txt Internal mechanism for automatically removing stale connections to prevent resource exhaustion. This is not an exposed API endpoint but a server-side process. ```APIDOC ## Connection Timeout Check ### Description Automatically removes stale connections to prevent resource exhaustion. This process runs internally on the server. ### Method Internal Server Process (not an HTTP method) ### Endpoint N/A ### Parameters N/A ### Request Body N/A ### Request Example N/A ### Response N/A ### Notes This process is called every 1 second by `RouterComponent.Update()` and processes up to 10 connections per check cycle. It monitors connections based on their status (Sync or Msg) and checks `LastRecvOuterTime` against predefined timeouts. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.