Bonsoir Monsieur/Madame,
je suis ici ce soir pour exposer un problème qui est étonnant ! En effet ; j'utilise la classe MessagePart de BehaviorIsManaged (#bouh2), cette classe fonctionne à merveille en Full Socket mais pas en MITM ! C'est très étonnant :ugeek: !
Dans un premier temps voici la classe en question:
Cliquez pour révéler
Cliquez pour masquer
namespace SmartBot.Network.Message
{
public class MessagePart
{
#region Variables
public bool IsValid
{
get
{
return Header.HasValue && Length.HasValue &&
Length == Data.Length;
}
}
public int? Header { get; private set; }
public int? MessageId
{
get
{
if (!Header.HasValue)
return null;
return Header >> 2;
}
}
public int? LengthBytesCount
{
get
{
if (!Header.HasValue)
return null;
return Header & 0x3;
}
}
public int? Length
{
get;
private set;
}
private byte[] m_data;
public byte[] Data
{
get { return m_data; }
private set { m_data = value; }
}
public byte[] FullPacket { get; set; }
#endregion
#region Methods
public bool Build(BigEndianReader reader)
{
if (IsValid)
return true;
FullPacket = reader.Data;
if (reader.BytesAvailable >= 2 && !Header.HasValue)
{
Header = reader.ReadShort();
}
if (LengthBytesCount.HasValue &&
reader.BytesAvailable >= LengthBytesCount && !Length.HasValue)
{
if (LengthBytesCount < 0 || LengthBytesCount > 3)
throw new Exception("Malformated Message Header, invalid bytes number to read message length (inferior to 0 or superior to 3)");
Length = 0;
// 3..0 or 2..0 or 1..0
for (int i = LengthBytesCount.Value - 1; i >= 0; i--)
{
Length |= reader.ReadByte() << (i * 8);
}
}
// first case : no data read
if (Data == null && Length.HasValue)
{
if (Length == 0)
Data = new byte[0];
// enough bytes in the buffer to build a complete message
if (reader.BytesAvailable >= Length)
{
Data = reader.ReadBytes(Length.Value);
}
// not enough bytes, so we read what we can
else if (Length > reader.BytesAvailable)
{
Data = reader.ReadBytes((int)reader.BytesAvailable);
}
}
//second case : the message was split and it missed some bytes
if (Data != null && Length.HasValue && Data.Length < Length)
{
int bytesToRead = 0;
// still miss some bytes ...
if (Data.Length + reader.BytesAvailable < Length)
bytesToRead = (int)reader.BytesAvailable;
// there is enough bytes in the buffer to complete the message :)
else if (Data.Length + reader.BytesAvailable >= Length)
bytesToRead = Length.Value - Data.Length;
if (bytesToRead != 0)
{
int oldLength = Data.Length;
Array.Resize(ref m_data, (int)(Data.Length + bytesToRead));
Array.Copy(reader.ReadBytes(bytesToRead), 0, Data, oldLength, bytesToRead);
}
}
return IsValid;
}
#endregion
}
}
Ensuite voici ma classe network qui utilise notre fameux MessagePart:
Cliquez pour révéler
Cliquez pour masquer
namespace SmartBot.Network.Client
{
public class SimpleClient
{
#region Variables
private Socket clientSocket;
public bool Runing { get; private set; }
private byte[] sendBuffer, receiveBuffer;
private BigEndianReader buffer;
const int bufferLength = 8192;
private MessagePart currentMessage;
#endregion
#region Builder
public SimpleClient()
{
Init();
}
#endregion
#region Methods
public void Start(Socket socket)
{
Runing = true;
clientSocket = socket;
clientSocket.BeginReceive(receiveBuffer, 0, bufferLength, SocketFlags.None, new AsyncCallback(ReceiveCallBack), clientSocket);
}
public void Start(string ip, short port)
{
clientSocket.BeginConnect(new IPEndPoint(IPAddress.Parse(ip), port), new AsyncCallback(ConnectionCallBack), clientSocket);
}
public void Stop()
{
clientSocket.BeginDisconnect(false, DisconectedCallBack, clientSocket);
}
public void Send(byte[] data)
{
if (clientSocket.Connected == false)
Runing = false;
if (Runing)
{
if (data.Length == 0)
return;
sendBuffer = data;
clientSocket.BeginSend(sendBuffer, 0, sendBuffer.Length, SocketFlags.None, new AsyncCallback(SendCallBack), clientSocket);
}
else
Console.WriteLine("Send " + data.Length + " bytes but not runing");
}
public void Send(NetworkMessage message)
{
BigEndianWriter writer = new BigEndianWriter();
message.Pack(writer);
Send(writer.Data);
}
public void Init()
{
buffer = new BigEndianReader();
receiveBuffer = new byte[bufferLength];
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
private void ThreatBuffer()
{
if (buffer.BytesAvailable <= 0)
return;
if (currentMessage == null)
currentMessage = new MessagePart();
long pos = buffer.Position;
if (currentMessage.Build(buffer))
{
OnDataReceived(new DataReceivedEventArgs(currentMessage));
currentMessage = null;
ThreatBuffer();
}
}
#endregion
#region CallBack
private void ConnectionCallBack(IAsyncResult asyncResult)
{
Runing = true;
Socket client = (Socket)asyncResult.AsyncState;
client.EndConnect(asyncResult);
client.BeginReceive(receiveBuffer, 0, bufferLength, SocketFlags.None, new AsyncCallback(ReceiveCallBack), client);
OnConnected(new ConnectedEventArgs());
}
private void DisconectedCallBack(IAsyncResult asyncResult)
{
Runing = false;
Socket client = (Socket)asyncResult.AsyncState;
client.EndDisconnect(asyncResult);
OnDisconnected(new DisconnectedEventArgs());
}
private void ReceiveCallBack(IAsyncResult asyncResult)
{
Socket client = (Socket)asyncResult.AsyncState;
if (client.Connected == false)
{
Runing = false;
return;
}
if (Runing)
{
int bytesRead = 0;
bytesRead = client.EndReceive(asyncResult);
if (bytesRead == 0)
{
Runing = false;
OnDisconnected(new DisconnectedEventArgs());
return;
}
byte[] data = new byte[bytesRead];
Array.Copy(receiveBuffer, data, bytesRead);
buffer.Add(data, 0, data.Length);
ThreatBuffer();
client.BeginReceive(receiveBuffer, 0, bufferLength, SocketFlags.None, new AsyncCallback(ReceiveCallBack), client);
}
else
Console.WriteLine("Receive data but not running");
}
private void SendCallBack(IAsyncResult asyncResult)
{
if (Runing == true)
{
Socket client = (Socket)asyncResult.AsyncState;
client.EndSend(asyncResult);
OnDataSended(new DataSendedEventArgs(sendBuffer));
}
else
Console.WriteLine("Receive data but not runing !");
}
#endregion
#region Events
public event EventHandler<ConnectedEventArgs> Connected;
public event EventHandler<DisconnectedEventArgs> Disconnected;
public event EventHandler<DataReceivedEventArgs> DataReceived;
public event EventHandler<DataSendedEventArgs> DataSended;
private void OnConnected(ConnectedEventArgs e)
{
if (Connected != null)
Connected(this, e);
}
private void OnDisconnected(DisconnectedEventArgs e)
{
if (Disconnected != null)
Disconnected(this, e);
}
private void OnDataReceived(DataReceivedEventArgs e)
{
if (DataReceived != null)
DataReceived(this, e);
}
private void OnDataSended(DataSendedEventArgs e)
{
if (DataSended != null)
DataSended(this, e);
}
#endregion
#region EventArgs
public class ConnectedEventArgs : EventArgs
{
}
public class DisconnectedEventArgs : EventArgs
{
}
public class DataSendedEventArgs : EventArgs
{
public byte[] Data { get; private set; }
public DataSendedEventArgs(byte[] data)
{
Data = data;
}
}
public class DataReceivedEventArgs : EventArgs
{
public MessagePart Data { get; private set; }
public DataReceivedEventArgs(MessagePart data)
{
Data = data;
}
}
#endregion
}
}
Vous remarquerez que j'ai ajouté une petite variable FullPacket contenant le buffer dans MessagePart.
Donc je tiens à préciser que lors de mes tests entre le Full Socket et MITM j'utilisais la même classe network; SimpleClient.
Explication :idea: :
Cliquez pour révéler
Cliquez pour masquer
void Server_DataReceived(object sender, SimpleClient.DataReceivedEventArgs e)
{
NetworkMessage Message = ProtocolManager.GetPacket(e.Data.Data, (int)e.Data.MessageId);;
Dispatcher.Dispatch(this, Message);
if (Message.SendMessage == true)
ClientNetwork.Send(e.Data.Data);
Console.WriteLine(string.Format("[SERVER] ID: {0}; NAME: {1}; SIZE: {2}", Message.ProtocolId.ToString(), Message.ToString().Split('.').Reverse().ToArray()[0], e.Data.Data.Length.ToString()));
}
Voici notre événement qui reçoit des datas envoyés par le serveur :geek: (MITM)
Et voici la même fonction mais cette fois-ci en Full Socket;
Cliquez pour révéler
Cliquez pour masquer
void Client_DataReceived(object sender, SimpleClient.DataReceivedEventArgs e)
{
try
{
int IndexTime = TimeCount.StartTime();
NetworkMessage message = ProtocolManager.GetPacket(e.Data.Data, (int)e.Data.MessageId);
Dispatcher.Dispatch(this, message);
long TimeElapsed = TimeCount.GetTime(IndexTime);
if (TimeElapsed > 500)
ConsoleLogger.Log(string.Format("Temps écoulé anormalement long pour le traitement d'un paquet ({0})", message.ToString().Split('.').Reverse().ToArray()[0]), ContainerTypeEnum.WARNING);
ConsoleLogger.Log(string.Format("[Received] ID : {0}; NAME : {1}; SIZE : {2}; (Done in {3} ms)", e.Data.MessageId, message.ToString().Split('.').Reverse().ToArray()[0], e.Data.Data.Length.ToString(), TimeElapsed.ToString()), ContainerTypeEnum.PAQUET);
}
catch (Exception ex)
{
ExceptionManager.ManageError(this, ex, ConsoleLogger, ChatLogger);
}
}
EDIT: Petite rectification donc désormais l'id fonctionne ainsi que le nom de la classe.
Dans la partie MITM en envoyant la variable Data au client; Impossible de lire au dela du Flux, ID: Correct, SIZE: Correct.
Et le client se frise
Cliquez pour révéler
Cliquez pour masquer
Loading Image
CEPENDANT, lorsque j'envoi la variable Full Packet càd le buffer en entier; Aucune Erreur ID: Incorrect, SIZE: Incorrect
Et la MAZETTE, le client se connecte.
Cliquez pour révéler
Cliquez pour masquer
Loading Image
Et biensur en Full Sock avec la variable 'Data' aucun souci avec le code que je vous ai envoyé plus haut;
Cliquez pour révéler
Cliquez pour masquer
Loading Image
Si quelqu'un peut m'expliquer le problème :(