Files
GoKart/trunk/Common/Net/Session.cs
Andrew 6d74d5b59e source
Created by: Andrew
2016-08-27 22:43:23 -04:00

295 lines
8.3 KiB
C#

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);
}
}