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_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);
bool modified = false;
@@ -1331,36 +1331,41 @@ static HandlerResult S_13_A7(shared_ptr<ProxyServer::LinkedSession> ses, uint16_
return HandlerResult::Type::FORWARD;
}
if (cmd.data_size > sf->remaining_bytes) {
ses->log.warning("Chunk size extends beyond original file size; truncating file");
cmd.data_size = sf->remaining_bytes;
modified = true;
} else if (cmd.data_size > 0x400) {
ses->log.warning("Chunk data size is invalid; truncating to 0x400");
cmd.data_size = 0x400;
bool is_last_block = (cmd.data_size != 0x400);
size_t block_offset = flag * 0x400;
size_t allowed_block_size = (block_offset < sf->total_size)
? min<size_t>(sf->total_size - block_offset, 0x400)
: 0;
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;
}
if (!sf->output_filename.empty()) {
ses->log.info("Adding %" PRIu32 " bytes to %s => %s",
cmd.data_size.load(), sf->basename.c_str(), sf->output_filename.c_str());
ses->log.info("Adding %" PRIu32 " bytes to %s:%02" PRIX32 " => %s:%zX",
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)) {
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)) {
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"))) {
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")) {
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);
phosg::save_file(sf->output_filename + ".txt", disassembly);
} 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")) {
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 {
ses->map = Lobby::load_maps(
ses->version(),
+2 -2
View File
@@ -708,12 +708,12 @@ void ProxyServer::LinkedSession::update_channel_names() {
ProxyServer::LinkedSession::SavingFile::SavingFile(
const string& basename,
const string& output_filename,
size_t remaining_bytes,
size_t total_size,
bool is_download)
: basename(basename),
output_filename(output_filename),
is_download(is_download),
remaining_bytes(remaining_bytes) {}
total_size(total_size) {}
void ProxyServer::LinkedSession::dispatch_on_timeout(evutil_socket_t, short, void* ctx) {
reinterpret_cast<LinkedSession*>(ctx)->on_timeout();
+3 -3
View File
@@ -115,13 +115,13 @@ public:
std::string basename;
std::string output_filename;
bool is_download;
size_t remaining_bytes;
std::deque<std::string> blocks;
size_t total_size;
std::string data;
SavingFile(
const std::string& basename,
const std::string& output_filename,
size_t remaining_bytes,
size_t total_size,
bool is_download);
};
std::unordered_map<std::string, SavingFile> saving_files;