handle out-of-order quest downloads on proxy server

This commit is contained in:
Martin Michelsen
2024-09-17 21:56:13 -07:00
parent 79eabe5ed2
commit e6e11794b8
3 changed files with 28 additions and 23 deletions
+23 -18
View File
@@ -1318,7 +1318,7 @@ constexpr on_command_t S_PG_44_A6 = &S_44_A6<S_OpenFile_PC_GC_44_A6>;
constexpr on_command_t S_X_44_A6 = &S_44_A6<S_OpenFile_XB_44_A6>; constexpr on_command_t S_X_44_A6 = &S_44_A6<S_OpenFile_XB_44_A6>;
constexpr on_command_t S_B_44_A6 = &S_44_A6<S_OpenFile_BB_44_A6>; constexpr on_command_t S_B_44_A6 = &S_44_A6<S_OpenFile_BB_44_A6>;
static HandlerResult S_13_A7(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t, string& data) { static HandlerResult S_13_A7(shared_ptr<ProxyServer::LinkedSession> ses, uint16_t, uint32_t flag, string& data) {
auto& cmd = check_size_t<S_WriteFile_13_A7>(data); auto& cmd = check_size_t<S_WriteFile_13_A7>(data);
bool modified = false; bool modified = false;
@@ -1331,36 +1331,41 @@ static HandlerResult S_13_A7(shared_ptr<ProxyServer::LinkedSession> ses, uint16_
return HandlerResult::Type::FORWARD; return HandlerResult::Type::FORWARD;
} }
if (cmd.data_size > sf->remaining_bytes) { bool is_last_block = (cmd.data_size != 0x400);
ses->log.warning("Chunk size extends beyond original file size; truncating file"); size_t block_offset = flag * 0x400;
cmd.data_size = sf->remaining_bytes; size_t allowed_block_size = (block_offset < sf->total_size)
modified = true; ? min<size_t>(sf->total_size - block_offset, 0x400)
} else if (cmd.data_size > 0x400) { : 0;
ses->log.warning("Chunk data size is invalid; truncating to 0x400");
cmd.data_size = 0x400; if (cmd.data_size > allowed_block_size) {
ses->log.warning("Block size extends beyond allowed size; truncating block");
cmd.data_size = allowed_block_size;
modified = true; modified = true;
} }
if (!sf->output_filename.empty()) { if (!sf->output_filename.empty()) {
ses->log.info("Adding %" PRIu32 " bytes to %s => %s", ses->log.info("Adding %" PRIu32 " bytes to %s:%02" PRIX32 " => %s:%zX",
cmd.data_size.load(), sf->basename.c_str(), sf->output_filename.c_str()); cmd.data_size.load(), sf->basename.c_str(), flag, sf->output_filename.c_str(), block_offset);
if (ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) { if (ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) {
sf->blocks.emplace_back(reinterpret_cast<const char*>(cmd.data.data()), cmd.data_size); size_t block_end_offset = block_offset + cmd.data_size;
if (sf->data.size() < block_end_offset) {
sf->data.resize(block_end_offset);
}
memcpy(sf->data.data() + block_offset, reinterpret_cast<const char*>(cmd.data.data()), cmd.data_size);
} }
} }
sf->remaining_bytes -= cmd.data_size;
if (sf->remaining_bytes == 0) { if (is_last_block) {
if (ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) { if (ses->config.check_flag(Client::Flag::PROXY_SAVE_FILES)) {
ses->log.info("Writing file %s => %s", sf->basename.c_str(), sf->output_filename.c_str()); ses->log.info("Writing file %s => %s", sf->basename.c_str(), sf->output_filename.c_str());
string data = phosg::join(sf->blocks);
if (sf->is_download && (phosg::ends_with(sf->basename, ".bin") || phosg::ends_with(sf->basename, ".dat") || phosg::ends_with(sf->basename, ".pvr"))) { if (sf->is_download && (phosg::ends_with(sf->basename, ".bin") || phosg::ends_with(sf->basename, ".dat") || phosg::ends_with(sf->basename, ".pvr"))) {
data = decode_dlq_data(data); sf->data = decode_dlq_data(sf->data);
} }
phosg::save_file(sf->output_filename, data); phosg::save_file(sf->output_filename, sf->data);
if (phosg::ends_with(sf->basename, ".bin")) { if (phosg::ends_with(sf->basename, ".bin")) {
try { try {
string decompressed = prs_decompress(data); string decompressed = prs_decompress(sf->data);
auto disassembly = disassemble_quest_script(decompressed.data(), decompressed.size(), ses->version(), ses->language(), false); auto disassembly = disassemble_quest_script(decompressed.data(), decompressed.size(), ses->version(), ses->language(), false);
phosg::save_file(sf->output_filename + ".txt", disassembly); phosg::save_file(sf->output_filename + ".txt", disassembly);
} catch (const exception& e) { } catch (const exception& e) {
@@ -1372,7 +1377,7 @@ static HandlerResult S_13_A7(shared_ptr<ProxyServer::LinkedSession> ses, uint16_
} }
if (!sf->is_download && phosg::ends_with(sf->basename, ".dat")) { if (!sf->is_download && phosg::ends_with(sf->basename, ".dat")) {
auto quest_dat_data = make_shared<std::string>(phosg::join(sf->blocks)); auto quest_dat_data = make_shared<std::string>(prs_decompress(sf->data));
try { try {
ses->map = Lobby::load_maps( ses->map = Lobby::load_maps(
ses->version(), ses->version(),
+2 -2
View File
@@ -708,12 +708,12 @@ void ProxyServer::LinkedSession::update_channel_names() {
ProxyServer::LinkedSession::SavingFile::SavingFile( ProxyServer::LinkedSession::SavingFile::SavingFile(
const string& basename, const string& basename,
const string& output_filename, const string& output_filename,
size_t remaining_bytes, size_t total_size,
bool is_download) bool is_download)
: basename(basename), : basename(basename),
output_filename(output_filename), output_filename(output_filename),
is_download(is_download), is_download(is_download),
remaining_bytes(remaining_bytes) {} total_size(total_size) {}
void ProxyServer::LinkedSession::dispatch_on_timeout(evutil_socket_t, short, void* ctx) { void ProxyServer::LinkedSession::dispatch_on_timeout(evutil_socket_t, short, void* ctx) {
reinterpret_cast<LinkedSession*>(ctx)->on_timeout(); reinterpret_cast<LinkedSession*>(ctx)->on_timeout();
+3 -3
View File
@@ -115,13 +115,13 @@ public:
std::string basename; std::string basename;
std::string output_filename; std::string output_filename;
bool is_download; bool is_download;
size_t remaining_bytes; size_t total_size;
std::deque<std::string> blocks; std::string data;
SavingFile( SavingFile(
const std::string& basename, const std::string& basename,
const std::string& output_filename, const std::string& output_filename,
size_t remaining_bytes, size_t total_size,
bool is_download); bool is_download);
}; };
std::unordered_map<std::string, SavingFile> saving_files; std::unordered_map<std::string, SavingFile> saving_files;