//===========================================================================// // File: l4net.cpp // // Project: MUNGA Brick: Network Manager // // Contents: Implementation details for the L4 network manager // //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 03/02/95 GAC Initial coding. // // 04/08/95 GAC Netnow Removed, TCP/NetNub support added // //---------------------------------------------------------------------------// // Copyright (C) 1994-1995, Virtual World Entertainment, Inc. // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #include #pragma hdrstop #if !defined(L4NET_HPP) # include #endif #if !defined(L4APP_HPP) # include #endif #if !defined(L4HOST_HPP) # include #endif #if !defined(MISSION_HPP) # include #endif #if !defined(NOTATION_HPP) # include #endif // //############################################################################# // NetNub client-side globals. Net_Common_Ptr NULL = no NetNub TSR loaded; // L4File then takes its plain-DOS path (L4FILE.CPP:32) and the network // manager runs in single user mode. //############################################################################# // Netcom_Ptr Net_Common_Ptr = NULL; void NetNub::SendCommand() { Fail("NetNub::SendCommand -- netnub interface not yet reconstructed"); } // //############################################################################# // Shared data support //############################################################################# // Derivation L4NetworkManager::ClassDerivations( NetworkManager::ClassDerivations, "L4NetworkManager" ); const Receiver::HandlerEntry L4NetworkManager::MessageHandlerEntries[]= { MESSAGE_ENTRY(L4NetworkManager,ReceiveEggFile), MESSAGE_ENTRY(L4NetworkManager,AcknowledgeEggFile), MESSAGE_ENTRY(L4NetworkManager,HostConnected), MESSAGE_ENTRY(L4NetworkManager,HostDisconnected) }; L4NetworkManager::MessageHandlerSet L4NetworkManager::MessageHandlers( ELEMENTS(L4NetworkManager::MessageHandlerEntries), L4NetworkManager::MessageHandlerEntries, NetworkManager::MessageHandlers ); L4NetworkManager::SharedData L4NetworkManager::DefaultData( L4NetworkManager::ClassDerivations, L4NetworkManager::MessageHandlers ); // //############################################################################# // Code for the network manager class //############################################################################# // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Constructor for the L4NetworkManager // L4NetworkManager::L4NetworkManager(): NetworkManager(DefaultData), messageBuffer(this) { unsigned long network_common_flat_address; network_common_flat_address = L4Application::GetNetworkCommonFlatAddress(); lastHostIteratorPosition = 0; nextOpenHostID = FirstLegalHostID+1; // Reserve first legal id for console currentNetworkState = NormalState; myConsoleHost = NULL; eggAcknowledged = False; networkStartupMode = SlaveMode; numberOfMungaHostsConnected = 0; numberOfConsoleHostsConnected = 0; remoteHostCount = 0x7FFFFFFF; // // If there is no net common, set things up for single user mode // if (network_common_flat_address == 0) { Net_Common_Ptr = NULL; // //--------------------------------------------------------------------- // Retrieve the egg as specified on the command line, and send it as an // egg message //--------------------------------------------------------------------- // CString egg_name = L4Application::GetEggNotationFileName(); if (!strlen(egg_name)) { Fail("ERROR: No source exists for egg!"); } networkEggNotationFile = new NotationFile(egg_name); Register_Object(networkEggNotationFile); networkEggNotationFile->WriteFile("last.egg"); currentNetworkState = NormalState; ReceiveEggFileMessage egg_message(-1, 10, "local egg", 10); application->Post(DefaultEventPriority, this, &egg_message); return; } // // Setup the local netcom structure and some pointers to things inside it // Fail("L4NetworkManager -- netnub (networked) path not yet reconstructed"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::~L4NetworkManager() { if (networkEggNotationFile) { Unregister_Object(networkEggNotationFile); delete networkEggNotationFile; networkEggNotationFile = NULL; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::CreateConsoleHost This routine creates the console remote // host and posts a listen for the console connection. // void L4NetworkManager::CreateConsoleHost() { // // Die if there is no network common around // if (Net_Common_Ptr == NULL) { return; } // // Initialize a bunch of stuff to sane states // nextOpenHostID = FirstLegalHostID+1; // Reserve first legal id for console networkStartupMode = SlaveMode; // We're a slave, (not a simulated console) currentNetworkState = ConsoleOnly; // Only accept messages from the console numberOfConsoleHostsConnected = 0; // Shouldn't be any consoles yet numberOfMungaHostsConnected = 0; // No game machines either Fail("L4NetworkManager::CreateConsoleHost -- netnub path not yet reconstructed"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::StartConnecting This routine is called when a mission // starts to allow the network management system to establish communications // with all the participants. // void L4NetworkManager::StartConnecting(Mission *mission) { L4Host *my_l4host; // // This should be entered with no network connections to other game hosts // up, so we initialize this count to zero. // numberOfMungaHostsConnected = 0; // // Create the host iterator for the mission egg // Mission::HostIterator mission_host_iterator(mission); MissionHostData *mission_host_data; // // If there is no net common, set things up for single user mode // if (Net_Common_Ptr == NULL) { // // Make the local host for single user testing, we give the host ID#1 // and assign the first symbolic name in the egg to it. // mission_host_data = mission_host_iterator.ReadAndNext(); Check(mission_host_data); my_l4host = new L4Host( 1, // Host ID mission_host_data->GetHostType(), // Host Type NullNetworkAddress, // Net Address 0, // Socket address mission_host_data->GetAddressString() ); Register_Object(my_l4host); Check(application); Check(application->GetHostManager()); application->GetHostManager()->AdoptLocalHost(my_l4host); // //-------------------------------------------------------------------- // 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); return; } Fail("L4NetworkManager::StartConnecting -- netnub path not yet reconstructed"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::Shutdown This routine is called when a mission ends to // allow the network management system to drop all the connections. // Logical L4NetworkManager::Shutdown() { Host *base_host; L4Host *my_l4host; unsigned long network_common_flat_address; network_common_flat_address = L4Application::GetNetworkCommonFlatAddress(); if (networkEggNotationFile) { Unregister_Object(networkEggNotationFile); delete networkEggNotationFile; networkEggNotationFile = NULL; } // // If there is no net common, all we do is deregister the local host // if (network_common_flat_address == 0) { base_host = application->GetHostManager()->OrphanLocalHost(); my_l4host = Cast_Object(L4Host*, base_host); Check(my_l4host); Unregister_Object(my_l4host); delete my_l4host; return True; } Fail("L4NetworkManager::Shutdown -- netnub path not yet reconstructed"); return False; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::Send Sends a message to a single host. // void L4NetworkManager::Send(Message *message, ClientID, HostID host_ID) { Host *base_host; L4Host *l4host; Check_Pointer(message); Check(application); Check(application->GetHostManager()); base_host = application->GetHostManager()->GetRemoteHost(host_ID); if (base_host == NULL) { return; } l4host = Cast_Object(L4Host*, base_host); if (l4host->GetConnectStatus() != L4Host::OnLineConnectionStatus) { return; } Fail("L4NetworkManager::Send -- netnub path not yet reconstructed"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::ExclusiveBroadcast Sends a message to every online host // except the named client. // void L4NetworkManager::ExclusiveBroadcast(Message *message, ClientID) { Check_Pointer(message); Check(application); // // With no hosts online there is no one to broadcast to // if (numberOfMungaHostsConnected == 0 && numberOfConsoleHostsConnected == 0) { return; } Fail("L4NetworkManager::ExclusiveBroadcast -- netnub path not yet reconstructed"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::CheckBuffers Checks to see if there is a message for us // buffered up in the network interface card. // Logical L4NetworkManager::CheckBuffers(NetworkPacket *) { // // No netnub present? Nothing can have arrived. // if (Net_Common_Ptr == NULL) { return False; } Fail("L4NetworkManager::CheckBuffers -- netnub path not yet reconstructed"); return False; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void L4NetworkManager::RemovePacket(NetworkPacket *) { // // No netnub present? Just return // if (Net_Common_Ptr == NULL) { return; } Fail("L4NetworkManager::RemovePacket -- netnub path not yet reconstructed"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical L4NetworkManager::ExecuteBackground() { Check(this); if (!messageBuffer.IsEmpty()) { messageBuffer.AttemptToSend(); return True; } return False; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::Marker Sends a text marker down the netnub spool for // mission review annotation. // void L4NetworkManager::Marker(char *) { // // No netnub present? Just return // if (Net_Common_Ptr == NULL) { return; } Fail("L4NetworkManager::Marker -- netnub path not yet reconstructed"); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::Mode Switches the netnub between reliable and unreliable // delivery. // void L4NetworkManager::Mode(NetworkMode) { // // No netnub present? Just return // if (Net_Common_Ptr == NULL) { return; } Fail("L4NetworkManager::Mode -- netnub path not yet reconstructed"); } // //############################################################################# // Message handlers //############################################################################# // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::ReceiveEggFileMessageHandler // void L4NetworkManager::ReceiveEggFileMessageHandler( ReceiveEggFileMessage *EggMessage ) { #if defined(LAB_ONLY) DEBUG_STREAM << "Received Egg message #" << EggMessage->sequenceNumber << endl; #endif // // 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"); currentNetworkState = NormalState; // // 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; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::AcknowledgeEggFileMessageHandler // void L4NetworkManager::AcknowledgeEggFileMessageHandler( AcknowledgeEggFileMessage * ) { #if defined(LAB_ONLY) DEBUG_STREAM << "\nReceived egg acknowledged message\n"; #endif eggAcknowledged = True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::HostConnectedMessageHandler // void L4NetworkManager::HostConnectedMessageHandler( HostConnectedMessage *HostConnected ) { // // Get a pointer to the L4 host // Check(application); Check(application->GetHostManager()); Host *connected_host = application->GetHostManager()->GetRemoteHost(HostConnected->hostID); L4Host *l4connected_host = Cast_Object(L4Host*, connected_host); Check(l4connected_host); // // Set the host connection status to on line and increment the // counter of hosts online. // l4connected_host->SetConnectStatus(L4Host::OnLineConnectionStatus); switch (l4connected_host->GetHostType()) { case GameMachineHostType: numberOfMungaHostsConnected++; DEBUG_STREAM << "Connected to GameMachineHost at "; break; case CameraShipHostType: numberOfMungaHostsConnected++; DEBUG_STREAM << "Connected to CameraShipHost at "; break; case MissionReviewHostType: numberOfMungaHostsConnected++; DEBUG_STREAM << "Connected to MissionReviewHost at "; break; case ConsoleHostType: numberOfConsoleHostsConnected++; DEBUG_STREAM << "Connected to ConsoleHost at "; break; default: Fail("L4NetworkManager::HostConnectedMessageHandler - unknown host type"); break; } DEBUG_STREAM << HostConnected->networkAddress << endl; if (numberOfMungaHostsConnected >= remoteHostCount) { DEBUG_STREAM << "All connections completed!\n"; Marker("MUNGA MARKER--All connections completed!\n"); // //-------------------------------------------------------------------- // All hosts are up; 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); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4NetworkManager::HostDisconnectedMessageHandler // This message is assumed only to be sent by the console just prior to it // disconnecting. It clues us to locally close and destroy the console host // so the game will start normally even if the console isn't around. // void L4NetworkManager::HostDisconnectedMessageHandler( HostDisconnectedMessage *HostDisconnected ) { // // Get a pointer to the L4 host // Check(application->GetHostManager()); Host *connected_host = application->GetHostManager()->GetRemoteHost(HostDisconnected->hostID); L4Host *l4connected_host = Cast_Object(L4Host*, connected_host); Check(l4connected_host); // // Set the host connection status to off line, then close the connection. // l4connected_host->SetConnectStatus(L4Host::NoNetworkConnectionStatus); NetworkAddress temp_net_address = l4connected_host->GetNetworkAddress(); CloseConnection(HostDisconnected->streamPointer); // // See what type of host it was that disconnected // switch (l4connected_host->GetHostType()) { case GameMachineHostType: numberOfMungaHostsConnected--; DEBUG_STREAM << "\nDisconnected from GameMachineHost at "; break; case CameraShipHostType: numberOfMungaHostsConnected--; DEBUG_STREAM << "\nDisconnected from CameraShipHost at "; break; case MissionReviewHostType: numberOfMungaHostsConnected--; DEBUG_STREAM << "\nDisconnected from MissionReviewHost at "; break; case ConsoleHostType: // // Knock down the number of consoles online, then destroy the // console host and recreate it; this resets all the internal // buffers and pointers so check_buffers won't go crazy // numberOfConsoleHostsConnected--; DEBUG_STREAM << "\nDisconnected from ConsoleHost at "; application->GetHostManager()->OrphanRemoteHost(l4connected_host); Unregister_Object(l4connected_host); delete l4connected_host; CreateConsoleHost(); break; default: Fail("L4NetworkManager::HostDisconnectedMessageHandler - unknown host type"); break; } DEBUG_STREAM << temp_net_address << "\n"; } // //############################################################################# // Netnub wire primitives -- not yet reconstructed //############################################################################# // unsigned long L4NetworkManager::CheckSocket(unsigned long) { Fail("L4NetworkManager::CheckSocket -- netnub path not yet reconstructed"); return 0; } unsigned long L4NetworkManager::ResolveAddress(CString) { Fail("L4NetworkManager::ResolveAddress -- netnub path not yet reconstructed"); return 0; } unsigned long L4NetworkManager::GetMyAddress() { Fail("L4NetworkManager::GetMyAddress -- netnub path not yet reconstructed"); return 0; } unsigned long L4NetworkManager::OpenConnection(int, int, int, int) { Fail("L4NetworkManager::OpenConnection -- netnub path not yet reconstructed"); return 0; } void L4NetworkManager::CloseConnection(unsigned long) { Fail("L4NetworkManager::CloseConnection -- netnub path not yet reconstructed"); } Logical L4NetworkManager::GetNextMungaPacket( NetworkPacket *, HostManager::RemoteHostIterator * ) { Fail("L4NetworkManager::GetNextMungaPacket -- netnub path not yet reconstructed"); return False; } Logical L4NetworkManager::SendMessageToNetnub(Message *, ClientID, HostID) { Fail("L4NetworkManager::SendMessageToNetnub -- netnub path not yet reconstructed"); return False; } void L4NetworkManager::SendBatchedMessageToNetnub( Message *, ClientID, DroppedMessageHostSocket * ) { Fail("L4NetworkManager::SendBatchedMessageToNetnub -- netnub path not yet reconstructed"); } // //############################################################################# // L4NetworkManager__MessageBuffer //############################################################################# // L4NetworkManager__MessageBuffer::L4NetworkManager__MessageBuffer( L4NetworkManager *network_manager ): messageQueueSocket(NULL, 1) { networkManager = network_manager; currentQueueIndex = 0; bufferSize = 0; } L4NetworkManager__MessageBuffer::~L4NetworkManager__MessageBuffer() { } void L4NetworkManager__MessageBuffer::AddSendRequest( HostID, NetworkClient::ClientID, Receiver::Message * ) { Fail("L4NetworkManager__MessageBuffer::AddSendRequest -- netnub path not yet reconstructed"); } void L4NetworkManager__MessageBuffer::AttemptToSend() { Fail("L4NetworkManager__MessageBuffer::AttemptToSend -- netnub path not yet reconstructed"); }