Exemple #1
0
int32 send_parse(int8 *buff, size_t* buffsize, sockaddr_in* from, map_session_data_t* map_session_data)
{
    // Модификация заголовка исходящего пакета
    // Суть преобразований:
    //  - отправить клиенту номер последнего полученного от него пакета
    //  - присвоить исходящему пакету номер последнего отправленного клиенту пакета +1
    //  - записать текущее время отправки пакета

    WBUFW(buff, 0) = map_session_data->server_packet_id;
    WBUFW(buff, 2) = map_session_data->client_packet_id;

    // сохранение текущего времени (32 BIT!)
    WBUFL(buff, 8) = (uint32)time(nullptr);

    // собираем большой пакет, состоящий из нескольких маленьких
    CCharEntity *PChar = map_session_data->PChar;
    CBasicPacket* PSmallPacket;
    uint32 PacketSize = UINT32_MAX;
    uint32 PacketCount = PChar->getPacketCount();
    uint8 packets = 0;

    while (PacketSize > 1300 - FFXI_HEADER_SIZE - 16) //max size for client to accept
    {
        *buffsize = FFXI_HEADER_SIZE;
        PacketList_t packetList = PChar->getPacketList();
        packets = 0;

        while (!packetList.empty() && *buffsize + packetList.front()->length() < map_config.buffer_size &&
            packets < PacketCount)
        {
            PSmallPacket = packetList.front();

            PSmallPacket->sequence(map_session_data->server_packet_id);
            memcpy(buff + *buffsize, *PSmallPacket, PSmallPacket->length());

            *buffsize += PSmallPacket->length();
            packetList.pop_front();
            packets++;
        }
        //Сжимаем данные без учета заголовка
        //Возвращаемый размер в 8 раз больше реальных данных
        PacketSize = zlib_compress(buff + FFXI_HEADER_SIZE, *buffsize - FFXI_HEADER_SIZE, PTempBuff, *buffsize, zlib_compress_table);
        WBUFL(PTempBuff, (PacketSize + 7) / 8) = PacketSize;

        PacketSize = (PacketSize + 7) / 8 + 4;

        PacketCount /= 2;
    }
    PChar->erasePackets(packets);

    //Запись размера данных без учета заголовка
    uint8 hash[16];
    md5((uint8*)PTempBuff, hash, PacketSize);
    memcpy(PTempBuff + PacketSize, hash, 16);
    PacketSize += 16;

    if (PacketSize > map_config.buffer_size + 20)
    {
        ShowFatalError(CL_RED"%Memory manager: PTempBuff is overflowed (%u)\n" CL_RESET, PacketSize);
    }

    //making total packet
    memcpy(buff + FFXI_HEADER_SIZE, PTempBuff, PacketSize);

    uint32 CypherSize = (PacketSize / 4)&-2;

    blowfish_t* pbfkey = &map_session_data->blowfish;

    for (uint32 j = 0; j < CypherSize; j += 2)
    {
        blowfish_encipher((uint32*)(buff)+j + 7, (uint32*)(buff)+j + 8, pbfkey->P, pbfkey->S[0]);
    }

    // контролируем размер отправляемого пакета. в случае,
    // если его размер превышает 1400 байт (размер данных + 42 байта IP заголовок),
    // то клиент игнорирует пакет и возвращает сообщение о его потере

    // в случае возникновения подобной ситуации выводим предупреждующее сообщение и
    // уменьшаем размер BuffMaxSize с шагом в 4 байта до ее устранения (вручную)

    *buffsize = PacketSize + FFXI_HEADER_SIZE;

    return 0;
}