1
\$\begingroup\$

I have difficulties when sometimes a game client sends a list of packet in the same buffer, where it is split before processing. The biggest problem is when any packets don't come complete. For example; all packets have the same size, of 1000 bytes, and then we receive a list of packets of only 2500 bytes. Say the third packet came incomplete, I have difficulty filling this incomplete packet. I'm not sure if the way I'm doing the split buffer are really correct.

I'm not sure if doing right way below is what I'm using.

public static async void ProcessarAsync(Client client, byte[] buffer) // process recv packets
{
    try{
        int cc = buffer[0];
        int id = BitConverter.ToInt16(buffer, 1);
        int length = BitConverter.ToInt32(buffer, 4);
        //VERIFY IF THE FIRST PACKET BELONG THE GAME
        if (client != null)
        {
            if (client.PrimeiroPacote)
            {
                if (id != SecureConfig.PrimeiroPacoteMap)
                {
                    if (client != null) client.Close();
                    return;
                }
            }
        }
        try
        {
            if (client != null)
            {
                client.delayCheck = DateTime.Now;
                //ANALISA O PACOTE E SEPARA CASO HAJA MAIS DE 1 PACOTE EM UM MESMO PACOTE
                //ANALISE THE PACKAGE AND SPLIT IF HAVE MORE THEN 1 PACKETS IN SAME PACKET
                if (buffer.Length > length || length > buffer.Length || length <= 0)//180
                {
                    //FAZ A SEPARAÇÃO DOS PACOTES
                    //MAKE THE PACKET SEPARATION
                    List<byte[]> datas = await SepararData.Separar(buffer,client);
                    bool fail = false;
                    bool sucess = false;
                    //Faz a junção dos pacotes ou envia para o handler
                    //Merge packets or send to handler
                    while (datas.Count > 0)
                    {
                        //VERIFICA SE O CLIENT FOI DISPENSADO
                        //VERIFY IF THE CLIENT WAS DISPOSED
                        if (client == null || client != null && client.Dispensado) break;
                        
                        //PACOTE COMPLETO (OU AGUARDANDO PARA SER COMPELTADO)
                        // PACKET FULL ( OR WAITING TO BE COMPLETED)
                        byte[] maindata = null;
                        
                        //PROCESSO DE JUNTAR OS PACOTES CASO NÃO ESTEJA COMPLETO
                        //PROCESS OF UNITS THE PACKETS IF NOT COMPLET
                        if (client.packetListEncrypted.Count > 0)
                        {
                            //PEGA O PRIMEIRO PACOTE ARMAZENADO PARA SER PROCESSADO
                            //GET THE FIRST PACKET STORED TO BE PROCESSED
                            byte[] data = (byte[])client.packetListEncrypted.Dequeue();
                            if (data == null)
                            {
                                continue;
                            }
                            //PEGA O TAMANHO DO PACOTE QUANDO EXISTE
                            //GET THE LENGTH OF THE PACKET WHEN EXIST
                            length = BitConverter.ToInt32(data, 4);
                            if (length <= 0)
                            {
                                fail = true;
                                break;
                            }
                            
                            //ENQUANTO O TAMANHO DESSE TRECHO DE PACOTE FOR MENOR QUE O TAMANHO TOTAL
                            //WHILE THE SIZE OF THIS PACKAGE SECTION IS LESS THAN THE TOTAL SIZE
                            while (data.Length < length)
                            {
                                //VERIFICA SE O CLIENT FOI DISPENSADO
                                //VERIFY IF THE CLIENT WAS DISPOSED
                                if (client == null || client != null && client.Dispensado) break;
                                
                                //VERIFICA SE EXISTE PARTES SEPARADAS
                                //VERIFY IF EXIST PARTS SEPARATE
                                if (datas.Count > 0)
                                {
                                    //ADICIONA A DADO AO PACOTE PRINCIPAL
                                    //ADD DATA TO MAIN PACKAGE
                                    byte[] maindata2 = datas[0];
                                    datas.RemoveAt(0);
                                    Array.Resize(ref data, data.Length + maindata2.Length);
                                    Buffer.BlockCopy(maindata2, 0, data, ((data.Length - maindata2.Length)), maindata2.Length);
                                }
                                else
                                {
                                    //DEVOLVE O TRECHO PARA A LISTA
                                    //RETURN THE SECTION TO THE LIST
                                    fail = true;
                                    client.packetListEncrypted.Enqueue(data);
                                    break;
                                }
                            }
                            //CASO O TAMANHO SEJA EQUIVALENTE
                            // IF SIZE IS EQUIVALENT
                            if (data.Length == length)
                            {
                                //PACOTE "COMPLETO"
                                //COMPLETE PACKAGE"
                                sucess = true;
                                maindata = data;
                            }
                            else if(data.Length < length)
                            {
                                //VERIFICA SE ESSE TRECHO JÁ SE ENCONTRA NA LISTA
                                //CASO NÃO ESTIVER, ADICIONAR
                                // CHECK IF THIS SECTION IS ALREADY IN THE LIST
                                // IF NOT, ADD
                                if (!client.packetListEncrypted.Contains(data))
                                    client.packetListEncrypted.Enqueue(data);
                                fail = true;
                            }
                        }

                        //CASO AINDA TENHA TRECHOS AGUARDANDO (TENTA EXTRAIR OS TRECHOS NOVAMENTE)
                        // IF STILL HAVE A SECTION WAITING (TRY TO EXTRACT THE SECTIONS AGAIN)
                        if (datas.Count > 0)
                        {
                            //E O PACOTE AINDA NÃO SE ENCONTRA COMPLETO
                            //AND THE PACKAGE IS NOT YET COMPLETE
                            if (!sucess)
                            {
                                //PEGA O PRIMEIRO PACOTE DA LISTA
                                //GET THE FIRST PACKAGE FROM THE LIST
                                maindata = datas[0];
                                datas.RemoveAt(0);
                                
                                //PEGA O TAMANHO DO PACOTE QUANDO EXISTE
                                //GET THE SIZE OF PACKET WHEN EXIST
                                length = BitConverter.ToInt32(maindata, 4);
                                
                                //ENQUANTO O TAMANHO DESSE TRECHO DE PACOTE FOR MENOR QUE O TAMANHO TOTAL
                                //WHILE THE SIZE OF THIS PACKAGE SECTION IS LESS THAN THE TOTAL SIZE
                                while (maindata.Length < length)
                                {
                                    //VERIFICA SE O CLIENT FOI DISPENSADO
                                    //VERIFY IF THE CLIENT WAS DISPOSED
                                    if (client == null || client != null && client.Dispensado) break;
                                    
                                    //LOOP VERIFICANDO SE HÁ MAIS PARTES SEPARADAS
                                    // LOOP CHECKING IF THERE ARE MORE SEPARATE PARTS
                                    while (datas.Count > 0)
                                    {
                                        //VERIFICA SE O CLIENT FOI DISPENSADO
                                        //VERIFY IF THE CLIENT WAS DISPOSED
                                        if (client == null || client != null && client.Dispensado) break;
                                        
                                        //ADICIONA A DADO AO PACOTE PRINCIPAL
                                        //ADD DATA TO MAIN PACKAGE
                                        byte[] maindata2 = datas[0];
                                        datas.RemoveAt(0);
                                        Array.Resize(ref maindata, maindata.Length + maindata2.Length);
                                        Buffer.BlockCopy(maindata2, 0, maindata, ((maindata.Length - maindata2.Length)), maindata2.Length);
                                    }
                                    
                                    //DEFINE O TAMANHO DO PACOTE PRINCIPAL
                                    //DEFINE THE SIZE OF MAIN PACKAGE
                                    length = BitConverter.ToInt32(maindata, 4);
                                    
                                    //CASO O TAMANHO NÃO SEJA IGUAL AO PACOTE PRINCIPAL
                                    // IF THE SIZE IS NOT EQUAL TO THE MAIN PACKAGE
                                    if (maindata.Length < length || length < 0)
                                    {
                                        //VERIFICA SE ESSE TRECHO JÁ SE ENCONTRA NA LISTA
                                        //CASO NÃO ESTIVER, ADICIONAR
                                        // CHECK IF THIS SECTION IS ALREADY IN THE LIST
                                        // IF NOT, ADD
                                        if (!client.packetListEncrypted.Contains(maindata))
                                            client.packetListEncrypted.Enqueue(maindata);
                                        fail = true;
                                        break;
                                    }
                                }
                                
                                //VERIFICA SE ESSE TRECHO HÁ ALGUM DADO PARA RETORNA-LO PARA A LISTA
                                // CHECK IF THERE IS ANY DATA IN THIS SECTION TO RETURN IT TO THE LIST
                                if (length <= 0)
                                {
                                    //VERIFICA SE ESSE TRECHO JÁ SE ENCONTRA NA LISTA
                                    //CASO NÃO ESTIVER, ADICIONAR
                                    // CHECK IF THIS SECTION IS ALREADY IN THE LIST
                                    // IF NOT, ADD
                                    if (!client.packetListEncrypted.Contains(maindata))
                                        client.packetListEncrypted.Enqueue(maindata);
                                    fail = true;
                                    break;
                                }
                            }
                        }
                        
                        //NÃO FOI POSSÍVEL RECUPERAR O PACOTE
                        // IT WASN'T POSSIBLE TO RECOVER THE PACKAGE
                        if (fail)
                        {
                            break;
                        }
                        
                        //NÃO FOI POSSÍVEL RECUPERAR O PACOTE
                        // IT WASN'T POSSIBLE TO RECOVER THE PACKAGE
                        if (maindata == null) break;
                        
                        //O PACOTE FOI RECEBIDO COM SUCESSO
                        // THE PACKAGE WAS SUCCESSFULLY RECEIVED
                        
                        //PARTE DE DECRIPTAR O PACOTE CASO ESTEJA HABILITADO
                        // PART OF DECRIPTING THE PACKAGE IF IT IS ENABLED
                        if (Server.AtivarEncriptacao && client.AtivarEncriptacao)
                        {
                            
                            Crypto crypto = new Crypto();
                            Int32 packetSize = BitConverter.ToInt32(maindata, 0x04);
                            if (packetSize <= 0) packetSize = maindata.Length;
                            if (maindata.Length < packetSize)
                            {
                                Array.Resize(ref maindata, packetSize);
                            }
                            else if (maindata.Length > packetSize)
                            {
                                Array.Resize(ref maindata, packetSize);
                            }
                            byte[] csSucks = new byte[packetSize - 8];
                            Array.Copy(maindata, 8, csSucks, 0, packetSize - 8);
                            crypto.crypto(ref csSucks, packetSize - 8, 1);
                            Array.Copy(csSucks, 0, maindata, 8, packetSize - 8);
                            //Log.SalvarF(client, "Bugs_Map", "ULTIMO RECEBIDO NaO SEPARADO", "DEPOIS DECRYPT:\n" + Digimon_Battle_Online.Packets.Packet.Visualize(buffer, true), true);
                        }
                        
                        //ENVIA PARA A LISTA DE PACOTES PARA SER PROCESSADO
                        // SEND TO PACKAGE LIST TO BE PROCESSED
                        client.packetListRecv.Enqueue(maindata);
                    }
                    
                    //LIMPA A LISTA DE PACOTES, JÁ FOI ARMAZENADO EM OUTRO OBJETO EM UMA OUTRA LISTA
                    // CLEAR THE PACKAGE LIST, IT HAS ALREADY BEEN STORED IN ANOTHER OBJECT IN ANOTHER LIST
                    for (int i = 0; i < datas.Count; i++)
                    {
                        datas[i] = null;
                    }
                    datas.Clear();
                }
                //CASO O TAMANHO DO PACOTE SEJA IGUAL E TEM A HEADER DO JOGO    
                // IF THE PACKAGE SIZE IS EQUAL AND HAS THE GAME HEADER
                else if (cc == 0xCC)                
                {
                    //PARTE DE DECRIPTAR O PACOTE CASO ESTEJA HABILITADO
                    // PART OF DECRIPTING THE PACKAGE IF IT IS ENABLED
                    if (Server.AtivarEncriptacao && client.AtivarEncriptacao)
                    {
                        Crypto crypto = new Crypto();
                        Int32 packetSize = BitConverter.ToInt32(buffer, 0x04);
                        if (packetSize <= 0) packetSize = buffer.Length;
                        if (buffer.Length < packetSize)
                        {
                            Array.Resize(ref buffer, packetSize);
                        }
                        else if (buffer.Length > packetSize)
                        {
                            Array.Resize(ref buffer, packetSize);
                        }
                        byte[] csSucks = new byte[packetSize - 8];
                        Array.Copy(buffer, 8, csSucks, 0, packetSize - 8);
                        crypto.crypto(ref csSucks, packetSize - 8, 1);
                        Array.Copy(csSucks, 0, buffer, 8, packetSize - 8);
                    }
                    
                    //ENVIA PARA A LISTA DE PACOTES PARA SER PROCESSADO
                    // SEND TO PACKAGE LIST TO BE PROCESSED
                    client.packetListRecv.Enqueue(buffer);
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Erro ao processar pacote Map: {0}", ex);
            if (client.Login.Length > 0)
            {
                Log.Salvar(client, "Map", "Processar Pacote", string.Format("login: {0} erro ao processar pacote! {1}", client.Login, ex), false);
                Log.Salvar(client, "Map", "Processar Pacote", Packet.Visualize(buffer, false), false);
            }
            else
            {
                Log.Salvar(client, "Map", "Processar Pacote", Packet.Visualize(buffer, false), false);
            }
            client.Close();
            //Handler(client, buffer);
        }
    }
    
    catch (Exception e)
    {
        Console.WriteLine("Erro ProcessarAsync " + e.Message);
    }
}

using Common.Entity.Clients;
using Common.Network.Packet;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Common.Utils
{
    public class SepararData
    {
        public static Task<List<byte[]>> Separar(byte[] data, Client client)
        {
            var t = Task.Run(() =>
            {
                bool encontrado = false;
                bool fail = false;
                List<byte[]> lista = new List<byte[]>();
                //try
                //{
                int index = data[0];
                int header = data[1];
                int tamanho = BitConverter.ToInt32(data, 4);
                int otamanho = tamanho;
                if (tamanho == data.Length)
                {
                    lista.Add(data);
                    return lista;
                }

                PacketLog.Write(client, "Recv", data[1].ToString("X2") + "[" + (int)data[1] + "]", Packet.Visualize(data, false), client.Tamer != null && client.Tamer.Nome.Length > 0 ? true : false);
                // await Log.SalvarPacoteTamanhoAsync("PACKET-H-" + header + "-L-" + tamanho, Packet.Visualize(data, true));

                for (int i = 0; i < data.Length; i += tamanho)
                {
                    encontrado = false;
                    if (i >= data.Length)
                    {
                        //Console.WriteLine("DATA INVALIDA HEADER: {0} LENGHT: {1}", data[0], otamanho);
                        break;//ativar dps
                    }
                    if (i+1 >= data.Length)
                    {
                        //Console.WriteLine("DATA INVALIDA HEADER: {0} LENGHT: {1}", data[0], otamanho);
                        break;//ativar dps
                    }
                    if (i + 4 >= data.Length)
                    {
                        //Console.WriteLine("DATA INVALIDA HEADER: {0} LENGHT: {1}", data[1], otamanho);
                        break;//ativar dps
                    }
                    if (i + 8 >= data.Length)
                    {
                        //Console.WriteLine("DATA INVALIDA HEADER: {0} LENGHT: {1}", data[1], otamanho);
                        break;//ativar dps
                    }
                    index = data[i];
                    header = data[i + 1];
                    tamanho = BitConverter.ToInt32(data, i+4);
                   
                    if (tamanho <= 0)
                    {
                        //Console.WriteLine("DATA INVALIDA HEADER T<0: {0} LENGHT: {1}", data[i + 1], tamanho);
                        tamanho = data.Length - i;
                        fail = true;
                    }

                    if (tamanho >= data.Length)
                    {
                        //Console.WriteLine("DATA INVALIDA HEADER T>D: {0} LENGHT: {1}", data[i + 1], tamanho);
                        tamanho = data.Length - i;
                        fail = true;
                        //break;
                    }

                    //header = BitConverter.ToInt16(data, 1);
                    if (i + tamanho > data.Length)
                    {
                        //Console.WriteLine("DATA INVALIDA HEADER I>T: {2}: {0} LENGHT: {1}", data[i + 1], tamanho, nome);
                        tamanho = data.Length - i;
                        fail = true;
                        //break;
                        //continue;
                    }
                    if (index > 0)
                    {
                        //Console.WriteLine("DATA INVALIDA HEADER INDEX!=0xCC: {2}: {0} LENGHT: {1}", header, tamanho, nome);
                    }

                    if (!fail && header <= 255 && header >= 0)
                    {
                        encontrado = true;
                        if (tamanho >= 8)
                        {
                            byte[] b = new byte[tamanho];
                            Buffer.BlockCopy(data, i, b, 0, tamanho);
                            lista.Add(b);
                        }
                    }
                    //if (!encontrado && fail)
                    //{
                    //    /*byte[] b = new byte[tamanho];
                    //    Buffer.BlockCopy(data, i, b, 0, tamanho);
                    //    lista.Add(b);*/

                    //    byte[] b = new byte[data.Length];
                    //    Buffer.BlockCopy(data, 0, b, 0, data.Length);
                    //    lista.Add(b);
                    //}
                    else if(!encontrado&&fail)
                    {
                        List<int> remove = new List<int>();
                        List<int> zeros = new List<int>();
                        for(int z=data.Length-1;z>0;z--)
                        {
                            if ((z - 3) < 0) break;
                            if (data[z] == 0x00 &&
                             data[z - 1] == 0x00 &&
                             data[z - 2] == 0x00 &&
                             data[z - 3] == 0x00)
                            {
                                z -= 3;
                                zeros.Add(z);
                            }
                        }
                        if (zeros.Count > 0)
                        {

                        }
                        int lastZero = -1;
                        int count = 0;
                        bool retirar = false;
                        foreach (int b in zeros)
                        {
                            if (lastZero == -1) lastZero = b;
                            else if (lastZero - 4 == b)
                            {
                                lastZero = b;
                                count++;
                            }
                            else
                            {
                                remove.Add(b);
                            }
                        }
                        foreach (int b in remove)
                        {
                            zeros.Remove(b);
                        }
                        if (count >= 4) retirar = true;
                        if (retirar && zeros.Count > 0)
                        {
                            Array.Resize(ref data, data.Length - zeros[zeros.Count-1]);

                            remove.Clear();
                            zeros.Clear();
                            remove = null;
                            zeros = null;
                        }
                        
                        lista.Add(data);
                        break;
                    }
                    //}
                    //catch { break; }
                }
                //Console.WriteLine("Tamanho Max:{0}", lista.Count);
                return lista;
            });
            return t;
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ i hate that's winsock does packets fragmentation \$\endgroup\$ – Johnny Camargo Jun 17 at 19:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.