Fixed the ban loop bug (client goes into zombie state if immediately kicked upon joining, and won't disconnect until a timeout)

This commit is contained in:
RaidMax 2017-05-28 20:07:33 -05:00
parent 28fcc7b922
commit bc452cfd93
14 changed files with 48 additions and 64 deletions

View File

@ -322,7 +322,7 @@ copy /Y "$(ProjectDir)lib\SQLite.Interop.dll" "$(SolutionDir)BUILD\lib"
if $(ConfigurationName) == Release powershell.exe -file "$(SolutionDir)DEPLOY\publish_nightly.ps1" %25iw4madmin_version%25</PostBuildEvent> if $(ConfigurationName) == Release powershell.exe -file "$(SolutionDir)DEPLOY\publish_nightly.ps1" 1.3</PostBuildEvent>
</PropertyGroup> </PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -23,6 +23,9 @@ namespace IW4MAdmin
public Logger(string fn) public Logger(string fn)
{ {
FileName = fn; FileName = fn;
if (File.Exists(fn))
File.Delete(fn);
} }
void Write(string msg, LogType type) void Write(string msg, LogType type)

View File

@ -16,11 +16,10 @@ namespace IW4MAdmin
static void Main(string[] args) static void Main(string[] args)
{ {
Version = 1.3; Version = 1.3;
double latestVersion = 0;
handler = new ConsoleEventDelegate(OnProcessExit); handler = new ConsoleEventDelegate(OnProcessExit);
SetConsoleCtrlHandler(handler, true); SetConsoleCtrlHandler(handler, true);
double.TryParse(CheckUpdate(), out latestVersion); double.TryParse(CheckUpdate(), out double latestVersion);
Console.WriteLine("====================================================="); Console.WriteLine("=====================================================");
Console.WriteLine(" IW4M ADMIN"); Console.WriteLine(" IW4M ADMIN");
Console.WriteLine(" by RaidMax "); Console.WriteLine(" by RaidMax ");

View File

@ -83,7 +83,7 @@ namespace IW4MAdmin
Servers.Add(ServerInstance); Servers.Add(ServerInstance);
// this way we can keep track of execution time and see if problems arise. // this way we can keep track of execution time and see if problems arise.
var Status = new AsyncStatus(ServerInstance); var Status = new AsyncStatus(ServerInstance, UPDATE_FREQUENCY);
TaskStatuses.Add(Status); TaskStatuses.Add(Status);
Logger.WriteVerbose($"Now monitoring {ServerInstance.Hostname}"); Logger.WriteVerbose($"Now monitoring {ServerInstance.Hostname}");
@ -123,7 +123,7 @@ namespace IW4MAdmin
{ {
Status.Update(new Task(() => (Status.Dependant as Server).ProcessUpdatesAsync(Status.GetToken()))); Status.Update(new Task(() => (Status.Dependant as Server).ProcessUpdatesAsync(Status.GetToken())));
if (Status.RunAverage > 500) if (Status.RunAverage > 500)
Logger.WriteWarning($"Update task average execution is longer than desired for {(Status.Dependant as Server).getIP()}::{(Status.Dependant as Server).getPort()}"); Logger.WriteWarning($"Update task average execution is longer than desired for {(Status.Dependant as Server).getIP()}::{(Status.Dependant as Server).getPort()} [{Status.RunAverage}ms]");
} }
} }

View File

@ -2,13 +2,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.IO; using System.IO;
using System.Runtime.InteropServices;
using System.Linq; using System.Linq;
using SharedLibrary; using SharedLibrary;
using SharedLibrary.Network; using SharedLibrary.Network;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Net;
namespace IW4MAdmin namespace IW4MAdmin
{ {
@ -36,7 +33,7 @@ namespace IW4MAdmin
} }
} }
public override List<Aliases> getAliases(Player Origin) public override List<Aliases> GetAliases(Player Origin)
{ {
List<Aliases> allAliases = new List<Aliases>(); List<Aliases> allAliases = new List<Aliases>();
@ -52,14 +49,17 @@ namespace IW4MAdmin
return allAliases; return allAliases;
} }
//Add player object p to `players` list
override public async Task<bool> AddPlayer(Player P) override public async Task<bool> AddPlayer(Player P)
{ {
if (P.clientID < 0 || P.clientID > (Players.Count-1)) // invalid index if (P.clientID < 0 || P.clientID > (Players.Count-1) || P.Ping < 1 || P.Ping == 999) // invalid index
return false; return false;
if (Players[P.clientID] != null && Players[P.clientID].npID == P.npID) // if someone has left and a new person has taken their spot between polls if (Players[P.clientID] != null && Players[P.clientID].npID == P.npID) // if someone has left and a new person has taken their spot between polls
{
// update their ping
Players[P.clientID].Ping = P.Ping;
return true; return true;
}
Logger.WriteDebug($"Client slot #{P.clientID} now reserved"); Logger.WriteDebug($"Client slot #{P.clientID} now reserved");
@ -86,6 +86,7 @@ namespace IW4MAdmin
await this.ExecuteCommandAsync("clientkick " + P.clientID + " \"Please do not impersonate an admin^7\""); await this.ExecuteCommandAsync("clientkick " + P.clientID + " \"Please do not impersonate an admin^7\"");
} }
// below this needs to be optimized ~ 425ms runtime
NewPlayer.updateName(P.Name.Trim()); NewPlayer.updateName(P.Name.Trim());
NewPlayer.Alias = aliasDB.getPlayer(NewPlayer.databaseID); NewPlayer.Alias = aliasDB.getPlayer(NewPlayer.databaseID);
@ -122,24 +123,8 @@ namespace IW4MAdmin
if (NewPlayer.Level == Player.Permission.Banned) // their guid is already banned so no need to check aliases if (NewPlayer.Level == Player.Permission.Banned) // their guid is already banned so no need to check aliases
{ {
String Message;
Logger.WriteInfo($"Banned client {P.Name}::{P.npID} trying to connect..."); Logger.WriteInfo($"Banned client {P.Name}::{P.npID} trying to connect...");
await NewPlayer.Kick(NewPlayer.lastOffense != null ? "^7Previously banned for ^5 " + NewPlayer.lastOffense : "^7Previous Ban", NewPlayer);
if (NewPlayer.lastOffense != null)
Message = "Previously banned for ^5" + NewPlayer.lastOffense;
else
Message = "Previous Ban";
await NewPlayer.Kick(Message, NewPlayer);
if (Players[NewPlayer.clientID] != null)
{
lock (Players)
{
Players[NewPlayer.clientID] = null;
}
}
return true; return true;
} }
@ -161,25 +146,15 @@ namespace IW4MAdmin
Logger.WriteDebug($"Banned client {aP.Name}::{aP.npID} is connecting with new alias {NewPlayer.Name}"); Logger.WriteDebug($"Banned client {aP.Name}::{aP.npID} is connecting with new alias {NewPlayer.Name}");
NewPlayer.lastOffense = String.Format("Evading ( {0} )", aP.Name); NewPlayer.lastOffense = String.Format("Evading ( {0} )", aP.Name);
if (B.Reason != null) await NewPlayer.Ban(B.Reason != null ? "^7Previously banned for ^5 " + B.Reason : "^7Previous Ban", NewPlayer);
await NewPlayer.Ban("^7Previously Banned: ^5" + B.Reason, NewPlayer); Players[NewPlayer.clientID] = null;
else
await NewPlayer.Ban("^7Previous Ban", NewPlayer);
lock (Players)
{
if (Players[NewPlayer.clientID] != null)
Players[NewPlayer.clientID] = null;
}
return true; return true;
} }
} }
lock (Players) Players[NewPlayer.clientID] = null;
{ Players[NewPlayer.clientID] = NewPlayer;
Players[NewPlayer.clientID] = null; // just in case we have shit in the way
Players[NewPlayer.clientID] = NewPlayer;
}
#if DEBUG == FALSE #if DEBUG == FALSE
await NewPlayer.Tell($"Welcome ^5{NewPlayer.Name} ^7this is your ^5{NewPlayer.TimesConnected()} ^7time connecting!"); await NewPlayer.Tell($"Welcome ^5{NewPlayer.Name} ^7this is your ^5{NewPlayer.TimesConnected()} ^7time connecting!");
#endif #endif
@ -471,7 +446,6 @@ namespace IW4MAdmin
Logger.WriteError("Unexpected error on \"" + Hostname + "\""); Logger.WriteError("Unexpected error on \"" + Hostname + "\"");
Logger.WriteDebug("Error Message: " + E.Message); Logger.WriteDebug("Error Message: " + E.Message);
Logger.WriteDebug("Error Trace: " + E.StackTrace); Logger.WriteDebug("Error Trace: " + E.StackTrace);
return 1;
} }
#endif #endif
} }
@ -702,7 +676,7 @@ namespace IW4MAdmin
if (Target.clientID > -1) if (Target.clientID > -1)
{ {
await this.ExecuteCommandAsync($"tempbanclient {Target.clientID } \"^1Player Temporarily Banned: ^5{ Reason } (1 hour)\""); await this.ExecuteCommandAsync($"tempbanclient {Target.clientID } \"^1Player Temporarily Banned: ^5{ Reason } (1 hour)\"");
Penalty newPenalty = new Penalty(Penalty.Type.TempBan, SharedLibrary.Utilities.StripColors(Reason), Target.npID, Origin.npID, DateTime.Now, Target.IP); Penalty newPenalty = new Penalty(Penalty.Type.TempBan, Reason.StripColors(), Target.npID, Origin.npID, DateTime.Now, Target.IP);
await Task.Run(() => await Task.Run(() =>
{ {
Manager.GetClientPenalties().AddPenalty(newPenalty); Manager.GetClientPenalties().AddPenalty(newPenalty);
@ -710,11 +684,9 @@ namespace IW4MAdmin
} }
} }
private String getWebsiteString() private String GetWebsiteString()
{ {
if (Website != null) return Website != null ? $" (appeal at {Website}" : " (appeal at this server's website)";
return String.Format(" (appeal at {0})", Website);
return " (appeal at this server's website)";
} }
override public async Task Ban(String Message, Player Target, Player Origin) override public async Task Ban(String Message, Player Target, Player Origin)
@ -734,7 +706,7 @@ namespace IW4MAdmin
{ {
var activeClient = server.getPlayers().Find(x => x.npID == Target.npID); var activeClient = server.getPlayers().Find(x => x.npID == Target.npID);
if (activeClient != null) if (activeClient != null)
await server.ExecuteCommandAsync("tempbanclient " + activeClient.clientID + " \"" + Message + "^7" + getWebsiteString() + "^7\""); await server.ExecuteCommandAsync("tempbanclient " + activeClient.clientID + " \"" + Message + "^7" + GetWebsiteString() + "^7\"");
} }
} }

View File

@ -619,7 +619,7 @@ namespace IW4MAdmin
{ {
if (pp == null) continue; if (pp == null) continue;
var playerAliases = Manager.GetInstance().Servers.First().getAliases(pp); var playerAliases = Manager.GetInstance().Servers.First().GetAliases(pp);
PlayerInfo eachPlayer = new PlayerInfo(); PlayerInfo eachPlayer = new PlayerInfo();
eachPlayer.playerID = pp.databaseID; eachPlayer.playerID = pp.databaseID;
eachPlayer.playerIP = pp.IP; eachPlayer.playerIP = pp.IP;

Binary file not shown.

View File

@ -12,15 +12,17 @@ namespace SharedLibrary
CancellationToken Token; CancellationToken Token;
DateTime StartTime; DateTime StartTime;
int TimesRun; int TimesRun;
int UpdateFrequency;
public double RunAverage { get; private set; } public double RunAverage { get; private set; }
public object Dependant { get; private set; } public object Dependant { get; private set; }
public Task RequestedTask { get; private set; } public Task RequestedTask { get; private set; }
public AsyncStatus(object dependant) public AsyncStatus(object dependant, int frequency)
{ {
Token = new CancellationToken(); Token = new CancellationToken();
StartTime = DateTime.Now; StartTime = DateTime.Now;
Dependant = dependant; Dependant = dependant;
UpdateFrequency = frequency;
// technically 0 but it's faster than checking for division by 0 // technically 0 but it's faster than checking for division by 0
TimesRun = 1; TimesRun = 1;
} }
@ -40,10 +42,10 @@ namespace SharedLibrary
RequestedTask = T; RequestedTask = T;
RequestedTask.Start(); RequestedTask.Start();
if (TimesRun > 100) if (TimesRun > 25)
TimesRun = 1; TimesRun = 1;
RunAverage = RunAverage + ((DateTime.Now - StartTime).TotalMilliseconds - RunAverage) / TimesRun; RunAverage = RunAverage + ((DateTime.Now - StartTime).TotalMilliseconds - RunAverage - UpdateFrequency) / TimesRun;
StartTime = DateTime.Now; StartTime = DateTime.Now;
} }
} }

View File

@ -41,6 +41,11 @@ namespace SharedLibrary
return ((Player)obj).npID == this.npID; return ((Player)obj).npID == this.npID;
} }
public override int GetHashCode()
{
return base.GetHashCode();
}
public Player(string n, string id, int num, int l) public Player(string n, string id, int num, int l)
{ {
Name = n; Name = n;
@ -178,6 +183,8 @@ namespace SharedLibrary
public DateTime LastConnection { get; private set; } public DateTime LastConnection { get; private set; }
public Server currentServer { get; private set; } public Server currentServer { get; private set; }
public int Ping;
public Event lastEvent; public Event lastEvent;
public String lastOffense; public String lastOffense;
public int Warnings; public int Warnings;

View File

@ -32,12 +32,13 @@ namespace SharedLibrary.Network
{ {
String[] playerInfo = responseLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); String[] playerInfo = responseLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
int cID = -1; int cID = -1;
int Ping = -1;
Int32.TryParse(playerInfo[2], out Ping);
String cName = Utilities.StripColors(responseLine.Substring(46, 18)).Trim(); String cName = Utilities.StripColors(responseLine.Substring(46, 18)).Trim();
String npID = responseLine.Substring(29, 17).Trim(); // DONT TOUCH PLZ String npID = responseLine.Substring(29, 17).Trim(); // DONT TOUCH PLZ
int.TryParse(playerInfo[0], out cID); int.TryParse(playerInfo[0], out cID);
String cIP = responseLine.Substring(72, 20).Trim().Split(':')[0]; String cIP = responseLine.Substring(72, 20).Trim().Split(':')[0];
Player P = new Player(cName, npID, cID, cIP) { Ping = Ping };
Player P = new Player(cName, npID, cID, cIP);
StatusPlayers.Add(P); StatusPlayers.Add(P);
} }
} }

View File

@ -121,13 +121,13 @@ namespace SharedLibrary
/// Get any know aliases ( name or ip based ) from the database /// Get any know aliases ( name or ip based ) from the database
/// </summary> /// </summary>
/// <param name="Origin">Player to scan for aliases</param> /// <param name="Origin">Player to scan for aliases</param>
abstract public List<Aliases> getAliases(Player Origin); abstract public List<Aliases> GetAliases(Player Origin);
public List<Player> getPlayerAliases(Player Origin) public List<Player> getPlayerAliases(Player Origin)
{ {
List<int> databaseIDs = new List<int>(); List<int> databaseIDs = new List<int>();
foreach (Aliases A in getAliases(Origin)) foreach (Aliases A in GetAliases(Origin))
databaseIDs.Add(A.Number); databaseIDs.Add(A.Number);
return Manager.GetClientDatabase().getPlayers(databaseIDs); return Manager.GetClientDatabase().getPlayers(databaseIDs);

View File

@ -268,9 +268,9 @@ namespace SharedLibrary
case 100: case 100:
return "One-Hundreth (amazing!)"; return "One-Hundreth (amazing!)";
case 500: case 500:
return "^7You're really ^5dedicated ^7to this server! This is your ^5500th ^7time connecting!"; return "you're really ^5dedicated ^7to this server! This is your ^5500th^7";
case 1000: case 1000:
return "WOW! Soldier, it's your ^11000th ^7time connecting! You deserve a medal."; return "you deserve a medal. it's your ^11000th^7";
default: default:
return connection.ToString() + Prefix; return connection.ToString() + Prefix;

View File

@ -5,7 +5,6 @@ using SharedLibrary;
using SharedLibrary.Network; using SharedLibrary.Network;
using SharedLibrary.Interfaces; using SharedLibrary.Interfaces;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading;
namespace Votemap_Plugin namespace Votemap_Plugin
{ {
@ -223,7 +222,6 @@ namespace Votemap_Plugin
public async Task OnTickAsync(Server S) public async Task OnTickAsync(Server S)
{ {
var serverVotes = getServerVotes(S.getPort()); var serverVotes = getServerVotes(S.getPort());
Thread.Sleep(500);
if (serverVotes != null) if (serverVotes != null)
{ {

View File

@ -53,10 +53,12 @@ namespace Welcome_Plugin
Player newPlayer = E.Origin; Player newPlayer = E.Origin;
if (newPlayer.Level >= Player.Permission.Trusted && !E.Origin.Masked) if (newPlayer.Level >= Player.Permission.Trusted && !E.Origin.Masked)
await E.Owner.Broadcast(Utilities.levelToColor(newPlayer.Level) + " ^5" + newPlayer.Name + " ^7has joined the server."); await E.Owner.Broadcast(Utilities.levelToColor(newPlayer.Level) + " ^5" + newPlayer.Name + " ^7has joined the server.");
await newPlayer.Tell($"Welcome ^5{newPlayer.Name}^7, this your ^5{newPlayer.TimesConnected()} ^7time connecting!");
if (newPlayer.Level == Player.Permission.Flagged) if (newPlayer.Level == Player.Permission.Flagged)
await E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name}^7 has joined!"); await E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name}^7 has joined!");
else else
{ {