private static void DoHandleClient(object objClient) { currentClient = (RCONClient)objClient; if (ValidRCONClients.Count == 0) { currentClient.SetLoginState(RCONClient.ELoginState.LoggedIn); } try { HandleClient(); } catch (Exception e) { LogManager.Error("RCON", "Exception occured in RCON thread for " + currentClient.RemoteEndpoint); LogManager.Error("RCON", e.ToString()); } if (currentClient.tcpClient.Connected) { currentClient.tcpClient.Close(); } }
private static void HandleClient() { LogManager.Log("RCON", "Accepted RCON connection from " + currentClient.Username + " (" + currentClient.RemoteEndpoint + ")"); bool closingConnection = false; NetworkStream stream = currentClient.tcpClient.GetStream(); string welcomeString = Program.BismuthWelcomeHeader + "\r\nWelcome to this Bismuth RCON server\r\n"; if (true) //Check if login required { welcomeString += "\r\n" + UsernamePrompt; } SendClientResponse(stream, Encoding.ASCII.GetBytes(welcomeString)); Stopwatch timeSinceLastRequest = new Stopwatch(); Stopwatch timeSinceLastInput = new Stopwatch(); while (!closingConnection) { timeSinceLastRequest.Restart(); LinkedList <byte> requestData = new LinkedList <byte>(); byte lastByte = 255; while (lastByte != 10) { timeSinceLastInput.Restart(); while (currentClient.tcpClient.Available == 0) { Thread.Sleep(2); if (timeSinceLastRequest.ElapsedMilliseconds > RCONConnectionMaxTTL * 1000) { SendClientResponse(stream, ttlFullExpiredText, true); closingConnection = true; break; } else if (timeSinceLastInput.ElapsedMilliseconds > RCONConnectionInputTTL * 1000) { SendClientResponse(stream, ttlInputExpiredText, true); closingConnection = true; break; } } if (!currentClient.tcpClient.Connected || closingConnection) { closingConnection = true; break; } byte[] pdata = new byte[currentClient.tcpClient.Available]; stream.Read(pdata, 0, pdata.Length); for (int i = 0; i < pdata.Length; i++) { if (pdata[i] == 8) //Backspace { if (requestData.Count > 0) { requestData.RemoveLast(); } continue; } requestData.AddLast(pdata[i]); } lastByte = requestData.Last == null ? lastByte: requestData.Last.Value; } if (closingConnection || !currentClient.tcpClient.Connected) { break; } string requestString = Encoding.ASCII.GetString(requestData.ToArray()).TrimEnd('\r', '\n'); requestString = new string(requestString.Where(c => !char.IsControl(c)).ToArray()); if (requestString == "" && currentClient.LoginState == RCONClient.ELoginState.NotLoggedIn) { requestString = "quit"; currentClient.SetLoginState(RCONClient.ELoginState.LoggedIn); //Will be booted straight out again } if (currentClient.LoginState == RCONClient.ELoginState.NotLoggedIn) { currentClient.SetUsername(requestString); currentClient.SetLoginState(RCONClient.ELoginState.NeedPassword); SendClientResponse(stream, PasswordPrompt); } else if (currentClient.LoginState == RCONClient.ELoginState.NeedPassword) { if ((ValidRCONClients.ContainsKey(currentClient.Username) || ValidRCONClients.ContainsKey("@" + currentClient.Username)) && AuthManager.CheckPlaintextCredentials(authType, requestString, ValidRCONClients[currentClient.Username])) { SendClientResponse(stream, LoginSuccessfulText + currentClient.Username + "!\r\n"); currentClient.SetLoginState(RCONClient.ELoginState.LoggedIn); LogManager.Log("RCON", "Client " + currentClient.Username + " successfully logged in"); } else { LogManager.Log("RCON", "Client " + currentClient.RemoteEndpoint + " failed to login as " + currentClient.Username); currentClient.SetUsername(currentClient.RemoteEndpoint); SendClientResponse(stream, LoginFailedText); currentClient.SetLoginState(RCONClient.ELoginState.NotLoggedIn); } } else if (currentClient.LoginState == RCONClient.ELoginState.LoggedIn) { string[] request = requestString.Split(' '); if (request.Length == 0) { continue; } string command = request[0].ToLower(); string[] commandArgs = request.Skip(1).ToArray(); if (command == "quit" || command == "disconnect" || command == "exit") { command = "quit"; closingConnection = true; } byte[] responseData; if (commands.ContainsKey(command)) { object response = commands[command].Invoke(commandArgs); if (response is byte[]) { responseData = (byte[])response; } else { responseData = Encoding.ASCII.GetBytes(response.ToString()); } } else { //Presume that the request contained secure data LogManager.Log("RCON - " + currentClient.Username + TelnetInputPromptStr + command + " + " + commandArgs.Length + " args"); responseData = Encoding.ASCII.GetBytes("Error: Unknown command '" + command + "'"); } SendClientResponse(stream, responseData, closingConnection); } } LogManager.Log("RCON", "Closed RCON connection from " + currentClient.Username + " (" + currentClient.RemoteEndpoint + ")"); currentClient.tcpClient.Close(); }
private static void DoHandleClient(object objClient) { currentClient = (RCONClient)objClient; if (ValidRCONClients.Count == 0) currentClient.SetLoginState(RCONClient.ELoginState.LoggedIn); try { HandleClient(); } catch (Exception e) { LogManager.Error("RCON", "Exception occured in RCON thread for " + currentClient.RemoteEndpoint); LogManager.Error("RCON", e.ToString()); } if (currentClient.tcpClient.Connected) currentClient.tcpClient.Close(); }