protected override void ProcessAccept(GamespyUdpPacket Packet)
{
IPEndPoint remote = (IPEndPoint)Packet.AsyncEventArgs.RemoteEndPoint;
// Need at least 5 bytes
if (Packet.BytesRecieved.Length < 5)
{
base.Release(Packet.AsyncEventArgs);
return;
}
// Handle request in a new thread
Task.Run(() =>
{
// If we dont reply, we must manually release the pool
bool replied = false;
try
{
// Both the clients and servers will send a Gamespy Available Heartbeat Check
// When starting Battlefield 2, the client will send 7 heartbeat checks
if (Packet.BytesRecieved[0] == 0x09 && Packet.BytesRecieved.SequenceEqual(BF2AvailableRequest))
{
DebugLog.Write("BF2Available Called From {0}:{1}", remote.Address, remote.Port);
// Send back a generic reply.
Packet.SetBufferContents(BF2AvailableReply);
base.ReplyAsync(Packet);
replied = true;
}
else if (Packet.BytesRecieved[0] == 0x03 && Program.Config.GamespyEnableServerlist)
{
// === this is where server details come in, it starts with 0x03, it happens every 60 seconds or so
// If we aren't validated (initial connection), send a challenge key
if (!ParseServerDetails(remote, Packet.BytesRecieved.Skip(5).ToArray()))
{
DebugLog.Write("Sending Server Challenge to {0}:{1}", remote.Address, remote.Port);
// this should be some sort of proper encrypted challenge, but for now i'm just going to hard code
// it because I don't know how the encryption works...
byte[] uniqueId = Packet.BytesRecieved.Skip(1).Take(4).ToArray();
Packet.SetBufferContents(new byte[]
{
0xfe, 0xfd, 0x01, uniqueId[0], uniqueId[1], uniqueId[2], uniqueId[3], 0x44, 0x3d, 0x73,
0x7e, 0x6a, 0x59, 0x30, 0x30, 0x37, 0x43, 0x39, 0x35, 0x41, 0x42, 0x42, 0x35, 0x37, 0x34,
0x43, 0x43, 0x00
});
base.ReplyAsync(Packet);
replied = true;
}
}
else if (Packet.BytesRecieved[0] == 0x01 && Program.Config.GamespyEnableServerlist)
{
// === this is a challenge response, it starts with 0x01
if (Packet.BytesRecieved.Skip(5).SequenceEqual(ServerValidateCode))
{
DebugLog.Write("Server Challenge Recieved and Validated: {0}:{1}", remote.Address, remote.Port);
// Send back a good response if we validate successfully
if (ValidateServer(remote))
{
byte[] uniqueId = Packet.BytesRecieved.Skip(1).Take(4).ToArray();
Packet.SetBufferContents(new byte[] { 0xfe, 0xfd, 0x0a, uniqueId[0], uniqueId[1], uniqueId[2], uniqueId[3] });
base.ReplyAsync(Packet);
replied = true;
}
}
else
DebugLog.Write("Server Challenge Received and FAILED Validation: {0}:{1}", remote.Address, remote.Port);
}
else if (Packet.BytesRecieved[0] == 0x08 && Program.Config.GamespyEnableServerlist)
{
// this is a server ping, it starts with 0x08, it happens every 20 seconds or so
string key = String.Format("{0}:{1}", remote.Address, remote.Port);
GameServer server;
if (Servers.TryGetValue(key, out server) && server.IsValidated)
{
DebugLog.Write("Server Heartbeat Received: " + key);
// Update Ping
server.LastPing = DateTime.Now;
Servers.AddOrUpdate(key, server, (k, old) => { return server; });
}
else
DebugLog.Write("Server Heartbeat Received from Unvalidated Server: " + key);
}
}
catch (Exception E)
{
Program.ErrorLog.Write("ERROR: [MasterUdpServer.ProcessAccept] " + E.Message);
}
// Release so that we can pool the EventArgs to be used on another connection
if (!replied)
base.Release(Packet.AsyncEventArgs);
});
}