fix(core): Tightens the network stack (#479)
- [X] Removes network pause/resume - [X] Adds back packet profiler - [X] Adds state machine to keep track and trace netstates - [X] Changes NetState.Running back to using an interlock exchange - [X] Adds preliminary packet throttling support ### Packet Throttling - `[GetThrottle <packetId>` to get the delay in milliseconds for that packet - `[SetThrottle <packetId> <delay>` to set the delay in milliseconds for that packet The settings are saved to `Configuration/throttles.json`
This commit is contained in:
parent
1736469ac0
commit
8903028b5f
36 changed files with 1018 additions and 405 deletions
|
|
@ -172,7 +172,7 @@ namespace Server.Misc
|
|||
if (ns.Connection != null)
|
||||
{
|
||||
ns.WriteConsole("Disconnecting, bad version");
|
||||
ns.Disconnect();
|
||||
ns.Disconnect($"Invalid client version {ns.Version}.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ namespace Server
|
|||
{
|
||||
World.Broadcast(0x35, true, "Generating doors, please wait.");
|
||||
|
||||
NetState.Pause();
|
||||
NetState.FlushAll();
|
||||
|
||||
m_Map = Map.Trammel;
|
||||
m_Count = 0;
|
||||
|
|
@ -389,8 +389,6 @@ namespace Server
|
|||
|
||||
var malasCount = m_Count;
|
||||
|
||||
NetState.Resume();
|
||||
|
||||
World.Broadcast(
|
||||
0x35,
|
||||
true,
|
||||
|
|
|
|||
|
|
@ -145,35 +145,35 @@ namespace Server
|
|||
{
|
||||
reader.ReadByte(); // 1: <4.0.1a, 2>=4.0.1a
|
||||
|
||||
var info = new HardwareInfo();
|
||||
|
||||
info.InstanceID = reader.ReadInt32();
|
||||
info.OSMajor = reader.ReadInt32();
|
||||
info.OSMinor = reader.ReadInt32();
|
||||
info.OSRevision = reader.ReadInt32();
|
||||
info.CpuManufacturer = reader.ReadByte();
|
||||
info.CpuFamily = reader.ReadInt32();
|
||||
info.CpuModel = reader.ReadInt32();
|
||||
info.CpuClockSpeed = reader.ReadInt32();
|
||||
info.CpuQuantity = reader.ReadByte();
|
||||
info.PhysicalMemory = reader.ReadInt32();
|
||||
info.ScreenWidth = reader.ReadInt32();
|
||||
info.ScreenHeight = reader.ReadInt32();
|
||||
info.ScreenDepth = reader.ReadInt32();
|
||||
info.DXMajor = reader.ReadInt16();
|
||||
info.DXMinor = reader.ReadInt16();
|
||||
info.VCDescription = reader.ReadLittleUniSafe(64);
|
||||
info.VCVendorID = reader.ReadInt32();
|
||||
info.VCDeviceID = reader.ReadInt32();
|
||||
info.VCMemory = reader.ReadInt32();
|
||||
info.Distribution = reader.ReadByte();
|
||||
info.ClientsRunning = reader.ReadByte();
|
||||
info.ClientsInstalled = reader.ReadByte();
|
||||
info.PartialInstalled = reader.ReadByte();
|
||||
info.Language = reader.ReadLittleUniSafe(4);
|
||||
info.Unknown = reader.ReadAsciiSafe(64);
|
||||
|
||||
info.TimeReceived = DateTime.UtcNow;
|
||||
var info = new HardwareInfo
|
||||
{
|
||||
InstanceID = reader.ReadInt32(),
|
||||
OSMajor = reader.ReadInt32(),
|
||||
OSMinor = reader.ReadInt32(),
|
||||
OSRevision = reader.ReadInt32(),
|
||||
CpuManufacturer = reader.ReadByte(),
|
||||
CpuFamily = reader.ReadInt32(),
|
||||
CpuModel = reader.ReadInt32(),
|
||||
CpuClockSpeed = reader.ReadInt32(),
|
||||
CpuQuantity = reader.ReadByte(),
|
||||
PhysicalMemory = reader.ReadInt32(),
|
||||
ScreenWidth = reader.ReadInt32(),
|
||||
ScreenHeight = reader.ReadInt32(),
|
||||
ScreenDepth = reader.ReadInt32(),
|
||||
DXMajor = reader.ReadInt16(),
|
||||
DXMinor = reader.ReadInt16(),
|
||||
VCDescription = reader.ReadLittleUniSafe(64),
|
||||
VCVendorID = reader.ReadInt32(),
|
||||
VCDeviceID = reader.ReadInt32(),
|
||||
VCMemory = reader.ReadInt32(),
|
||||
Distribution = reader.ReadByte(),
|
||||
ClientsRunning = reader.ReadByte(),
|
||||
ClientsInstalled = reader.ReadByte(),
|
||||
PartialInstalled = reader.ReadByte(),
|
||||
Language = reader.ReadLittleUniSafe(4),
|
||||
Unknown = reader.ReadAsciiSafe(64),
|
||||
TimeReceived = DateTime.UtcNow
|
||||
};
|
||||
|
||||
if (state.Account is Account acct)
|
||||
{
|
||||
|
|
|
|||
157
Projects/UOContent/Misc/PacketThrottles.cs
Normal file
157
Projects/UOContent/Misc/PacketThrottles.cs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Server.Json;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static class PacketThrottles
|
||||
{
|
||||
// Delay in milliseconds
|
||||
private static readonly int[] Delays = new int[0x100];
|
||||
private static string ThrottlesConfiguration = "Configuration/throttles.json";
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("GetThrottle", AccessLevel.Administrator, GetThrottle);
|
||||
CommandSystem.Register("SetThrottle", AccessLevel.Administrator, SetThrottle);
|
||||
|
||||
var configPath = ThrottlesConfiguration;
|
||||
var path = Path.Join(Core.BaseDirectory, configPath);
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var throttles = JsonConfig.Deserialize<SortedDictionary<string, int>>(path);
|
||||
foreach (var (k, v) in throttles)
|
||||
{
|
||||
if (!Utility.ToInt32(k, out var packetId))
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.DarkYellow);
|
||||
Console.WriteLine("Packet Throttles: Error deserializing {0} from {1}", k, configPath);
|
||||
Utility.PopColor();
|
||||
continue;
|
||||
}
|
||||
|
||||
Delays[packetId] = v;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Delays[0x03] = 5; // Speech
|
||||
Delays[0xAD] = 5; // Speech
|
||||
Delays[0x75] = 500; // Rename request
|
||||
}
|
||||
|
||||
for (int i = 0; i < 0x100; i++)
|
||||
{
|
||||
if (Delays[i] > 0)
|
||||
{
|
||||
IncomingPackets.RegisterThrottler(i, Throttle);
|
||||
}
|
||||
}
|
||||
|
||||
SaveDelays();
|
||||
}
|
||||
|
||||
[Usage("GetThrottle <packetID>")]
|
||||
[Description("Gets throttle for the given packet.")]
|
||||
public static void GetThrottle(CommandEventArgs e)
|
||||
{
|
||||
if (e.Length != 1)
|
||||
{
|
||||
e.Mobile.SendMessage("Invalid Command Format. Should be [GetThrottle <packetID>");
|
||||
return;
|
||||
}
|
||||
|
||||
int packetID = e.GetInt32(0);
|
||||
|
||||
if (packetID < 0 || packetID > 0x100)
|
||||
{
|
||||
e.Mobile.SendMessage("Invalid Command Format. PacketID must be between 0 and 0x100.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
e.Mobile.SendMessage("Packet 0x{0:X} throttle is currently {1}ms.", packetID, Delays[packetID]);
|
||||
}
|
||||
|
||||
[Usage("SetThrottle <packetID> <timeInMilliseconds>")]
|
||||
[Description("Sets a throttle for the given packet.")]
|
||||
public static void SetThrottle(CommandEventArgs e)
|
||||
{
|
||||
if (e.Length != 2)
|
||||
{
|
||||
e.Mobile.SendMessage("Invalid Command Format. Should be [SetThrottle <packetID> <timeInMilliseconds>");
|
||||
return;
|
||||
}
|
||||
|
||||
int packetID = e.GetInt32(0);
|
||||
int delay = e.GetInt32(1);
|
||||
|
||||
if (packetID < 0 || packetID > 0x100)
|
||||
{
|
||||
e.Mobile.SendMessage("Invalid Command Format. PacketID must be between 0 and 0x100.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (delay > 5000)
|
||||
{
|
||||
e.Mobile.SendMessage("Invalid Command Format. Delay cannot exceed 5000 milliseconds.");
|
||||
return;
|
||||
}
|
||||
|
||||
long oldDelay = Delays[packetID];
|
||||
|
||||
if (oldDelay == 0 && delay > 0)
|
||||
{
|
||||
IncomingPackets.RegisterThrottler(packetID, Throttle);
|
||||
}
|
||||
else if (oldDelay > 0 && delay == 0)
|
||||
{
|
||||
IncomingPackets.RegisterThrottler(packetID, null);
|
||||
}
|
||||
|
||||
Delays[packetID] = delay;
|
||||
SaveDelays();
|
||||
}
|
||||
|
||||
private static void SaveDelays()
|
||||
{
|
||||
SortedDictionary<string, int> table = new();
|
||||
for (var i = 0; i < Delays.Length; i++)
|
||||
{
|
||||
var delay = Delays[i];
|
||||
|
||||
if (delay != 0)
|
||||
{
|
||||
table[$"0x{i:X2}"] = delay;
|
||||
}
|
||||
}
|
||||
|
||||
var configPath = ThrottlesConfiguration;
|
||||
var path = Path.Join(Core.BaseDirectory, configPath);
|
||||
JsonConfig.Serialize(path, table);
|
||||
}
|
||||
|
||||
public static bool Throttle(int packetID, NetState ns, out bool drop)
|
||||
{
|
||||
if (ns.Mobile is not PlayerMobile player || player.AccessLevel >= AccessLevel.Counselor)
|
||||
{
|
||||
drop = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Core.TickCount < ns.GetPacketDelay(packetID) + Delays[packetID])
|
||||
{
|
||||
drop = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
drop = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -99,7 +99,7 @@ namespace Server.Misc
|
|||
return true;
|
||||
case ProfanityAction.Disconnect:
|
||||
{
|
||||
from.NetState?.Disconnect();
|
||||
from.NetState?.Disconnect("Using profanity.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue