diff --git a/MUNGA/NETWORK.cpp b/MUNGA/NETWORK.cpp index 85ca2e3..cda5be9 100644 --- a/MUNGA/NETWORK.cpp +++ b/MUNGA/NETWORK.cpp @@ -287,7 +287,7 @@ void networkEggNotationFile = new NotationFile(); Register_Object(networkEggNotationFile); networkEggNotationFile->ReadText(eggTempBuffer, eggTempNext); - networkEggNotationFile->WriteFile("last.egg"); + networkEggNotationFile->WriteFile("last-loaded.egg"); // // Now turn the notation file into a mission diff --git a/MUNGA_L4/L4NET.CPP b/MUNGA_L4/L4NET.CPP index d87784d..3a80028 100644 --- a/MUNGA_L4/L4NET.CPP +++ b/MUNGA_L4/L4NET.CPP @@ -387,7 +387,7 @@ void networkEggNotationFile = new NotationFile(egg_path); Register_Object(networkEggNotationFile); - networkEggNotationFile->WriteFile("last.egg"); + networkEggNotationFile->WriteFile("last-loaded.egg"); // In network mode (the owner pod of a multiplayer race) the state // gate must open or CheckBuffers keeps dropping mesh packets - a @@ -907,7 +907,7 @@ void #if defined(LAB_ONLY) DEBUG_STREAM << "Created egg\n"; #endif - networkEggNotationFile->WriteFile("last.egg"); + networkEggNotationFile->WriteFile("last-loaded.egg"); currentNetworkState = NormalState; // diff --git a/MUNGA_L4/L4SPLR.cpp b/MUNGA_L4/L4SPLR.cpp index 54a4f80..5f0bdd2 100644 --- a/MUNGA_L4/L4SPLR.cpp +++ b/MUNGA_L4/L4SPLR.cpp @@ -195,11 +195,30 @@ void //###################### L4PlaybackNetworkManager ######################### //############################################################################# +// +// Whether the spool's header has been taken off the front of the stream, so +// SpoolerTask::Execute knows when the cursor is standing on a packet rather +// than on the header. Cleared when a playback manager is built, since the +// single-binary loop can play a second spool in the same process. +// +namespace +{ + Logical gSpoolHeaderConsumed = False; +} + +Logical + SpoolHeaderConsumed() +{ + return gSpoolHeaderConsumed; +} + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4PlaybackNetworkManager::L4PlaybackNetworkManager(): NetworkManager(L4PlaybackNetworkManager::DefaultData) { + gSpoolHeaderConsumed = False; + // // Give this application its mission. // @@ -400,6 +419,16 @@ void } } + // + // The cursor is now standing on the first packet, so the spooler task + // may start reading. Set only after the sanity check above, so a spool + // whose header did not add up is never played at all. + // + gSpoolHeaderConsumed = True; + DEBUG_STREAM << "Playback: header consumed, " + << (int) spool->GetBytesRemaining() << " bytes of packets to play\n" + << std::flush; + // // Now, just send the load message // @@ -817,6 +846,32 @@ void return; } + // + // Nothing may be read until the header has been taken off the front. + // + // A spool opens with the application ID, the resource version and one + // (remote, hostID) pair per host named in the egg, and the length of + // that depends on the egg - so it can only be read once the mission + // exists, which is what L4PlaybackNetworkManager::StartConnecting does. + // Until then the cursor is sitting on the header, and this function + // happily parsed it as packet one: the application ID read as a client + // ID, and ours is 0, which is NetworkManagerClientID exactly. The pair + // of host IDs after it read as a message length of 1 and a message ID + // of 3 - and message 3 on the network manager is ReceiveEggFile, which + // builds a Mission. From a packet. That was the heap corruption. + // + // The WaitingForEgg case below is for an arcade spool that CARRIES its + // egg as network manager packets, which cannot work with this format + // anyway: reading those packets means passing the header first, and + // passing the header means already knowing the egg. A recording made + // by this build keeps its egg beside it instead, which is why there is + // no such circle to break. + // + if (!SpoolHeaderConsumed()) + { + return; + } + // //----------------------------------------------------------------------- // We have a spool file, so interpret it based upon the application state diff --git a/MUNGA_L4/L4SPLR.h b/MUNGA_L4/L4SPLR.h index c9a5f05..2e08c58 100644 --- a/MUNGA_L4/L4SPLR.h +++ b/MUNGA_L4/L4SPLR.h @@ -54,6 +54,14 @@ public: //################### L4PlaybackNetworkManager ######################### //########################################################################## +// True once a spool's header has been read off the front of the stream, so +// the cursor is standing on a packet. SpoolerTask must not read before +// this: the header's length depends on the egg's host count, so it can only +// be taken off once the mission exists, and a task that reads early parses +// the header as a packet. See SpoolerTask::Execute. +Logical + SpoolHeaderConsumed(); + class L4PlaybackNetworkManager: public NetworkManager {