#include #include #include "pso/forward.h" #include "pso/macros.h" #include "pso/TMainTask.h" #include "pso/TMenuList.h" #include "pso/TPlyCharData.h" #include "pso/TPlyDispData.h" #include "pso/TPlyInventory.h" #include "pso/TObject.h" #include "pso/TProtocol.h" #include "pso/TSocket.h" OBJECT_NAME(TProtocol); packet *server_packet = nullptr; TPlyMeetUserExtension meet_user_settings; void copy_packet(struct packet *pkt) { } void TProtocol::recv_start_game(packet &pkt) { int lobby_entry_idx; TPlyStartGame tmp = as(TPlyStartGame &, pkt); tmp.bswap(); meet_user_settings = tmp.extension; lobby_entry_idx = -1; for (int i = 0; i < tmp.header.flags && i < 4; ++i) { if (tmp.lobby_data[i].tag == m_guildcard_tag) { lobby_entry_idx = i; } } // Failed to find our guildcard tag, go into an infinite loop. if (lobby_entry_idx == -1) { for (;;) {} } else { m_joined_game = true; if (m_recv_handlers.handle_0E_recv_start_game != nullptr) { m_recv_handlers.handle_0E_recv_start_game(tmp.lobby_data, tmp.header.flags, lobby_entry_idx); } } }; void TProtocol::recv_info_list(packet &pkt) { typedef TMenuList info_list; info_list tmp = as(info_list &, pkt); tmp.bswap(); m_entry_count = tmp.header.flags; for (int i = 0; i < m_entry_count; ++i) { m_game_entries[i] = tmp.entries[i]; } if (m_recv_handlers.handle_1F_recv_info_list != nullptr) { m_recv_handlers.handle_1F_recv_info_list(m_entry_count, m_game_entries, tmp.pad_entries[0]); } }; void TProtocol::recv_game_list(packet &pkt) { typedef TMenuList game_list; game_list tmp = as(game_list &, pkt); tmp.bswap(); m_entry_count = tmp.header.flags; for (int i = 0; i < m_entry_count; ++i) { m_game_entries[i] = tmp.entries[i]; } if (m_recv_handlers.handle_08_recv_game_list != nullptr) { m_recv_handlers.handle_08_recv_game_list(m_entry_count, m_game_entries, tmp.pad_entries[0]); } }; void TProtocol::recv_dir_list(packet &pkt) { typedef TMenuList dir_list; dir_list tmp = as(dir_list &, pkt); tmp.bswap(); m_entry_count = tmp.header.flags; for (int i = 0; i < m_entry_count; ++i) { m_game_entries[i] = tmp.entries[i]; } if (m_recv_handlers.handle_07_A0_A1_recv_dir_list != nullptr) { m_recv_handlers.handle_07_A0_A1_recv_dir_list(m_entry_count, m_game_entries, tmp.pad_entries[0]); } }; void TProtocol::recv_chat(packet &pkt) { TMessageBox tmp = as(TMessageBox &, pkt); tmp.bswap(); if (m_recv_handlers.handle_06_recv_chat != nullptr) { m_recv_handlers.handle_06_recv_chat(tmp.tag, tmp.mesg); } }; void TProtocol::recv_logout(packet &pkt) { close(); m_is_encrypted = false; m_connected = false; m_packet_offset = 0; m_packet_size = 0; if (m_recv_handlers.handle_05_recv_logout != nullptr) { m_recv_handlers.handle_05_recv_logout(); } }; void TProtocol::recv_login(packet &pkt) { TPlyRecvLogin tmp = as(TPlyRecvLogin &, pkt); tmp.bswap(); if (!tmp.header.flags) { m_guildcard_tag = tmp.tag; m_client_config = tmp.client_config; m_connected = true; } if (m_recv_handlers.handle_04_recv_login != nullptr) { m_recv_handlers.handle_04_recv_login(tmp.header.flags); } }; void TProtocol::recv_regist(packet &pkt) { packet_header tmp = pkt.pkt.header; tmp.bswap(); m_login_response_state = tmp.flags; if (m_recv_handlers.handle_03_recv_regist != nullptr) { m_recv_handlers.handle_03_recv_regist(tmp.flags); } }; void TProtocol::recv_text(packet &pkt) { TPlyText<1024> tmp = as(TPlyText<1024> &, pkt); if (m_recv_handlers.handle_1A_D5_recv_text != nullptr) { m_recv_handlers.handle_1A_D5_recv_text(tmp.text); } }; void TProtocol::recv_error(packet &pkt) { TMessageBox tmp = as(TMessageBox &, pkt); tmp.bswap(); if (m_recv_handlers.handle_01_recv_error != nullptr) { m_recv_handlers.handle_01_recv_error(tmp.mesg); } }; int TProtocol::handle_command(struct packet *pkt) { static const command_handler_entry handlers[] = { { 0x01, &recv_error }, { 0x03, &recv_regist }, { 0x04, &recv_login }, { 0x05, &recv_logout }, { 0x06, &recv_chat }, { 0x07, &recv_dir_list }, { 0x08, &recv_game_list }, { 0x0E, &recv_start_game }, { 0x1F, &recv_info_list }, { 0x1A, &recv_text }, { 0xA0, &recv_dir_list }, { 0xA1, &recv_dir_list }, { 0xD5, &recv_text }, { 0, nullptr } }; for (int i = 0; !handlers[i].command; ++i) { if (pkt->pkt.header.command == handlers[i].command) { (this->*handlers[i].handler)(*pkt); return 0; } } m_is_invalid_packet = true; return 1; } void TProtocol::parse_packet() { // This is needed to match, either that or cast the sizeof to an int. const int max_packet_size = sizeof(struct packet); while (!is_empty()) { m_packet.bytes[m_packet_offset++] = next(); if (m_packet_offset == sizeof(packet_header)) { if (m_is_encrypted) { m_recv_crypt.encrypt(&m_packet.pkt.header, sizeof(packet_header)); } } // NOTE: The `const int &` is required here to match. // Convert packet size to native endian. const int &packet_size = m_packet_size = to_be_uint16_t(m_packet.pkt.header.size); // Is the packet size invalid? if (packet_size > max_packet_size || !packet_size) { m_packet_size = 0; m_packet_offset = 0; m_is_invalid_packet = true; break; // Do we have the rest of the packet yet? } else if (m_packet_size > 0 && m_packet_offset >= m_packet_size) { // Decrypt it if necessary. if (m_is_encrypted) { m_recv_crypt.encrypt(&m_packet.pkt.data, m_packet_size-sizeof(packet_header)); } struct packet *pkt = &m_packet; m_packet_size = 0; m_packet_offset = 0; if (m_handle_pings_only) { if (pkt->pkt.header.command == 0x1d) { if (!handle_command(pkt)) { continue; } else { break; } } else { copy_packet(pkt); } } else if (handle_command(pkt)) { break; } } } } short TProtocol::send(u8 *data, size_t size) { const short ret = TTcpSocket::send(data, size); return ret; } void TProtocol::run_task() { TTcpSocket::some_stub(); some_stub(); if (m_is_invalid_packet) { close(); m_is_encrypted = 0; m_connected = 0; m_packet_offset = 0; m_packet_size = 0; } else if (!m_buffer_cleared) { server_packet = &m_packet; parse_packet(); recv(); } } void TProtocol::some_stub() {} TProtocol::~TProtocol() { } #define fill_with(name, value) memset(&m_##name, value, sizeof(m_##name)) #define copy(name) strncpy(m_##name, name, sizeof(m_##name)) TProtocol::TProtocol(TObject *parent, u16 sub_version, int language, char *serial_number, char *access_key, char *password) : TTcpSocket(parent) { u8 thing[6]; m_name = TProtocol_name; memset(thing, 0, sizeof(thing)); { int i = 0; int j = 0; m_smth.m_smth[i++] = 0; m_smth.m_smth[i++] = 0; m_smth.m_smth[i++] = thing[j++]; m_smth.m_smth[i++] = thing[j++]; i = 0; m_smth.m_smth1[i++] = thing[j++]; m_smth.m_smth1[i++] = thing[j++]; m_smth.m_smth1[i++] = thing[j++]; m_smth.m_smth1[i++] = thing[j++]; } m_guildcard_tag = TPlyGuildCardTag(-1, -1); m_login_response_state = 0; m_connected = 0; m_joined_game = 0; m_has_meet_user_settings = 0; m_handle_pings_only = false; m_entry_count = 0; m_unused = 0; m_lobby_list_count = 0; m_unused5[0] = 0; m_unused2 = 0; m_udp_disabled = 0; m_packet_offset = 0; m_packet_size = 0; m_sub_version = sub_version; m_language = language; fill_with(serial_number, 0); fill_with(access_key, 0); fill_with(password, 0); copy(serial_number); copy(access_key); copy(password); fill_with(client_config, 0); m_recv_handlers.handle_unused_login = nullptr; m_recv_handlers.handle_03_recv_regist = nullptr; m_recv_handlers.handle_04_recv_login = nullptr; m_recv_handlers.handle_05_recv_logout = nullptr; m_recv_handlers.handle_07_A0_A1_recv_dir_list = nullptr; m_recv_handlers.handle_01_recv_error = nullptr; m_recv_handlers.handle_06_recv_chat = nullptr; m_recv_handlers.handle_11_additional_info_reply_packet = nullptr; m_recv_handlers.handle_0E_recv_start_game = nullptr; m_recv_handlers.unused7 = nullptr; m_recv_handlers.handle_64_join_game_packet = nullptr; m_recv_handlers.unused8 = nullptr; m_recv_handlers.handle_67_join_lobby_packet = nullptr; m_recv_handlers.handle_13_quest_data_packet = nullptr; m_recv_handlers.handle_80_unused_ignored_packet = nullptr; m_recv_handlers.unused9 = nullptr; m_recv_handlers.handle_65_add_player_to_game_packet = nullptr; m_recv_handlers.handle_66_player_left_game_packet = nullptr; m_recv_handlers.handle_68_add_player_to_lobby_packet = nullptr; m_recv_handlers.handle_69_player_left_lobby_packet = nullptr; m_recv_handlers.handle_92_9C_register_response_packet = nullptr; m_recv_handlers.unused10 = nullptr; m_recv_handlers.handle_81_simple_mail_packet = nullptr; m_recv_handlers.handle_41_guild_card_search_reply_packet = nullptr; m_recv_handlers.handle_A2_quest_list_packet = nullptr; m_recv_handlers.handle_A3_quest_info_packet = nullptr; m_recv_handlers.handle_44_quest_file_list_packet = nullptr; m_recv_handlers.handle_13_quest_data_packet = nullptr; m_recv_handlers.handle_A4_downloadable_quest_menu_packet = nullptr; m_recv_handlers.handle_A5_downloadable_quest_info_packet = nullptr; m_recv_handlers.unused11 = nullptr; m_recv_handlers.handle_97_checksum_reply_packet = nullptr; m_recv_handlers.handle_B0_server_message_packet = nullptr; m_recv_handlers.handle_1F_recv_info_list = nullptr; m_recv_handlers.handle_88_player_arrow_color_list_packet = nullptr; m_recv_handlers.handle_8A_lobby_name_packet = nullptr; m_recv_handlers.handle_C5_player_challenge_data_packet = nullptr; m_recv_handlers.handle_D3_execute_trade_packet = nullptr; m_recv_handlers.handle_D4_trade_result_packet = nullptr; m_recv_handlers.handle_D1_advance_trade_state_packet = nullptr; m_recv_handlers.handle_D8_infoboard_packet = nullptr; m_recv_handlers.handle_DA_lobby_event_packet = nullptr; m_recv_handlers.handle_AB_quest_stats_response_packet = nullptr; } #undef fill_with #undef copy