Files
TeslaRel410/restoration/source410/MUNGA/NETWORK.CPP
T
CydandClaude Fable 5 5b35eb973c 4.10 reconstruction: BTL4OPT.EXE links clean and BOOTS to the first staged brick
The reconstructed tree now produces a runnable binary with the authentic
1995 toolchain (BC4.52 / tlink32 / DPMI32):

- BTL4.CPP main TU reconstructed from the 4.11 Ghidra decomp (FUN_0040109c)
  + the 4.10 binary's own string pool + surviving RPL4TOOL.CPP house style;
  probe_main.cpp scaffold retired (BTL4.NOTES.md documents every decoded call)
- L4NET.CPP staged: L4NetworkManager ctor/dtor + 10 vtable-pulled virtuals
  (standalone-benign ones no-op, network ones Fail loudly) + NetNub client
  globals (Net_Common_Ptr=NULL routes L4File to its plain-DOS path)
- build410.sh: libs now built in the AUTHENTIC makefile member order
  (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK). Order is load-bearing:
  tlink emits static-init records in module pull order, and alphabetical
  order booted into a null-vptr crash (IcomManager::ClassDerivations
  constructing before parent NetworkClient::ClassDerivations). Also fixed
  stage_link to the proven 32-bit lib set (SOSDBXC+SOSMBXC, no WATTCPLG)
- BOXTREE.HPP MemoryBlock unify, BTL4GRND notify stubs, remaining engine
  backfills (audio/gauge/resource/stream TUs) that closed the deep ledger

Smoke test (DOSBox-X + 32RTM, copy of the pod BT tree, our exe swapped in):
  BattleTech v4.10
  BTL4Application::BTL4Application
  l4net.cpp(22): L4NetworkManager -- l4net.cpp not yet reconstructed
Static init, main, -egg parse, BTL4.RES load (version 1.0.6 check passes),
ApplicationManager and the BTL4Application ctor chain all execute real
reconstructed code; boot halts at the first staged Fail() as designed.
Next brick: the real l4net.cpp body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 19:05:53 -05:00

441 lines
12 KiB
C++

# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(HOSTMGR_HPP)
# include <hostmgr.hpp>
# endif
# if !defined(INTEREST_HPP)
# include <interest.hpp>
# endif
# if !defined(ICOM_HPP)
# include <icom.hpp>
# endif
# if !defined(APP_HPP)
# include <app.hpp>
# endif
# if !defined(NOTATION_HPP)
# include <notation.hpp>
# endif
# if !defined(NTTMGR_HPP)
# include <nttmgr.hpp>
# endif
#if defined(TRACE_ROUTE_PACKET)
static BitTrace Route_Packet("Route Packet");
# define SET_ROUTE_PACKET() Route_Packet.Set()
# define CLEAR_ROUTE_PACKET() Route_Packet.Clear()
#else
# define SET_ROUTE_PACKET()
# define CLEAR_ROUTE_PACKET()
#endif
const NetworkAddress NullNetworkAddress = 0x00000000;// 0.0.0.0 (in TCP land);
//#############################################################################
// Shared Data Support
//
NetworkClient::SharedData
NetworkClient::DefaultData(
NetworkClient::ClassDerivations,
NetworkClient::MessageHandlers
);
//
//#############################################################################
// Code for the network client class
//#############################################################################
//
Derivation
NetworkClient::ClassDerivations(Receiver::ClassDerivations, "NetworkClient");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for the NetworkClient
//
NetworkClient::NetworkClient(
ClassID class_ID,
SharedData &virtual_data,
ClientID client_ID
):
Receiver(class_ID, virtual_data)
{
clientID = client_ID;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destructor for the NetworkClient
//
NetworkClient::~NetworkClient()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destructor for the NetworkClient
//
Logical
NetworkClient::TestInstance() const
{
return IsDerivedFrom(ClassDerivations);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Receive packet for the NetworkClient
//
void
NetworkClient::ReceiveNetworkPacket(
NetworkPacket*,
Receiver::Message *packet_message
)
{
Dispatch(packet_message);
}
//
//#############################################################################
// Code for the network manager class
//#############################################################################
const Receiver::HandlerEntry
NetworkManager::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(NetworkManager,ReceiveEggFile)
};
NetworkManager::MessageHandlerSet
NetworkManager::MessageHandlers(ELEMENTS(NetworkManager::MessageHandlerEntries), NetworkManager::MessageHandlerEntries, NetworkClient::MessageHandlers);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
NetworkManager::SharedData
NetworkManager::DefaultData(
NetworkManager::ClassDerivations,
NetworkManager::MessageHandlers
);
Derivation
NetworkManager::ClassDerivations(NetworkClient::ClassDerivations, "NetworkManager");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for the NetworkManager
//
NetworkManager::NetworkManager(SharedData &shared_data):
NetworkClient(NetworkManagerClassID, shared_data, NetworkManagerClientID)
{
// basic init goes here
gameID = 0;
eggTempBuffer = NULL;
networkEggNotationFile = NULL;
eggTempNext = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Creates a host for us. Any derived class must deal with reading the
// notation file to get the network nodes to connect to. This start is
// designed for STAND-ALONE MODE ONLY and should not be inherited for use by
//
void
NetworkManager::StartConnecting(Mission *)
{
Check(this);
//
//---------------------------------------------------------
// Make the local host, and get the application to adopt it
//---------------------------------------------------------
//
Host *local_host = new Host(1, GameMachineHostType, 1);
Register_Object(local_host);
Check(application);
Check(application->GetHostManager());
application->GetHostManager()->AdoptLocalHost(local_host);
//
//--------------------------------------------------------------------
// Now, since this host creator is for stand-alone mode, send the load
// mission message to the application
//--------------------------------------------------------------------
//
Check(application);
Application::Message
load_message(
Application::LoadMissionMessageID,
sizeof(Application::Message)
);
application->Post(DefaultEventPriority, application, &load_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::EndMission This routine is called when a mission ends to
// allow the network management system to do stuff (like disconnecting network
// connections between pods and so on)
//
Logical
NetworkManager::Shutdown()
{
//
// If there is a notation file floating about, kill it!
//
if (networkEggNotationFile)
{
Unregister_Object(networkEggNotationFile);
delete networkEggNotationFile;
}
//
// Deregister local host
//
Host *local_host;
local_host = application->GetHostManager()->OrphanLocalHost();
Unregister_Object(local_host);
delete local_host;
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destructor for the NetworkManager
//
NetworkManager::~NetworkManager()
{
// shutdown net goes here
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::ReceiveEggFileMessageHandler
//
void
NetworkManager::ReceiveEggFileMessageHandler(
ReceiveEggFileMessage* EggMessage
)
{
//
// An egg sequence number of -1 means that the egg is posted locally, and
// should just call create mission
//
if (EggMessage->sequenceNumber == -1)
{
application->CreateMission(networkEggNotationFile);
return;
}
if (EggMessage->sequenceNumber == 0)
{
//
// Make a buffer
//
eggTempBuffer = new char[EggMessage->notationFileLength];
Register_Pointer(eggTempBuffer);
eggTempNext = 0;
}
//
// Write the egg data into the buffer
//
memcpy(
(eggTempBuffer+eggTempNext),
EggMessage->notationData,
EggMessage->thisMessageLength
);
eggTempNext += EggMessage->thisMessageLength;
//
// If we don't have all the data, return and wait for more
//
if(eggTempNext < EggMessage->notationFileLength)
{
return;
}
//
// We've got all the data, make the notation file
//
networkEggNotationFile = new NotationFile();
Register_Object(networkEggNotationFile);
networkEggNotationFile->ReadText(eggTempBuffer, eggTempNext);
networkEggNotationFile->WriteFile("last.egg");
//
// Now turn the notation file into a mission
//
application->CreateMission(networkEggNotationFile);
//
// Get rid of the ram buffer now that we're done with it
//
Unregister_Pointer(eggTempBuffer);
delete eggTempBuffer;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::Send Handles sending a message to a specific network address
// which can NOT be us. Default behavior is to do nothing, as no network is
// hooked up if we get here
//
void
NetworkManager::Send(
Message *,
ClientID,
HostID
)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::Broadcast Handles broadcasting a message to everyone,
// including ourselves. !!!! Reliable broadcasting is currently used,
// implimented by sending a point-to-point message to every destination.
//
void
NetworkManager::Broadcast(
Message *message,
ClientID client_id
)
{
//
// Send this message back to ourselves
//
NetworkClient *client = GetNetworkClientPointer(client_id);
Check(client);
client->ReceiveNetworkPacket(NULL, message);
//
// Broadcast the message to everyone else on the network
//
ExclusiveBroadcast(message,client_id);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::ExclusiveBroadcast Broadcasts a message to everyone on the
// network execpt us. Default behavior sends it to nobody, as there is really
// no network
//
void
NetworkManager::ExclusiveBroadcast(
Message *,
ClientID
)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::GetNetworkClientPointer Determine who the client of a
// message is and return a pointer to them.
//
NetworkClient*
NetworkManager::GetNetworkClientPointer(ClientID client_id)
{
switch (client_id)
{
case NetworkClient::NetworkManagerClientID:
return this;
case NetworkClient::EntityManagerClientID:
Check(application);
return application->GetEntityManager();
case NetworkClient::HostManagerClientID:
Check(application);
return application->GetHostManager();
case NetworkClient::InterestManagerClientID:
Check(application);
return application->GetInterestManager();
case NetworkClient::IcomManagerClientID:
Check(application);
return application->GetIntercomManager();
case NetworkClient::ApplicationClientID:
Check(application);
return application;
default:
DEBUG_STREAM << "------UNKNOWN NETWORK CLIENT ID " << client_id << endl << flush;
Fail("Unknown Client ID");
break;
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::RoutePacket
//
Logical
NetworkManager::RoutePacket()
{
Check(this);
Byte
message_buffer[NETWORKMANAGER_BUFFER_SIZE];
NetworkPacket
*p;
//
// Return if check buffers doesn't have a packet for us
//
if (!CheckBuffers((NetworkPacket*)message_buffer))
{
return False;
}
//
// Process and route the packet properly
//
p = (NetworkPacket*)message_buffer;
if (p->gameID == gameID)
{
// cout<<"++++++++client "<<p->clientID<<" gameID "<<p->gameID<<" fromHost "<<p->fromHost<<"\n";
NetworkClient *client = GetNetworkClientPointer(p->clientID);
Check(client);
SET_ROUTE_PACKET();
client->ReceiveNetworkPacket(p, &p->messageData);
CLEAR_ROUTE_PACKET();
}
else
{
DEBUG_STREAM << "+++++++++ client " << p->clientID << " gameID " << p->gameID << " fromHost " << p->fromHost << endl << flush;
Fail("######### NOT A PACKET FOR THIS GAME!");
}
RemovePacket(p);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::ExecuteBackground Allows the network to perform tasks in
// the applications background. The method should return True if the manager
// is busy, False otherwise. For example, if the input and output buffers of
// the network driver are not empty then return True, otherwise return False.
//
Logical
NetworkManager::ExecuteBackground()
{
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::CheckBuffers Checks to see if there is a message for us
// buffered up in the network interface card and returns a pointer to it.
//
Logical
NetworkManager::CheckBuffers(NetworkPacket*)
{
Fail("NetworkManager::CheckBuffers - should never reach here!");
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::RemovePacket If the network implimentation requires us to
// free up a packet buffer, this routine would do it.
//
void
NetworkManager::RemovePacket(NetworkPacket*)
{
Fail("NetworkManager::RemovePacket - should never reach here!");
}