source
Created by: Andrew
This commit is contained in:
65
trunk/Common/Net/Acceptor.cs
Normal file
65
trunk/Common/Net/Acceptor.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using KartExtreme.IO;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace KartExtreme.Net
|
||||
{
|
||||
public sealed class Acceptor
|
||||
{
|
||||
public const int Backlog = 25;
|
||||
|
||||
public ushort Port { get; private set; }
|
||||
|
||||
private readonly TcpListener m_listener;
|
||||
|
||||
private bool m_disposed;
|
||||
|
||||
public Action<Socket> OnClientAccepted;
|
||||
|
||||
public Acceptor(ushort port) : this(IPAddress.Any, port) { }
|
||||
|
||||
public Acceptor(IPAddress ip, ushort port)
|
||||
{
|
||||
Port = port;
|
||||
m_listener = new TcpListener(IPAddress.Any, port);
|
||||
OnClientAccepted = null;
|
||||
m_disposed = false;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
m_listener.Start(Backlog);
|
||||
m_listener.BeginAcceptSocket(EndAccept, null);
|
||||
|
||||
Log.Inform("Initialized clients listener on {0}.", this.Port);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private void EndAccept(IAsyncResult iar)
|
||||
{
|
||||
if (m_disposed) { return; }
|
||||
|
||||
Socket client = m_listener.EndAcceptSocket(iar);
|
||||
|
||||
if (OnClientAccepted != null)
|
||||
OnClientAccepted(client);
|
||||
|
||||
if (!m_disposed)
|
||||
m_listener.BeginAcceptSocket(EndAccept, null);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!m_disposed)
|
||||
{
|
||||
m_disposed = true;
|
||||
m_listener.Server.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
74
trunk/Common/Net/Cryptography.cs
Normal file
74
trunk/Common/Net/Cryptography.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace KartExtreme.Net
|
||||
{
|
||||
class Cryptography
|
||||
{
|
||||
public static uint HashPacket(byte[] pData, uint pKey, bool pEncrypt, uint npacketLength)
|
||||
{
|
||||
uint hash1 = (pKey ^ 0x14B307C8);
|
||||
uint hash2 = (pKey ^ 0x8CBF12AC);
|
||||
uint hash3 = (pKey ^ 0x240397C1);
|
||||
uint hash4 = (pKey ^ 0xF3BD29C0);
|
||||
|
||||
uint checksum = 0;
|
||||
int packetLength = (int)npacketLength;//pData.Length;
|
||||
|
||||
|
||||
Action<int, uint> doHash = (index, hash) =>
|
||||
{
|
||||
pData[index + 0] ^= (byte)(hash & 0xFF);
|
||||
pData[index + 1] ^= (byte)((hash << 8) & 0xFF);
|
||||
pData[index + 2] ^= (byte)((hash << 16) & 0xFF);
|
||||
pData[index + 3] ^= (byte)((hash << 24) & 0xFF);
|
||||
};
|
||||
|
||||
int offset = 0;
|
||||
int i = 0;
|
||||
for (i = 0; i < (packetLength >> 4); ++i)
|
||||
{
|
||||
if (pEncrypt)
|
||||
checksum ^= (uint)(BitConverter.ToUInt32(pData, offset + 12) ^ BitConverter.ToUInt32(pData, offset + 8) ^ BitConverter.ToUInt32(pData, offset + 4) ^ BitConverter.ToUInt32(pData, offset + 0));
|
||||
|
||||
doHash(offset + 0, hash1);
|
||||
doHash(offset + 4, hash2);
|
||||
doHash(offset + 8, hash3);
|
||||
doHash(offset + 12, hash4);
|
||||
|
||||
if (!pEncrypt)
|
||||
checksum ^= (uint)(BitConverter.ToUInt32(pData, offset + 12) ^ BitConverter.ToUInt32(pData, offset + 8) ^ BitConverter.ToUInt32(pData, offset + 4) ^ BitConverter.ToUInt32(pData, offset + 0));
|
||||
|
||||
offset += 16;
|
||||
}
|
||||
|
||||
|
||||
i *= 16;
|
||||
int sub = 0;
|
||||
|
||||
///Note: it has a problem with Checksum Calculation
|
||||
while (i < packetLength)
|
||||
{
|
||||
if (pEncrypt) checksum ^= (uint)(pData[i] << sub);
|
||||
pData[i] ^= (byte)(hash1 << (sub * 8));
|
||||
if (!pEncrypt) checksum ^= (uint)(pData[i] << sub);
|
||||
sub++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/*
|
||||
for (int i = offset; i < packetLength; i++)
|
||||
{
|
||||
if (pEncrypt) checksum ^= (uint)(pData[i] << sub);
|
||||
pData[i] ^= (byte)(hash1 << (sub * 8));
|
||||
if (!pEncrypt) checksum ^= (uint)(pData[i] << sub);
|
||||
sub++;
|
||||
}*/
|
||||
|
||||
return checksum;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
trunk/Common/Net/SendPacketException.cs
Normal file
12
trunk/Common/Net/SendPacketException.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace KartExtreme.Net
|
||||
{
|
||||
public sealed class SendPacketException : Exception
|
||||
{
|
||||
public SendPacketException()
|
||||
: base("Disconnected while sending packet")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
294
trunk/Common/Net/Session.cs
Normal file
294
trunk/Common/Net/Session.cs
Normal file
@@ -0,0 +1,294 @@
|
||||
using KartExtreme.IO;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Sockets;
|
||||
using KartExtreme.IO.Packet;
|
||||
|
||||
namespace KartExtreme.Net
|
||||
{
|
||||
public abstract class Session
|
||||
{
|
||||
private Socket _socket;
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _bufferIndex;
|
||||
|
||||
private bool _header;
|
||||
private bool _connected;
|
||||
|
||||
private string _label;
|
||||
|
||||
private uint riv;
|
||||
private uint siv;
|
||||
|
||||
private object _lock;
|
||||
|
||||
public string Label
|
||||
{
|
||||
get
|
||||
{
|
||||
return _label;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _connected;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Session class.
|
||||
/// </summary>
|
||||
/// <param name="socket"></param>
|
||||
public Session(Socket socket)
|
||||
{
|
||||
this._socket = socket;
|
||||
this._socket.NoDelay = true;
|
||||
|
||||
this._label = this._socket.RemoteEndPoint.ToString();
|
||||
|
||||
this._connected = true;
|
||||
|
||||
this._lock = new object();
|
||||
|
||||
this.InitiateReceive(4, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initiates the receiving mechanism.
|
||||
/// </summary>
|
||||
/// <param name="length">The length of the data</param>
|
||||
/// <param name="header">Indicates if a header is received</param>
|
||||
private void InitiateReceive(uint length, bool header = false)
|
||||
{
|
||||
if (!this._connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this._header = header;
|
||||
this._buffer = new byte[length];
|
||||
this._bufferIndex = 0;
|
||||
|
||||
this.BeginReceive();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins to asynchronously receive data from the socket.
|
||||
/// </summary>
|
||||
private void BeginReceive()
|
||||
{
|
||||
if (!this._connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var error = SocketError.Success;
|
||||
|
||||
this._socket.BeginReceive(this._buffer,
|
||||
this._bufferIndex,
|
||||
this._buffer.Length - this._bufferIndex,
|
||||
SocketFlags.None, out error,
|
||||
EndReceive,
|
||||
null);
|
||||
|
||||
if (error != SocketError.Success)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the data from the callback and handles it.
|
||||
/// </summary>
|
||||
/// <param name="iar"></param>
|
||||
private void EndReceive(IAsyncResult iar)
|
||||
{
|
||||
if (!this._connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var error = SocketError.Success;
|
||||
int received = this._socket.EndReceive(iar, out error);
|
||||
|
||||
if (received == 0 || error != SocketError.Success)
|
||||
{
|
||||
this.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
this._bufferIndex += received;
|
||||
|
||||
if (this._bufferIndex == this._buffer.Length)
|
||||
{
|
||||
if (this._header)
|
||||
{
|
||||
uint header = BitConverter.ToUInt32(this._buffer, 0);
|
||||
|
||||
if(riv != 0)
|
||||
header = (riv ^ header ^ 0xF834A608);
|
||||
|
||||
this.InitiateReceive(header, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (riv != 0)
|
||||
{
|
||||
int bufferLength = _buffer.Length - 4;
|
||||
|
||||
uint originalChecksum = (uint)(riv ^ BitConverter.ToUInt32(this._buffer, bufferLength) ^ 0xC9F84A90);
|
||||
|
||||
Array.Resize<byte>(ref this._buffer, bufferLength);
|
||||
|
||||
uint checksum = Cryptography.HashPacket(this._buffer, riv, false, (uint)bufferLength);
|
||||
|
||||
if (originalChecksum != checksum)
|
||||
{
|
||||
Log.Warn("Decrypt Checksum different!");
|
||||
}
|
||||
|
||||
riv += 21446425;
|
||||
|
||||
if (riv == 0)
|
||||
riv = 1;
|
||||
}
|
||||
|
||||
this.OnPacket(new InPacket(this._buffer));
|
||||
this.InitiateReceive(4, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.BeginReceive();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the initial patch data packet to the socket.
|
||||
/// </summary>
|
||||
/// <param name="version">The version's information</param>
|
||||
/// <param name="patchLocation">The patch data URL</param>
|
||||
public void SendPatchData(Version version, string patchLocation)
|
||||
{
|
||||
//Fuck!!!!!
|
||||
Random rnd = new Random();
|
||||
|
||||
uint val_first = 0;//(uint)rnd.Next();
|
||||
uint val_second = 0;//(uint)rnd.Next() ;
|
||||
|
||||
using (OutPacket outPacket = new OutPacket())
|
||||
{
|
||||
outPacket.WriteHexString("80 05 2B 28"); // NOTE: Header. Do not change. Probably typeid() of handler.
|
||||
outPacket.WriteShort(version.Localisation);
|
||||
outPacket.WriteShort(version.Major);
|
||||
outPacket.WriteShort(version.Minor);
|
||||
outPacket.WriteString(patchLocation);
|
||||
outPacket.WriteInt((int)val_first); // NOTE: IV Keys. Should we do random stuffs?
|
||||
outPacket.WriteInt((int)val_second);
|
||||
outPacket.WriteByte(0xE0); // NOTE: Some stuff used on Region / Service Area.
|
||||
outPacket.WriteHexString("03 00 09 03 00 00 03 00 00 00 00 00 83 A3 E5 47 00 00 15 00 0D 00 00 00 03 00 00 00 00 00 65");
|
||||
|
||||
this.Send(outPacket);
|
||||
}
|
||||
|
||||
riv = val_first ^ val_second;
|
||||
siv = val_first ^ val_second;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a KartExtreme.IO.OutPacket array to the socket.
|
||||
/// </summary>
|
||||
/// <param name="outPacket"></param>
|
||||
public void Send(OutPacket outPacket)
|
||||
{
|
||||
this.Send(outPacket.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends data to the socket.
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
public void Send(byte[] buffer)
|
||||
{
|
||||
if (!this._connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
|
||||
byte[] data = new byte[buffer.Length + (siv != 0 ? 8 : 4)];
|
||||
|
||||
if (siv == 0)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes((int)buffer.Length), 0, data, 0, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint newHash = Cryptography.HashPacket(buffer, siv, true, (uint)buffer.Length);
|
||||
|
||||
// NOTE: Length at beginning.
|
||||
Buffer.BlockCopy(BitConverter.GetBytes((int)(siv ^ (buffer.Length + 4) ^ 0xF834A608)), 0, data, 0, 4);
|
||||
// NOTE: Checksum at end.
|
||||
Buffer.BlockCopy(BitConverter.GetBytes((uint)(siv ^ newHash ^ 0xC9F84A90)), 0, data, data.Length - 4, 4);
|
||||
|
||||
siv += 0x1473F19;
|
||||
|
||||
if (siv == 0)
|
||||
siv = 1;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(buffer, 0, data, 4, buffer.Length);
|
||||
|
||||
this.SendRaw(data);
|
||||
}
|
||||
}
|
||||
|
||||
private void SendRaw(byte[] data)
|
||||
{
|
||||
if (!this._connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
|
||||
while (offset < data.Length)
|
||||
{
|
||||
SocketError error = SocketError.Success;
|
||||
int sent = this._socket.Send(data, offset, data.Length - offset, SocketFlags.None, out error);
|
||||
|
||||
if (sent == 0 || error != SocketError.Success)
|
||||
{
|
||||
throw new SendPacketException();
|
||||
}
|
||||
|
||||
offset += sent;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the socket.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (!this._connected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this._socket.Shutdown(SocketShutdown.Both);
|
||||
this._socket.Close();
|
||||
|
||||
this.OnDisconnect();
|
||||
}
|
||||
|
||||
public abstract void OnDisconnect();
|
||||
public abstract void OnPacket(InPacket inPacket);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user