void CSyncDebugger::Initialize(bool useBacktrace, unsigned numPlayers) { delete[] history; history = NULL; delete[] historybt; historybt = NULL; #ifdef HAVE_BACKTRACE if (useBacktrace) { historybt = new HistItemWithBacktrace[HISTORY_SIZE * BLOCK_SIZE]; memset(historybt, 0, HISTORY_SIZE * BLOCK_SIZE * sizeof(HistItemWithBacktrace)); } else #endif { history = new HistItem[HISTORY_SIZE * BLOCK_SIZE]; memset(history, 0, HISTORY_SIZE * BLOCK_SIZE * sizeof(HistItem)); } //cleanup historyIndex = 0; disable_history = false; may_enable_history = false; flop = 0; players.clear(); players.resize(numPlayers); pendingBlocksToRequest.clear(); waitingForBlockResponse = false; // init logger logger.SetFilename(useBacktrace ? LOGFILE_SERVER : LOGFILE_CLIENT); logger.AddLine("SyncDebugger initialized"); logger.FlushBuffer(); }
/** * @brief serverside network receiver * * Plugin for the CGameServer network code in GameServer.cpp. * @return the number of bytes read from the network stream */ bool CSyncDebugger::ServerReceived(const unsigned char* inbuf) { bool syncDebugPacket = false; switch (inbuf[0]) { case NETMSG_SD_CHKRESPONSE: if (*(short*)&inbuf[1] != HISTORY_SIZE * sizeof(unsigned) + 12) { logger.AddLine("Server: received checksum response of %d instead of %d bytes", *(short*)&inbuf[1], HISTORY_SIZE * 4 + 12); } else { int player = inbuf[3]; if(player >= playerHandler->ActivePlayers() || player < 0) { logger.AddLine("Server: got invalid playernum %d in checksum response", player); } else { logger.AddLine("Server: got checksum response from %d", player); const unsigned* begin = (unsigned*)&inbuf[12]; const unsigned* end = begin + HISTORY_SIZE; players[player].checksumResponses.resize(HISTORY_SIZE); std::copy(begin, end, players[player].checksumResponses.begin()); players[player].remoteFlop = *(uint64_t*)&inbuf[4]; assert(!players[player].checksumResponses.empty()); int i = 0; while (i < playerHandler->ActivePlayers() && !players[i].checksumResponses.empty()) ++i; if (i == playerHandler->ActivePlayers()) { ServerQueueBlockRequests(); logger.AddLine("Server: checksum responses received; %d block requests queued", pendingBlocksToRequest.size()); } } } syncDebugPacket = true; break; case NETMSG_SD_BLKRESPONSE: if (*(short*)&inbuf[1] != BLOCK_SIZE * sizeof(unsigned) + 4) { logger.AddLine("Server: received block response of %d instead of %d bytes", *(short*)&inbuf[1], BLOCK_SIZE * 4 + 4); } else { int player = inbuf[3]; if(player >= playerHandler->ActivePlayers() || player < 0) { logger.AddLine("Server: got invalid playernum %d in block response", player); } else { const unsigned* begin = (unsigned*)&inbuf[4]; const unsigned* end = begin + BLOCK_SIZE; unsigned size = players[player].remoteHistory.size(); players[player].remoteHistory.resize(size + BLOCK_SIZE); std::copy(begin, end, players[player].remoteHistory.begin() + size); int i = 0; size += BLOCK_SIZE; while (i < playerHandler->ActivePlayers() && size == players[i].remoteHistory.size()) ++i; if (i == playerHandler->ActivePlayers()) { logger.AddLine("Server: block responses received"); ServerReceivedBlockResponses(); } } } syncDebugPacket = true; break; default: logger.AddLine("Server: unknown packet"); break; } logger.FlushBuffer(); return syncDebugPacket; }
void CSyncDebugger::ServerQueueBlockRequests() { logger.AddLine("Server: queuing block requests"); boost::uint64_t correctFlop = 0; for (int j = 0; j < playerHandler->ActivePlayers(); ++j) { if (correctFlop) { if (players[j].remoteFlop != correctFlop) logger.AddLine( #ifdef _WIN32 "Server: bad flop# %I64u instead of %I64u for player %d", #else "Server: bad flop# %llu instead of %llu for player %d", #endif players[j].remoteFlop, correctFlop, j); } else { correctFlop = players[j].remoteFlop; } } unsigned i = ((unsigned)(correctFlop % (HISTORY_SIZE * BLOCK_SIZE)) / BLOCK_SIZE) + 1; for (unsigned c = 0; c < HISTORY_SIZE; ++i, ++c) { unsigned correctChecksum = 0; if (i == HISTORY_SIZE) i = 0; for (int j = 0; j < playerHandler->ActivePlayers(); ++j) { if (correctChecksum && players[j].checksumResponses[i] != correctChecksum) { pendingBlocksToRequest.push_back(i); break; } correctChecksum = players[j].checksumResponses[i]; } } if (!pendingBlocksToRequest.empty()) { logger.AddLine("Server: blocks: %u equal, %u not equal", HISTORY_SIZE - pendingBlocksToRequest.size(), pendingBlocksToRequest.size()); requestedBlocks = pendingBlocksToRequest; // we know the first FPU bug occured in block # ii, so we send out a block request for it. // serverNet->SendData<unsigned> (NETMSG_SD_BLKREQUEST, ii); } else { logger.AddLine("Server: huh, all blocks equal?!?"); clientNet->Send(CBaseNetProtocol::Get().SendSdReset()); } //cleanup for (PlayerVec::iterator it = players.begin(); it != players.end(); ++it) it->checksumResponses.clear(); logger.FlushBuffer(); }
/** * @brief initialize * * Initialize the sync debugger. Pass true for a server (this requires approx. * 144 megabytes on 32 bit systems and 240 megabytes on 64 bit systems) and * false for a client (requires only 16 megabytes extra). * FIXME update this comment to reflect new values */ void CSyncDebugger::Initialize(bool useBacktrace, unsigned numPlayers) { delete[] history; history = 0; delete[] historybt; historybt = 0; #ifdef HAVE_BACKTRACE if (useBacktrace) { historybt = new HistItemWithBacktrace[HISTORY_SIZE * BLOCK_SIZE]; memset(historybt, 0, HISTORY_SIZE * BLOCK_SIZE * sizeof(HistItemWithBacktrace)); } else #endif { history = new HistItem[HISTORY_SIZE * BLOCK_SIZE]; memset(history, 0, HISTORY_SIZE * BLOCK_SIZE * sizeof(HistItem)); } //cleanup historyIndex = 0; disable_history = false; may_enable_history = false; flop = 0; for (unsigned j = 0; j < numPlayers; ++j) { PlayerStruct buf; buf.checksumResponses.clear(); buf.remoteHistory.clear(); buf.remoteFlop = 0; players.push_back(buf); } pendingBlocksToRequest.clear(); waitingForBlockResponse = false; // init logger logger.SetFilename(useBacktrace ? LOGFILE_SERVER : LOGFILE_CLIENT); logger.AddLine("Syncdebugger initialised"); logger.FlushBuffer(); }
/** * @brief clientside network receiver * * Plugin for the CGame network code in Game.cpp. * @return the number of bytes read from the network stream */ bool CSyncDebugger::ClientReceived(const unsigned char* inbuf) { bool syncDebugPacket = false; switch (inbuf[0]) { case NETMSG_SD_CHKREQUEST: if (gs->frameNum != *(int*)&inbuf[1]) { logger.AddLine("Client: received checksum request for frame %d instead of %d", *(int*)&inbuf[1], gs->frameNum); } else { disable_history = true; // no more additions to the history until we're done may_enable_history = false; ClientSendChecksumResponse(); logger.AddLine("Client: checksum response sent"); } syncDebugPacket = true; break; case NETMSG_SD_BLKREQUEST: if (*(unsigned short*)&inbuf[1] >= HISTORY_SIZE) { logger.AddLine("Client: invalid block number %d in block request", *(unsigned short*)&inbuf[1]); } else { ClientSendBlockResponse(*(unsigned short*)&inbuf[1]); logger.AddLine("Client: block response sent for block %d", *(unsigned short*)&inbuf[1]); // simple progress indication logOutput.Print("[SD] Client: %d / %d", *(unsigned short*)&inbuf[3], *(unsigned short*)&inbuf[5]); } syncDebugPacket = true; break; case NETMSG_SD_RESET: logger.CloseSession(); logOutput.Print("[SD] Client: Done!"); // disable_history = false; may_enable_history = true; syncDebugPacket = true; break; } logger.FlushBuffer(); return syncDebugPacket; }