ace/Source/ACE.Server/Network/ClientPacket.cs
fartwhif f0717d4d23 fixing networking bugs (#1104)
* adding @netstats admin command

* trying to figure out the issue

* fixing bug causing AcknowledgeSequence packets to increment the lastReceivedFragmentSequence variable, causing the Sequence to break and never recover for that session
fixing bug causing RequestTransmit packets to be ignored
fixing bug causing the server to crash when a C2S packet is corrupt or malformed
changing the C2S RequestForTransmit packet count to be per request packet instead of per requested sequence
adding Developer commands junk, junk_s2c, junk_c2s, trash_s2c, and trash_c2s to simulate bad connections and manually corrupt packets

* updating changelog.md

* Update changelog.md

fixed incorrect variable name referred to in change log

* Update changelog.md

fix formatting

* adding preprocessor definition NETDIAG and directives to ACE.Common and ACE.Server to help development by preserving troubleshooting tools without interference with the optimal solution

* Apply suggestions from code review

set accessor only needed for NETDIAG functionality
minor change log addition

* reverting some unnecessary source syntax and formatting changes.
removing an unused exception variable

* reverting some unnecessary source syntax and formatting changes

* minor optimization of a duplicate prevention check
2018-11-30 23:58:00 -05:00

95 lines
3.2 KiB
C#

using System;
using System.IO;
using log4net;
namespace ACE.Server.Network
{
public class ClientPacket : Packet
{
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static readonly ILog packetLog = LogManager.GetLogger(System.Reflection.Assembly.GetEntryAssembly(), "Packets");
public BinaryReader Payload { get; private set; }
public PacketHeaderOptional HeaderOptional { get; private set; }
public bool IsValid { get; private set; } = false;
public ClientPacket(byte[] data)
{
#if NETDIAG
data = NetworkSyntheticTesting.SyntheticCorruption_C2S(data);
#endif
ParsePacketData(data);
if (IsValid)
ReadFragments();
}
private void ParsePacketData(byte[] data)
{
try
{
using (var stream = new MemoryStream(data))
{
using (var reader = new BinaryReader(stream))
{
Header = new PacketHeader(reader);
if (Header.Size > data.Length - reader.BaseStream.Position)
{
IsValid = false;
return;
}
Data = new MemoryStream(reader.ReadBytes(Header.Size), 0, Header.Size, false, true);
Payload = new BinaryReader(Data);
HeaderOptional = new PacketHeaderOptional(Payload, Header);
if (!HeaderOptional.IsValid)
{
IsValid = false;
return;
}
}
}
IsValid = true;
}
catch(Exception ex)
{
IsValid = false;
log.Error("Invalid packet data", ex);
}
}
private void ReadFragments()
{
if (Header.HasFlag(PacketHeaderFlags.BlobFragments))
{
while (Payload.BaseStream.Position != Payload.BaseStream.Length)
{
try
{
Fragments.Add(new ClientPacketFragment(Payload));
}
catch (Exception)
{
// corrupt packet
IsValid = false;
break;
}
}
}
}
public bool VerifyChecksum(uint issacXor)
{
uint fragmentChecksum = 0u;
foreach (ClientPacketFragment fragment in Fragments)
{
fragmentChecksum += fragment.CalculateHash32();
}
uint payloadChecksum = HeaderOptional.CalculateHash32() + fragmentChecksum;
uint finalChecksum = Header.CalculateHash32() + (payloadChecksum ^ issacXor);
packetLog.DebugFormat("Checksum is calculated as {0} and is {1} in header", finalChecksum, Header.Checksum);
return finalChecksum == Header.Checksum;
}
}
}