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