Files
RP412/MUNGA_L4/L4NET.CPP
T
CydandClaude Fable 5 c66cb00a7e Network races: the local console marshals remote pods over the wire
The lobby-owner-as-console architecture, in-engine. RPL4CONSOLE gains
RPL4LocalConsole_InstallNetworkRace: the owner pod switches to network
mode and meshes like any pod (egg fed locally via FeedLocalEgg, which
now opens the ConsoleOnly state gate), while the console tick also
marshals REMOTE pods over NetTransport speaking the exact arcade
protocol - egg chunks with 5s-retry-until-ACK, 1Hz state polling,
RunMission once every pod stages at WaitingForLaunch, StopMission at
expiry (remotes first, local pod holds until their EndMission scores
land), score intake labeled with [pilots]-order names on the results
screen.

The front end builds the multi-pilot egg: RP412HOSTPODS lists member
console channels (lobby stand-in; the Steam lobby feeds the same
path), RP412HOSTPORT/RP412HOSTADDR set the owner side.

Winsock Connect now redials with a fresh socket per attempt (a refused
TCP socket is dead; the old loop reused it) bounded at 120s - needed
whenever a peer boots after the caller, which is the normal Steam
lobby launch order.

Verified on loopback: member pod in -net, owner hosting from its menu;
mesh completed both sides, 30s race, remote score collected over the
wire (host 3), local stop after the drain, results screen shows both
pilots by name in one process that returns to the menu.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 21:08:18 -05:00

3274 lines
98 KiB
C++

//===========================================================================//
// File: l4net.cpp //
// Project: MUNGA Brick: Network Manager //
// Contents: Interface specification for network brick //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 03/02/95 GAC Initial coding. //
// 04/08/95 GAC Netnow Removed, TCP/NetNub support added //
// NOTE: old netnow code is saved in L4NetNow.* //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
// PROPRIETARY AND CONFIDENTIAL //
//===========================================================================//
#include "mungal4.h"
#pragma hdrstop
#include "l4app.h"
#include "l4host.h"
#include "l4net.h"
#include "l4nettransport.h"
#include "..\munga\mission.h"
#include "..\munga\notation.h"
//#include <netnub.hpp>
#if defined(TRACE_SEND_PACKET)
static BitTrace Send_Packet("Send Packet");
#define SET_SEND_PACKET() Send_Packet.Set()
#define CLEAR_SEND_PACKET() Send_Packet.Clear()
#else
#define SET_SEND_PACKET()
#define CLEAR_SEND_PACKET()
#endif
#if defined(TRACE_CHECK_BUFFERS)
static BitTrace Check_Buffers("Check Buffers");
#define SET_CHECK_BUFFERS() Check_Buffers.Set()
#define CLEAR_CHECK_BUFFERS() Check_Buffers.Clear()
#else
#define SET_CHECK_BUFFERS()
#define CLEAR_CHECK_BUFFERS()
#endif
#if defined(TRACE_CALL_NETNUB)
static BitTrace Call_Netnub("Call Netnub");
#define SET_CALL_NETNUB() Call_Netnub.Set()
#define CLEAR_CALL_NETNUB() Call_Netnub.Clear()
#else
#define SET_CALL_NETNUB()
#define CLEAR_CALL_NETNUB()
#endif
#if defined(TRACE_LOST_DATA)
static BitTrace Lost_Data("Lost Data");
#define SET_LOST_DATA() Lost_Data.Set()
#define CLEAR_LOST_DATA() Lost_Data.Clear()
#else
#define SET_LOST_DATA()
#define CLEAR_LOST_DATA()
#endif
#define BATCHED_TRANSMIT True // true sends broadcast messages with a single call to netnub
#define BATCHED_RECEIVE True // true receives from all streams with a single call to netnub
#define REPORT_LOST_DATA False // Print a message if data is lost (may be toxic)
#if !defined(MESSAGE_BUFFERING)
#define MESSAGE_BUFFERING True // true uses munga level buffering for dropped packets
#endif
#define CONSOLE_NET_PORT 1501 // Port number the console will connect on
#define GAME_NET_PORT 1502 // Port number the game will connect on
char GlobalEggFileName[80]; // NASTY HACK !!! should suffice till we get console up though
//struct RMREG //real mode registers structure
//{
//unsigned long
// edi,
// esi,
// ebp,
// reserved,//0
// ebx,
// edx,
// ecx,
// eax;
//unsigned short
// flags, //0
// es,
// ds,
// fs, //0
// gs, //0
// ip,
// cs,
// sp,
// ss;
//};
//
// !!!! this stuff is also nasty but is currently required to be global for the
// assembly language stuff to work properly.
//
//Netcom_Ptr
// Net_Common_Ptr = NULL;
//
//unsigned short
// *Buffer_Length_Ptr; // Where the network common buffer length field is located
//
//short
// *Function_Ptr, // Where the network common function field is located
// offs, // offset of Real Mode Netcom struct
// baseadr, // segment of Real Mode Netcom struct
// intno,
// RMFunction_Off, // Offset of function field for real mode structure
// RMBuffer_Length_Off; // Offset of buffer length field for real mode structure
//long
// RMverno; // Real mode version number
////
//// !!!! These are the assembyly code functions we will be calling
////
//extern "C"
//{
// void mapRMBuff(void); //get selector for rm buffer
// void getRMNumbers(void); //get interr and version numbers from rm buffer
// void getRMBuff(void); //copy block from rm buffer
// void setRMBuff(void); //copy block to rm buffer
//};
//#############################################################################
// Shared Data Support
//
L4NetworkManager::SharedData
L4NetworkManager::DefaultData(
L4NetworkManager::GetClassDerivations(),
L4NetworkManager::GetMessageHandlers()
);
Derivation* L4NetworkManager::GetClassDerivations()
{
static Derivation classDerivations(NetworkManager::GetClassDerivations(), "L4NetworkManager");
return &classDerivations;
}
//#############################################################################
// Messaging support
//
const Receiver::HandlerEntry
L4NetworkManager::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(L4NetworkManager,ReceiveEggFile),
MESSAGE_ENTRY(L4NetworkManager,AcknowledgeEggFile),
MESSAGE_ENTRY(L4NetworkManager,HostConnected),
MESSAGE_ENTRY(L4NetworkManager,HostDisconnected)
};
Receiver::MessageHandlerSet& L4NetworkManager::GetMessageHandlers()
{
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(L4NetworkManager::MessageHandlerEntries), L4NetworkManager::MessageHandlerEntries, NetworkManager::GetMessageHandlers());
return messageHandlers;
}
//
//#############################################################################
// Code for the network manager class
//#############################################################################
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for the L4NetworkManager
//
//WinSock support :ADB 01/06/07
L4NetworkManager::L4NetworkManager():
NetworkManager(DefaultData),
messageBuffer(this)
{
unsigned long
network_common_flat_address;
network_common_flat_address =
((L4Application *)application)->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;
wsaData = new WSADATA;
//
// If there is no net common, set things up for single user mode
//
if(network_common_flat_address == 0)
{
//Net_Common_Ptr = NULL;
wsaData = NULL;
//
//---------------------------------------------------------------------
// Retrieve the egg as specified on the command line, and send it as an
// egg message
//---------------------------------------------------------------------
//
const char* egg_name = l4_application->GetEggNotationFileName();
if (!egg_name || !strlen(egg_name))
{
DEBUG_STREAM << "ERROR: No source exists for egg!\n" << std::flush;
PostQuitMessage(AbortExitCodeID);
}
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
//
//Net_Common_Ptr = new Netcom;
//Register_Pointer(Net_Common_Ptr);
//Function_Ptr = &Net_Common_Ptr->Function;
//Buffer_Length_Ptr = &Net_Common_Ptr->Buffer_Length;
if (!NetTransport_Get()->Startup())
{
DEBUG_STREAM << "ERROR: network transport startup failed!\n" << std::flush;
NetTransport_Get()->Cleanup();
PostQuitMessage(AbortExitCodeID);
}
consoleListenerSocket = NULL;
gameListenerSocket = NULL;
//
// Setup the global pointers that the netnub real/protected mode interface
// requires to work.
//
//offs = (short)(network_common_flat_address & 0x0000000f);
//baseadr = (short)(network_common_flat_address>>4);
//mapRMBuff(); //get selector for baseadr
//RMFunction_Off = (short)(offs
// + sizeof(Net_Common_Ptr->Version_Number)
// + sizeof(Net_Common_Ptr->Interrupt_Number));
//RMBuffer_Length_Off = (short)(RMFunction_Off
// + sizeof(Net_Common_Ptr->Function)
// + sizeof(Net_Common_Ptr->Status));
//getRMNumbers(); // get Interrupt_Number , Version_Number
//intno = Net_Common_Ptr->Interrupt_Number;
//RMverno = Net_Common_Ptr->Version_Number;
//
// Check for right network common number
////
//if(RMverno != NETCOM_VERSION)
//{
// DEBUG_STREAM << "Netnub version " << RMverno
// << ", code version " << NETCOM_VERSION << endl;
// Fail("MUNGA was compiled with an old version of netnub.h");
//}
//
// Get my network address from the netnub (also verify's we are connected)
//
addresses = GetMyAddress();
if(addresses == NULL)
{
DEBUG_STREAM<<"ERROR: GetMyAddress() failed!\n";
NetTransport_Get()->Cleanup();
Fail("Unable to initialize the network");
}
//
// Force us into reliable mode
//
Mode(NetworkManager::ReliableMode);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::MakeNotationFileEgg This routine creates the console remote
// host
//
//WinSock support :ADB 01/06/07
void L4NetworkManager::CreateConsoleHost()
{
//unsigned long console_socket;
//
// Die if there is no network common around
//
if (wsaData == NULL)
{
return;
}
unsigned short networkPort = (unsigned short)((L4Application *)application)->GetNetworkCommonFlatAddress();
//
// 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
//
// Post a listen for a console with an unknown network address
// this will return a stream that the console will eventually be on
//
//WinSock support :ADB 01/06/07
//console_socket = OpenConnection(
// NETNUB_TCP_LISTEN,
// CONSOLE_NET_PORT, // Local port
// 0, // Remote port (don't care in this case)
// 0); // Network address (don't care in this case)
consoleListenerSocket = (SOCKET) NetTransport_Get()->Listen(networkPort, 1);
if(consoleListenerSocket == INVALID_SOCKET)
{
DEBUG_STREAM << "ERROR: Could not open the console listener!\n" << std::flush;
NetTransport_Get()->Cleanup();
PostQuitMessage(AbortExitCodeID);
return;
}
//
// Register the console host with the host manager, this will insure it gets
// polled by CheckBuffers for connection. On connect we'll get a message
// routed to the network manager. Note that this host has an unspecified
// net address since we won't know it till the console connects. This
// must be the ONLY host we are listening for or things will fail!!!
//
SOCKADDR_IN address;
address.sin_family = AF_INET;
address.sin_addr.S_un.S_addr = NullNetworkAddress;
myConsoleHost = new L4Host(
FirstLegalHostID,
ConsoleHostType,
&address, // Don't know the net address till it connects.
INVALID_SOCKET,
"Console");
//
// Do the usual stuff to the host, register it, and have the host manager adopt it
//
Register_Object(myConsoleHost);
myConsoleHost->SetConnectStatus(L4Host::ListeningConnectionStatus);
Check(application);
Check(application->GetHostManager());
application->GetHostManager()->AdoptRemoteHost(myConsoleHost);
networkEggNotationFile = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::FeedLocalEgg Load a local egg file and post the same
// 'local egg' message the single-user startup posts, kicking the next
// mission cycle. Used by the in-game front end / local console.
//
void
L4NetworkManager::FeedLocalEgg(const char *egg_path)
{
Check(this);
Check_Pointer(egg_path);
if (networkEggNotationFile != NULL)
{
Unregister_Object(networkEggNotationFile);
delete networkEggNotationFile;
networkEggNotationFile = NULL;
}
networkEggNotationFile = new NotationFile(egg_path);
Register_Object(networkEggNotationFile);
networkEggNotationFile->WriteFile("last.egg");
// In network mode (the owner pod of a multiplayer race) the state
// gate must open or CheckBuffers keeps dropping mesh packets - a
// console-fed pod gets this from the chunked egg path instead.
currentNetworkState = NormalState;
ReceiveEggFileMessage egg_message(-1, 10, "local egg", 10);
application->Post(DefaultEventPriority, this, &egg_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::LoadMission This routine is called when a mission starts to
// allow the network management system to do stuff (potentially establishing
// communications with all the participants and such like)
//
void
L4NetworkManager::StartConnecting(Mission *mission)
{
int listen; // True if we should listen, false for connect
//WinSock support :ADB 01/06/07
//unsigned long
SOCKET socket_ptr; // temporary place to store the socket for a host
SOCKADDR_IN net_address; // temporary place to store resolved net address
net_address.sin_family = AF_INET;
L4Host *my_l4host;
// the game port is the console listening port + 1
unsigned short localGamePort = (unsigned short)((L4Application *)application)->GetNetworkCommonFlatAddress() + 1;
//
// 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
//
//WinSock support :ADB 01/06/07
//if (Net_Common_Ptr == NULL)
if(wsaData == 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);
SOCKADDR_IN address;
address.sin_family = AF_INET;
address.sin_family = NullNetworkAddress;
my_l4host = new L4Host(
1, // Host ID
mission_host_data->GetHostType(), // Host Type
&address, // Net Address
INVALID_SOCKET, // 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;
}
//
// Iterate through all the host addresses in the egg and create all the host
// structures, note that there MUST be an entry in the egg for us.
//
listen = False;
remoteHostCount = 0;
while ((mission_host_data = mission_host_iterator.ReadAndNext()) != NULL)
{
Check(mission_host_data);
//
// Try to resolve this address to an IP address
//
CString host_name(mission_host_data->GetAddressString());
//WinSock support :ADB 01/06/07
//VERIFY: are these IP addresses?
//net_address = ResolveAddress(host_name);
//net_address = inet_addr((char *)host_name);
NetTransport_Get()->Resolve((LPSTR)host_name, &net_address);
if (net_address.sin_port == 0)
net_address.sin_port = htons(localGamePort);
//
// See if this host is us or someone else
//
//WinSock support :ADB 01/06/07
bool addressFound = false;
for(int i=0; i<num_addresses; i++)
{
if(addresses[i] == net_address.sin_addr.S_un.S_addr && localGamePort == ntohs(net_address.sin_port))
{
addressFound = true;
break;
}
}
//if(net_address == address)
if(addressFound)
{
//
// Create the local host, socket is set to null since we can't send to
// ourselves.
//
my_l4host = new L4Host(
nextOpenHostID,
mission_host_data->GetHostType(),
//WinSock support :ADB 01/06/07
//address,
&net_address,
INVALID_SOCKET,
host_name);
Register_Object(my_l4host);
listen = True;
Check(application);
Check(application->GetHostManager());
application->GetHostManager()->AdoptLocalHost(my_l4host);
}
else
{
//
// See what we should do to connect to this remote host (open or listen)
//
remoteHostCount++;
if(listen)
{
//WinSock support :ADB 01/06/07
socket_ptr = OpenConnection(NETNUB_TCP_LISTEN, localGamePort, 0, net_address.sin_addr.S_un.S_addr);
}
else
socket_ptr = OpenConnection(NETNUB_TCP_OPEN, localGamePort, ntohs(net_address.sin_port), net_address.sin_addr.S_un.S_addr);
if (!listen && socket_ptr == INVALID_SOCKET)
DEBUG_STREAM << "Could not open connection to " << host_name << ".\n" << std::flush;
//
// Now we can create the remote host and get the application to adopt
// it
//
my_l4host = new L4Host(
nextOpenHostID,
mission_host_data->GetHostType(),
&net_address,
socket_ptr,
host_name);
Register_Object(my_l4host);
my_l4host->SetConnectStatus(
(listen)
? L4Host::ListeningConnectionStatus
: L4Host::OpeningConnectionStatus
);
Check(application);
Check(application->GetHostManager());
application->GetHostManager()->AdoptRemoteHost(my_l4host);
}
nextOpenHostID++;
}
//
// All the hosts are created, the connects/listens done.
//
if(networkStartupMode == SlaveMode)
{
//
// We are a slave (got our egg from the network) so we will
// acknowledge the egg now and wait for the connects to finish
//
#if defined(LAB_ONLY)
DEBUG_STREAM << "Sending egg Acknowledgement\n" << flush;
#endif
AcknowledgeEggFileMessage myAcknowledgeEgg;
Send(
&myAcknowledgeEgg,
NetworkClient::NetworkManagerClientID,
myConsoleHost->GetHostID()
);
//
//-----------------------------------------------------------------------
// Send the load mission message to the application... if an egg was sent
//-----------------------------------------------------------------------
//
if (numberOfMungaHostsConnected >= remoteHostCount)
{
Check(application);
Application::Message
load_message(
Application::LoadMissionMessageID,
sizeof(Application::Message)
);
application->Post(DefaultEventPriority, application, &load_message);
}
}
// Console simulator that would be here has been moved to end of file if needed
else
{
Fail("host is in an illegal startup mode\n");
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::Shutdown 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
L4NetworkManager::Shutdown()
{
Host
*base_host;
L4Host
*my_l4host;
unsigned long
network_common_flat_address;
network_common_flat_address = l4_application->GetNetworkCommonFlatAddress();
if (networkEggNotationFile)
{
Unregister_Object(networkEggNotationFile);
delete networkEggNotationFile;
networkEggNotationFile = NULL;
}
//
// If there is no net common, all we do is deregister the local host and return
//
if(network_common_flat_address == 0)
{
//
// Deregister local host
//
base_host = application->GetHostManager()->OrphanLocalHost();
my_l4host = Cast_Object(L4Host*, base_host);
Check(my_l4host);
Unregister_Object(my_l4host);
delete my_l4host;
return True;
}
//
// If we get here there was a network setup, we must drop all connections
// deregister all the remote hosts and then deregister the local host.
// Start by closing all connections.
//
Check(application);
HostManager *host_mgr = application->GetHostManager();
Check(host_mgr);
HostManager::RemoteHostIterator remote_hosts(host_mgr);
while ((base_host = remote_hosts.ReadAndNext()) != NULL)
{
my_l4host = Cast_Object(L4Host*, base_host);
Check(my_l4host);
//
//------------------------------
// Don't delete the console host
//------------------------------
//
if (my_l4host->GetHostType() == ConsoleHostType)
{
continue;
}
//
// Don't do a close if the system says we're not connected (means close was
// allready done by disconnect handler
//
if(my_l4host->GetConnectStatus() != Host::NoNetworkConnectionStatus)
{
CloseConnection(my_l4host->GetNetworkSocket());
}
// deregister this host with the host manager
host_mgr->OrphanRemoteHost(my_l4host);
Unregister_Object(my_l4host);
delete my_l4host;
}
//
// Deregister local host
//
base_host = host_mgr->OrphanLocalHost();
if (base_host)
{
my_l4host = Cast_Object(L4Host*, base_host);
Check(my_l4host);
Unregister_Object(my_l4host);
delete my_l4host;
}
//
// Reinitialize this in case we start another game
//
remoteHostCount = 0x7FFFFFFF;
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
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destructor for the L4NetworkManager
//
L4NetworkManager::~L4NetworkManager()
{
//WinSock support :ADB 01/06/07
//if(Net_Common_Ptr)
if(wsaData)
{
Check(application);
HostManager *host_mgr = application->GetHostManager();
Check(host_mgr);
HostManager::RemoteHostIterator remote_hosts(host_mgr);
Host *base_host;
while ((base_host = remote_hosts.ReadAndNext()) != NULL)
{
L4Host *my_l4host = Cast_Object(L4Host*, base_host);
Check(my_l4host);
//
// Don't do a close if the system says we're not connected (means close was
// allready done by disconnect handler
//
if(my_l4host->GetConnectStatus() != Host::NoNetworkConnectionStatus)
{
CloseConnection(my_l4host->GetNetworkSocket());
}
// deregister this host with the host manager
host_mgr->OrphanRemoteHost(my_l4host);
Unregister_Object(my_l4host);
delete my_l4host;
}
NetTransport_Get()->Cleanup();
delete wsaData;
wsaData = NULL;
//Unregister_Pointer(Net_Common_Ptr);
//delete Net_Common_Ptr;
//Net_Common_Ptr = NULL;
}
if(addresses)
delete[] addresses;
addresses = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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);
#if defined(LAB_ONLY)
DEBUG_STREAM << "Created egg\n";
#endif
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;
}
// commenting out because Verify doesn't do anything anymore --RB 10/28/08
////
//// Cross check the network address with the one in the host (just in case)
////
//Verify(
// l4connected_host->GetNetworkAddress() == HostConnected->networkAddress
//);
char addressString[44];
DWORD bufferSize = sizeof(addressString);
WSAAddressToStringA((LPSOCKADDR)&HostConnected->networkAddress, sizeof(SOCKADDR_IN), NULL, addressString, &bufferSize);
DEBUG_STREAM << addressString << std::endl << std::flush;
if (numberOfMungaHostsConnected >= remoteHostCount)
{
DEBUG_STREAM << "All connections completed!\n" << std::flush;
Marker("MUNGA MARKER--All connections completed!\n");
//
//--------------------------------------------------------------------
// 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);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::HostDisconnectedMessageHandler
// This message should eventually be generated in CheckBuffers, right now it
// is actually sent over the network and is assumed only to be sent by the
// console just prior to it disconnecting. It clues us do 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, get the network address so we
// can announce it later, then close the connection.
//
l4connected_host->SetConnectStatus(L4Host::NoNetworkConnectionStatus);
SOCKADDR_IN 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
//
numberOfConsoleHostsConnected--;
DEBUG_STREAM<<"\nDisconnected from ConsoleHost at ";
//
// Post a listen for a console so it can reconnect if it wants to.
//
NetTransport_Get()->Close(gameListenerSocket);
gameListenerSocket = NULL;
//unsigned long console_socket = OpenConnection(
// NETNUB_TCP_LISTEN,
// ((L4Application *)application)->GetNetworkCommonFlatAddress(), // Local port
// 0, // Remote port (don't care in this case)
// 0); // Network address (don't care in this case)
//
// Destroy the console host and recreate it, this resets all the
// internal buffers and pointers so check_buffers won't go crazy
//
application->GetHostManager()->OrphanRemoteHost(l4connected_host);
Unregister_Object(l4connected_host);
delete l4connected_host;
#if 1
CreateConsoleHost();
/*SOCKADDR_IN address;
address.sin_family = AF_INET;
address.sin_family = NullNetworkAddress;
l4connected_host = new L4Host(
FirstLegalHostID,
ConsoleHostType,
&address,
console_socket,
"Console");
Register_Object(l4connected_host);
l4connected_host->SetConnectStatus(L4Host::ListeningConnectionStatus);
application->GetHostManager()->AdoptRemoteHost(l4connected_host);
myConsoleHost = l4connected_host;*/
#else
myConsoleHost = 0;
#endif
break;
}
default:
Fail("L4NetworkManager::HostDisconnectedMessageHandler - unknown host type");
break;
}
char addressString[44];
DWORD bufferSize = sizeof(addressString);
WSAAddressToStringA((LPSOCKADDR)&temp_net_address, sizeof(SOCKADDR_IN), NULL, addressString, &bufferSize);
DEBUG_STREAM << addressString << "\n" << std::flush;
}
#if MESSAGE_BUFFERING
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::Send
//
void
L4NetworkManager::Send(
Message *message,
ClientID client_ID,
HostID host_ID
)
{
SET_SEND_PACKET();
Check(this);
Check(message);
//
//--------------------------------------------------------------------------
// If the message buffer is not empty then add this new message into the
// buffer. Attempt to send a message.
//--------------------------------------------------------------------------
//
if (!messageBuffer.IsEmpty())
{
messageBuffer.AddSendRequest(host_ID, client_ID, message);
messageBuffer.AttemptToSend();
}
//
//--------------------------------------------------------------------------
// The message buffer is empty so attempt to send the message.
//--------------------------------------------------------------------------
//
else if (!SendMessageToNetnub(message, client_ID, host_ID))
{
//
// Message was dropped, add this new message into the buffer
//
messageBuffer.AddSendRequest(host_ID, client_ID, message);
}
CLEAR_SEND_PACKET();
}
#else
//WinSock support :ADB 01/06/07
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::Send Handles sending a message to a specific network address
// which can NOT be us.
//
void L4NetworkManager::Send(
Message *message,
ClientID client,
HostID host_ID)
{
int packet_size;
Host *local_host;
Host *base_host;
L4Host *l4host;
//SendPacketRequestPtr send_packet_request; // Format of the request we send to the NetNub
//SendPacketReturnPtr send_packet_return;
HostManager *our_host_manager;
NetworkPacket *my_temp_packet; // pointer to a place to build a network message
//
// Mark entry to the routine with an analysis call
//
SET_SEND_PACKET();
//
// Check whatever incoming data needs checking, get a pointer to the host
// we are going to send to and make sure that host is online.
//
Check_Pointer(message);
Check(application);
our_host_manager = application->GetHostManager();
Check(our_host_manager);
base_host = our_host_manager->GetRemoteHost(host_ID);
l4host = Cast_Object(L4Host*, base_host);
if(l4host->GetConnectStatus() != L4Host::OnLineConnectionStatus)
{
CLEAR_SEND_PACKET();
return;
}
Verify(l4host->GetConnectStatus() == L4Host::OnLineConnectionStatus);
//
// figure out where to put the packet we're assembling
//
//send_packet_request = (SendPacketRequestPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//send_packet_return = (SendPacketReturnPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//my_temp_packet = (NetworkPacket*)send_packet_request->Send_Data;
//
// Build a MUNGA network packet in the netnub common block
//
if((false) || (message->messageLength < 8) || (false))
//if((message->messageLength > MAX_SEND_DATA_SIZE) || (message->messageLength < 8) || (message->messageLength+sizeof(NetworkPacketHeader) > MAX_SEND_DATA_SIZE))
{
char addressString[44];
DWORD bufferSize = sizeof(addressString);
WSAAddressToStringA((LPSOCKADDR)l4host->GetNetworkAddress(), sizeof(SOCKADDR_IN), NULL, addressString, &bufferSize);
DEBUG_STREAM << addressString << " Requested to send a " << message->messageLength << " size packet\n" << std::flush;
Fail("Illegal transmit size\n");
}
//Verify(message->messageLength + sizeof(NetworkPacketHeader) <= MAX_SEND_DATA_SIZE);
Verify(message->messageLength >= 8);
my_temp_packet = (NetworkPacket*)malloc(message->messageLength + sizeof(NetworkPacketHeader));
memcpy(&my_temp_packet->messageData, message, message->messageLength);
my_temp_packet->clientID = client;
my_temp_packet->gameID = gameID;
my_temp_packet->timeStamp = Now();
//
// If the local host doesn't exist yet, we send back zero
// this lets the console get status before the local host is actually created
//
local_host = our_host_manager->GetLocalHost();
if(local_host == NULL)
{
my_temp_packet->fromHost = 0;
}
else
{
Check(local_host);
my_temp_packet->fromHost = local_host->GetHostID();
}
packet_size = message->messageLength + sizeof(NetworkPacketHeader);
//
// Fill in the NetNub common block with the rest of the data it needs for the call
//
//Net_Common_Ptr->Function = NETNUB_SEND_PACKET;
//Net_Common_Ptr->Buffer_Length = (short)SEND_BUFFER_SIZE(packet_size);
//send_packet_request->Socket_Ptr = l4host->GetNetworkSocket();
//NetNub::SendCommand();
NetTransport_Get()->Send(l4host->GetNetworkSocket(), my_temp_packet, packet_size);
free(my_temp_packet);
// Check for errors and abort if there were any
//#if defined(TRACE_SEND_BUFFER)
//l4host->sendBufferTrace->TakeSnapshot(send_packet_return->Send_Buffer_Used);
//#endif
//switch(Net_Common_Ptr->Status)
//{
// case NETNUB_OK:
// break;
// case NETNUB_DATA_DUMPED:
// {
// SET_LOST_DATA();
// #if REPORT_LOST_DATA
// unsigned long temp_net_address;
// temp_net_address = l4host->GetNetworkAddress();
// DEBUG_STREAM<<"Data lost to ";
// DEBUG_STREAM<<((temp_net_address>>24) & 0xff)<<"."<<((temp_net_address>>16) & 0xff)<<".";
// DEBUG_STREAM<<((temp_net_address>>8) & 0xff)<<"."<<(temp_net_address & 0xff)<<"\n";
// DEBUG_STREAM<<flush;
// #endif
// CLEAR_LOST_DATA();
// break;
// }
// case NETNUB_STREAM_DISCONNECTED:
// {
// DEBUG_STREAM<<"Disconnect detected in send\n";
// DEBUG_STREAM<<flush;
// HostDisconnectedMessage myHostDisconnected(
// l4host->GetHostID(),
// l4host->GetNetworkSocket());
// NetworkClient *client = GetNetworkClientPointer(NetworkManagerClientID);
// Check(client);
// client->ReceiveNetworkPacket(NULL, &myHostDisconnected);
// break;
// }
// default:
// {
// unsigned long temp_net_address;
// temp_net_address = l4host->GetNetworkAddress();
// DEBUG_STREAM<<"Error "<<Net_Common_Ptr->Status<<" on ";
// DEBUG_STREAM<<((temp_net_address>>24) & 0xff)<<"."<<((temp_net_address>>16) & 0xff)<<".";
// DEBUG_STREAM<<((temp_net_address>>8) & 0xff)<<"."<<(temp_net_address & 0xff)<<"\n";
// DEBUG_STREAM<<flush;
// Fail("NetNub error in transmit\n");
// }
//}
CLEAR_SEND_PACKET();
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::SendMessageToNetnub
//
//WinSock support :ADB 01/06/07
Logical L4NetworkManager::SendMessageToNetnub(
Message *message,
ClientID client_ID,
HostID host_ID)
{
Check(this);
Check(message);
//
//--------------------------------------------------------------------------
// Get host manager, receiving host. Verify that the host is online.
//--------------------------------------------------------------------------
//
HostManager *host_manager;
L4Host *receiving_host;
Check(application);
host_manager = application->GetHostManager();
Check(host_manager);
receiving_host = Cast_Object(L4Host*, host_manager->GetRemoteHost(host_ID));
if (receiving_host->GetConnectStatus() != L4Host::OnLineConnectionStatus)
{
return True;
}
Verify(receiving_host->GetConnectStatus() == L4Host::OnLineConnectionStatus);
//
//--------------------------------------------------------------------------
// Get the local host ID. If the local host doesn't exist yet, we use zero,
// this lets the console get status before the local host is actually
// created.
//--------------------------------------------------------------------------
//
Host *local_host;
HostID local_host_ID;
if((local_host = host_manager->GetLocalHost()) == NULL)
{
local_host_ID = 0;
}
else
{
Check(local_host);
local_host_ID = local_host->GetHostID();
}
//
//--------------------------------------------------------------------------
// Verify that the size of the message is within bounds.
//--------------------------------------------------------------------------
//
long munga_network_message_size;
munga_network_message_size = sizeof(NetworkPacketHeader) + message->messageLength;
if((message->messageLength < 8) || (false))
//if((message->messageLength < 8) || (munga_network_message_size > MAX_SEND_DATA_SIZE))
{
char addressString[44];
DWORD bufferSize = sizeof(addressString);
WSAAddressToStringA((LPSOCKADDR)local_host->GetNetworkAddress(), sizeof(SOCKADDR_IN), NULL, addressString, &bufferSize);
DEBUG_STREAM << "L4NetworkManager::SendMessageToNetnub - " << addressString << "Requested to send a " << munga_network_message_size << " size message\n" << std::flush;
Fail("L4NetworkManager::SendMessageToNetnub - Illegal transmit size\n");
return True;
}
Verify(SEND_BUFFER_SIZE(munga_network_message_size) <= SHARED_MEMORY_SIZE);
//
//--------------------------------------------------------------------------
// Build the send request and MUNGA network packet
//--------------------------------------------------------------------------
//
//SendPacketRequestPtr send_packet_request;
NetworkPacket *network_packet;
Check_Pointer(Net_Common_Ptr);
//send_packet_request = (SendPacketRequestPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//network_packet = (NetworkPacket*)send_packet_request->Send_Data;
network_packet = (NetworkPacket*)malloc(munga_network_message_size);
//send_packet_request->Socket_Ptr = receiving_host->GetNetworkSocket();
network_packet->clientID = client_ID;
network_packet->gameID = gameID;
network_packet->fromHost = local_host_ID;
network_packet->timeStamp = Now();
Mem_Copy(
&network_packet->messageData,
message,
message->messageLength,
MAX_SEND_DATA_SIZE-sizeof(NetworkPacketHeader)
);
//
//--------------------------------------------------------------------------
// Netnub call
//--------------------------------------------------------------------------
//
//Check_Pointer(Net_Common_Ptr);
//#if defined(TRACE_SEND_BUFFER)
// SendPacketReturnPtr send_packet_return =
// (SendPacketReturnPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//#endif
//Net_Common_Ptr->Buffer_Length =
// (unsigned short)SEND_BUFFER_SIZE(munga_network_message_size);
//Net_Common_Ptr->Function =
// NETNUB_SEND_PACKET;
//NetNub::SendCommand();
NetTransport_Get()->Send(receiving_host->GetNetworkSocket(), network_packet, munga_network_message_size);
free(network_packet);
#if defined(TRACE_SEND_BUFFER)
receiving_host->sendBufferTrace->TakeSnapshot(
send_packet_return->Send_Buffer_Used
);
#endif
//
//--------------------------------------------------------------------------
// Check for errors
//--------------------------------------------------------------------------
//
//switch(Net_Common_Ptr->Status)
//{
//case NETNUB_OK:
// return True;
//
//case NETNUB_DATA_DUMPED:
// {
// SET_LOST_DATA();
// #if REPORT_LOST_DATA
// unsigned long
// temp_net_address = receiving_host->GetNetworkAddress();
// DEBUG_STREAM << "L4NetworkManager::SendMessageToNetnub - ";
// DEBUG_STREAM << "Data lost to ";
// DEBUG_STREAM << ((temp_net_address>>24) & 0xff)<<"."<<
// ((temp_net_address>>16) & 0xff)<<".";
// DEBUG_STREAM << ((temp_net_address>>8) & 0xff)<<"."<<
// (temp_net_address & 0xff)<<"\n";
// DEBUG_STREAM << flush;
// #endif
// CLEAR_LOST_DATA();
// }
// return False;
//
//case NETNUB_STREAM_DISCONNECTED:
// {
// DEBUG_STREAM << "L4NetworkManager::SendMessageToNetnub - ";
// DEBUG_STREAM<<"Disconnect detected in send\n";
// DEBUG_STREAM<<flush;
//
// HostDisconnectedMessage
// myHostDisconnected(
// receiving_host->GetHostID(),
// receiving_host->GetNetworkSocket()
// );
//
// NetworkClient
// *client = GetNetworkClientPointer(NetworkManagerClientID);
// Check(client);
// client->ReceiveNetworkPacket(NULL, &myHostDisconnected);
// }
// return True;
//
//default:
// {
// unsigned long
// temp_net_address = receiving_host->GetNetworkAddress();
// DEBUG_STREAM << "L4NetworkManager::SendMessageToNetnub - ";
// DEBUG_STREAM << "Error "<<Net_Common_Ptr->Status<<" on ";
// DEBUG_STREAM << ((temp_net_address>>24) & 0xff)<<"."<<
// ((temp_net_address>>16) & 0xff)<<".";
// DEBUG_STREAM << ((temp_net_address>>8) & 0xff)<<"."<<
// (temp_net_address & 0xff)<<"\n";
// DEBUG_STREAM << flush;
// Fail("NetNub error in transmit\n");
// }
// break;
//}
return True;
}
#if MESSAGE_BUFFERING
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::ExclusiveBroadcast
//
void
L4NetworkManager::ExclusiveBroadcast(
Message *message,
ClientID client_ID
)
{
SET_SEND_PACKET();
Check(this);
Check(message);
//
//--------------------------------------------------------------------------
// If the message buffer is not empty then add this new message into the
// buffer. One copy per host.
//--------------------------------------------------------------------------
//
if (!messageBuffer.IsEmpty())
{
Check(application);
Check(application->GetHostManager());
HostManager::RemoteHostIterator
remote_hosts(application->GetHostManager());
Host
*host;
L4Host
*l4host;
while ((host = remote_hosts.ReadAndNext()) != NULL)
{
l4host = Cast_Object(L4Host*, host);
Check(l4host);
//
// only non-console hosts that are online
//
if(
(l4host->GetHostType() != ConsoleHostType) &&
(l4host->GetConnectStatus() == L4Host::OnLineConnectionStatus)
)
{
messageBuffer.AddSendRequest(
l4host->GetHostID(),
client_ID,
message
);
}
}
messageBuffer.AttemptToSend();
CLEAR_SEND_PACKET();
return;
}
//
//--------------------------------------------------------------------------
// The message buffer is empty so attempt to send the message.
//--------------------------------------------------------------------------
//
DroppedMessageHostSocket
dropped_message_host_socket(NULL);
SendBatchedMessageToNetnub(
message,
client_ID,
&dropped_message_host_socket
);
//
//--------------------------------------------------------------------------
// For each host the message was dropped, add a send request message
//--------------------------------------------------------------------------
//
DroppedMessageHostIterator
iterator(&dropped_message_host_socket);
L4Host
*l4host;
while((l4host = iterator.ReadAndNext()) != NULL)
{
Check(l4host);
messageBuffer.AddSendRequest(
l4host->GetHostID(),
client_ID,
message
);
}
CLEAR_SEND_PACKET();
}
#else
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::ExclusiveBroadcast Broadcasts a message to everyone on the
// network execpt us. !!!! Reliable broadcasting is currently used,
// implimented by sending a point-to-point message to every destination.
//
void
L4NetworkManager::ExclusiveBroadcast(
Message *message, // what,
ClientID client // to
)
{
#if !BATCHED_TRANSMIT
Host
*this_host;
//
// Iterate through the host list, resolving network addresses, sending and
// making sure we don't send to ourselves.
//
Check(application);
Check(application->GetHostManager());
HostManager::RemoteHostIterator remote_hosts(application->GetHostManager());
while ((this_host = remote_hosts.ReadAndNext()) != NULL)
{
Check(this_host);
if(this_host->GetHostType() == ConsoleHostType)
{
continue;
}
Send(message, client, this_host->GetHostID());
}
#else
int
i,
host_count, // Number of hosts we will be sending to
packet_size;
Host
*this_host,
*local_host;
L4Host
*l4_host_list[MULTIPLE_SEND_PACKET_MAX],
*l4host;
MultipleSendPacketReturnPtr
multiple_send_packet_return; // Format of the reply we get from the NetNub
MultipleSendPacketRequestPtr
multiple_send_packet_request; // Format of the request we send to the NetNub
HostManager
*our_host_manager;
NetworkPacket
*my_temp_packet; // pointer to a place to build a network message
//
// Mark entry to the routine with an analysis call
//
SET_SEND_PACKET();
//
// Make sure the application and host manager are valid
//
Check(application);
Check_Pointer(message);
our_host_manager = application->GetHostManager();
Check(our_host_manager);
//
// Make a remote host iterator
//
HostManager::RemoteHostIterator remote_hosts(our_host_manager);
multiple_send_packet_request = (MultipleSendPacketRequestPtr)Net_Common_Ptr->Shared_Memory_Buffer;
multiple_send_packet_return = (MultipleSendPacketReturnPtr)Net_Common_Ptr->Shared_Memory_Buffer;
my_temp_packet = (NetworkPacket*)multiple_send_packet_request->Send_Data;
//
// Iterate through all the hosts we want to send to and add them to the
// NETNUB_MULTIPLE_SEND command structure
//
host_count = 0;
while ((this_host = remote_hosts.ReadAndNext()) != NULL)
{
// convert regular host to an L4host so we can get net info
l4host = Cast_Object(L4Host*, this_host);
Check(l4host);
// only broadcast to non-console hosts that are online
if((l4host->GetHostType() != ConsoleHostType) &&
(l4host->GetConnectStatus() == L4Host::OnLineConnectionStatus))
{
// Remember this host so we can match up errors with it later
l4_host_list[host_count] = l4host;
// Put the socket pointer for this host into the request structure
multiple_send_packet_request->Socket_Ptrs[host_count] =
l4host->GetNetworkSocket();
host_count++;
if(host_count >= MULTIPLE_SEND_PACKET_MAX)
Fail("Tried to send to too many destinations\n");
}
}
//
// Return if we didn't find anyone to send to
//
if(host_count == 0)
{
CLEAR_SEND_PACKET();
return;
}
multiple_send_packet_request->Socket_Count = host_count;
//
// Check the packet to make sure it is of legal size
//
if( (message->messageLength > MAX_SEND_DATA_SIZE) ||
(message->messageLength < 8) ||
(message->messageLength+sizeof(NetworkPacketHeader) > MAX_SEND_DATA_SIZE))
{
DEBUG_STREAM<<"Tried to send a "<<message->messageLength<<" size packet\n";
DEBUG_STREAM<<flush;
Fail("Illegal transmit size\n");
}
//
// Copy the data over into the command to netnub
//
memcpy(&my_temp_packet->messageData, message, message->messageLength);
my_temp_packet->clientID = client;
my_temp_packet->gameID = gameID;
my_temp_packet->timeStamp = Now();
//
// If the local host doesn't exist yet, we send back zero as the from address
// this lets the console get status before the local host is actually created
//
local_host = our_host_manager->GetLocalHost();
if(local_host == NULL)
{
my_temp_packet->fromHost = 0;
}
else
{
Check(local_host);
my_temp_packet->fromHost = local_host->GetHostID();
}
//
// Fill in the NetNub common block with the rest of the data it needs for the call
//
packet_size = message->messageLength + sizeof(NetworkPacketHeader);
Net_Common_Ptr->Function = NETNUB_MULTIPLE_SEND;
Net_Common_Ptr->Buffer_Length = (short)MULTIPLE_SEND_BUFFER_SIZE(packet_size);
NetNub::SendCommand();
#if !defined(TRACE_SEND_BUFFER)
if(Net_Common_Ptr->Status == NETNUB_OK)
{
CLEAR_SEND_PACKET();
return;
}
#endif
//
// If we get this far an error was reported on one of the streams
//
for(i = 0; i<host_count; i++)
{
l4host = l4_host_list[i];
#if defined(TRACE_SEND_BUFFER)
l4host->sendBufferTrace->TakeSnapshot(multiple_send_packet_return->Send_Buffer_Used[i]);
#endif
switch(multiple_send_packet_return->Errors[i])
{
case NETNUB_OK:
break;
case NETNUB_DATA_DUMPED:
{
SET_LOST_DATA();
#if REPORT_LOST_DATA
unsigned long temp_net_address = l4host->GetNetworkAddress();
DEBUG_STREAM<<"Data lost to ";
DEBUG_STREAM<<((temp_net_address>>24) & 0xff)<<"."<<((temp_net_address>>16) & 0xff)<<".";
DEBUG_STREAM<<((temp_net_address>>8) & 0xff)<<"."<<(temp_net_address & 0xff)<<"\n";
DEBUG_STREAM<<flush;
#endif
CLEAR_LOST_DATA();
break;
}
case NETNUB_STREAM_DISCONNECTED:
{
DEBUG_STREAM<<"Disconnect detected in send\n";
DEBUG_STREAM<<flush;
HostDisconnectedMessage myHostDisconnected(
l4host->GetHostID(),
l4host->GetNetworkSocket());
NetworkClient *client = GetNetworkClientPointer(NetworkManagerClientID);
Check(client);
client->ReceiveNetworkPacket(NULL, &myHostDisconnected);
break;
}
default:
{
unsigned long temp_net_address;
temp_net_address = l4host->GetNetworkAddress();
DEBUG_STREAM<<"Error "<<Net_Common_Ptr->Status<<" on ";
DEBUG_STREAM<<((temp_net_address>>24) & 0xff)<<"."<<((temp_net_address>>16) & 0xff)<<".";
DEBUG_STREAM<<((temp_net_address>>8) & 0xff)<<"."<<(temp_net_address & 0xff)<<"\n";
DEBUG_STREAM<<flush;
Fail("NetNub error in transmit\n");
}
}
}
CLEAR_SEND_PACKET();
#endif
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::SendBatchedMessageToNetnub
//
//WinSock support :ADB 01/06/07
void
L4NetworkManager::SendBatchedMessageToNetnub(
Message *message,
ClientID client_ID,
DroppedMessageHostSocket *dropped_message_host_socket
)
{
Check(this);
Check(dropped_message_host_socket);
//
//--------------------------------------------------------------------------
// If communication with netnub does not exist then return.
//--------------------------------------------------------------------------
//
if(wsaData == NULL)
return;
//
//--------------------------------------------------------------------------
// Get host manager.
//--------------------------------------------------------------------------
//
HostManager
*host_manager;
Check(application);
host_manager = application->GetHostManager();
Check(host_manager);
//
//--------------------------------------------------------------------------
// Get the local host ID. If the local host doesn't exist yet, we use zero,
// this lets the console get status before the local host is actually
// created.
//--------------------------------------------------------------------------
//
Host
*local_host;
HostID
local_host_ID;
if ((local_host = host_manager->GetLocalHost()) == NULL)
{
local_host_ID = 0;
}
else
{
Check(local_host);
local_host_ID = local_host->GetHostID();
}
//
//--------------------------------------------------------------------------
// Verify that the size of the message is within bounds.
//--------------------------------------------------------------------------
//
long
munga_network_message_size;
munga_network_message_size = sizeof(NetworkPacketHeader)+message->messageLength;
//if((message->messageLength < 8) || (munga_network_message_size > MAX_SEND_DATA_SIZE))
if((message->messageLength < 8) || (false))
{
DEBUG_STREAM << "L4NetworkManager::SendBatchedMessageToNetnub - ";
DEBUG_STREAM << "Requested to send a " <<
munga_network_message_size << " size message\n";
DEBUG_STREAM << std::flush;
Fail("L4NetworkManager::SendBatchedMessageToNetnub - Illegal transmit size\n");
return;
}
Verify(MULTIPLE_SEND_BUFFER_SIZE(munga_network_message_size) <= SHARED_MEMORY_SIZE);
//
//--------------------------------------------------------------------------
// Build the send request and MUNGA network packet
//--------------------------------------------------------------------------
//
//MultipleSendPacketRequestPtr send_packet_request;
NetworkPacket *network_packet;
Check_Pointer(Net_Common_Ptr);
//send_packet_request = (MultipleSendPacketRequestPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//network_packet = (NetworkPacket*)send_packet_request->Send_Data;
network_packet = (NetworkPacket*)malloc(munga_network_message_size);
//
// Fill in socket ptrs
//
HostManager::RemoteHostIterator remote_hosts(host_manager);
Host *host;
L4Host *l4host, *l4host_array[MULTIPLE_SEND_PACKET_MAX];
int host_count;
host_count = 0;
while ((host = remote_hosts.ReadAndNext()) != NULL)
{
l4host = Cast_Object(L4Host*, host);
Check(l4host);
//
// only broadcast to non-console hosts that are online
//
if(
(l4host->GetHostType() != ConsoleHostType) &&
(l4host->GetConnectStatus() == L4Host::OnLineConnectionStatus)
)
{
if (host_count >= MULTIPLE_SEND_PACKET_MAX)
{
DEBUG_STREAM << "L4NetworkManager::SendBatchedMessageToNetnub - ";
Fail("Tried to send to too many destinations\n");
return;
}
//
// Remember this host so we can match up errors with it later
//
Verify(0 <= host_count && host_count < MULTIPLE_SEND_PACKET_MAX);
l4host_array[host_count] = l4host;
//
// Put the socket pointer for this host into the request structure
//
Verify(0 <= host_count && host_count < MULTIPLE_SEND_PACKET_MAX);
//send_packet_request->Socket_Ptrs[host_count] = l4host->GetNetworkSocket();
host_count++;
}
}
//
// Return if there are no hosts to send to
//
//if((send_packet_request->Socket_Count = host_count) == 0)
if(host_count == 0)
return;
//
// Fill out the munga network packet
//
network_packet->clientID = client_ID;
network_packet->gameID = gameID;
network_packet->fromHost = local_host_ID;
network_packet->timeStamp = Now();
Mem_Copy(
&network_packet->messageData,
message,
message->messageLength,
MAX_SEND_DATA_SIZE-sizeof(NetworkPacketHeader)
);
//
//--------------------------------------------------------------------------
// Netnub call
//--------------------------------------------------------------------------
//
//MultipleSendPacketReturn
// *send_packet_return;
//
//Check_Pointer(Net_Common_Ptr);
//send_packet_return =
// (MultipleSendPacketReturn*)Net_Common_Ptr->Shared_Memory_Buffer;
//Net_Common_Ptr->Buffer_Length =
// (unsigned short)MULTIPLE_SEND_BUFFER_SIZE(munga_network_message_size);
//Net_Common_Ptr->Function =
// NETNUB_MULTIPLE_SEND;
//NetNub::SendCommand();
for(int i=0; i<host_count; i++)
{
// was send(..., sizeof(network_packet), 0): sizeof a POINTER -
// four bytes of packet, which would shear the stream framing
// if this path ever fired
NetTransport_Get()->Send(l4host_array[i]->GetNetworkSocket(), network_packet, munga_network_message_size);
}
free(network_packet);
//if (Net_Common_Ptr->Status == NETNUB_OK)
// return;
//
////
////--------------------------------------------------------------------------
//// Parse return
////--------------------------------------------------------------------------
////
//for (int i = 0; i < host_count; i++)
//{
// Verify(0 <= i && i < MULTIPLE_SEND_PACKET_MAX);
// l4host = l4host_array[i];
// Check(l4host);
//
// #if defined(TRACE_SEND_BUFFER)
// l4host->sendBufferTrace->TakeSnapshot(
// send_packet_return->Send_Buffer_Used[i]
// );
// #endif
// switch (send_packet_return->Errors[i])
// {
// case NETNUB_OK:
// break;
//
// case NETNUB_DATA_DUMPED:
// {
// SET_LOST_DATA();
// #if REPORT_LOST_DATA
// unsigned long
// temp_net_address = l4host->GetNetworkAddress();
//
// DEBUG_STREAM << "L4NetworkManager::SendBatchedMessageToNetnub - ";
// DEBUG_STREAM << "Data lost to ";
// DEBUG_STREAM << ((temp_net_address>>24) & 0xff)<<"."<<
// ((temp_net_address>>16) & 0xff)<<".";
// DEBUG_STREAM << ((temp_net_address>>8) & 0xff)<<"."<<
// (temp_net_address & 0xff)<<"\n";
// DEBUG_STREAM << flush;
// #endif
//
// //
// // Add this host to the dropped message host socket
// //
// Check(dropped_message_host_socket);
// dropped_message_host_socket->Add(l4host);
// CLEAR_LOST_DATA();
// }
// break;
//
// case NETNUB_STREAM_DISCONNECTED:
// {
// DEBUG_STREAM << "L4NetworkManager::SendBatchedMessageToNetnub - ";
// DEBUG_STREAM <<"Disconnect detected in send\n";
// DEBUG_STREAM <<flush;
//
// HostDisconnectedMessage
// myHostDisconnected(
// l4host->GetHostID(),
// l4host->GetNetworkSocket()
// );
// NetworkClient
// *client = GetNetworkClientPointer(NetworkManagerClientID);
// Check(client);
// client->ReceiveNetworkPacket(NULL, &myHostDisconnected);
// }
// break;
//
// default:
// {
// unsigned long
// temp_net_address = l4host->GetNetworkAddress();
// DEBUG_STREAM << "L4NetworkManager::SendBatchedMessageToNetnub - ";
// DEBUG_STREAM <<"Error "<<Net_Common_Ptr->Status<<" on ";
// DEBUG_STREAM <<((temp_net_address>>24) & 0xff)<<"."<<
// ((temp_net_address>>16) & 0xff)<<".";
// DEBUG_STREAM <<((temp_net_address>>8) & 0xff)<<"."<<
// (temp_net_address & 0xff)<<"\n";
// DEBUG_STREAM <<flush;
// Fail("NetNub error in transmit\n");
// }
// break;
// }
//}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::ExecuteBackground
//
Logical
L4NetworkManager::ExecuteBackground()
{
#if MESSAGE_BUFFERING
Check(this);
if (!messageBuffer.IsEmpty())
{
messageBuffer.AttemptToSend();
return True;
}
return False;
#else
return False;
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::CheckBuffers Checks to see if there is a message for us
// buffered up in the network interface card and returns a pointer to it.
// NOTE: This thing should be using iterators to keep track of the people on
// line, waiting for connections and so on.
//
//WinSock support :ADB 01/06/07
Logical L4NetworkManager::CheckBuffers(NetworkPacket *network_packet)
{
//char *current_receive_ptr;
int
// i,
// status,
host_count;
Logical get_buffer_status;
short space_left;
Host *host;
L4Host
//*l4host,
*remote_host;
//*l4_host_list[MULTIPLE_SEND_PACKET_MAX];
//MultipleReceivePacketRequestPtr multiple_receive_packet;
//MultipleReceivePacketReturnPtr multiple_receive_packet_return;
//SOCKET next_socket_ptr;
SET_CHECK_BUFFERS();
//
// Get pointers to the receive packet request structure
//
//multiple_receive_packet = (MultipleReceivePacketRequestPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//next_socket_ptr = multiple_receive_packet->Socket_Ptrs;
//multiple_receive_packet_return = (MultipleReceivePacketReturnPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//current_receive_ptr = multiple_receive_packet_return->Received_Data;
//
// Check some of the pointers we plan to use
//
Check(application);
Check(application->GetHostManager());
//
// Make an iterator to take us through all the hosts
//
HostManager::RemoteHostIterator remote_hosts(application->GetHostManager());
//
// See if there is ANY data available from the MUNGA buffers before we go
// looking for it from the network.
//
if(GetNextMungaPacket(network_packet,&remote_hosts))
{
CLEAR_CHECK_BUFFERS();
return True;
}
//
// Reset to the first host, then attempt to read from every host that has
// room in it's buffers for a packet
//
host_count = 0;
remote_hosts.First();
while ((host = remote_hosts.ReadAndNext()) != NULL)
{
// get the host pointer and cast it over to an l4 host. This is done so we can
// bang directly on the pad buffers stored in the host. Yes, it's ugly but it will
// be fixed in the future !!!! GAC
remote_host = Cast_Object(L4Host*, host);
Check(remote_host);
//
// Our first priority is to check connection status on any hosts that we haven't
// connected to yet. If we encounter a host who has connected we immediately
// generate and return the appropriate message for transmission via routepacket
//
switch(remote_host->GetConnectStatus())
{
case L4Host::NoNetworkConnectionStatus:
//
// No connection at all, we skip polling this guy for data
//
continue;
case L4Host::OpeningConnectionStatus:
{
SOCKADDR_IN stream_net_address, host_net_address;
//
// This checks a connection that was created with an active open.
// If there wasn't a connection, continue on to the next guy
//
if(!CheckSocket(remote_host->GetNetworkSocket(), &stream_net_address))
continue;
//
// Because we opened to a specific host address we should ALWAYS connect
// to the host we expected. If the address of the computer on the remote
// doesn't match the one we opened to, we scream loudly and fail.
//
host_net_address = *remote_host->GetNetworkAddress();
if(!(stream_net_address == host_net_address))
{
char addressString[44];
DWORD bufferSize = sizeof(addressString);
WSAAddressToStringA((LPSOCKADDR)&stream_net_address, sizeof(SOCKADDR_IN), NULL, addressString, &bufferSize);
DEBUG_STREAM << "Host " << addressString << std::flush;
bufferSize = sizeof(addressString);
WSAAddressToStringA((LPSOCKADDR)&host_net_address, sizeof(SOCKADDR_IN), NULL, addressString, &bufferSize);
DEBUG_STREAM << " client " << addressString << "\n";
Fail("For an OPEN the host MUST match the client or something is really messed up\n");
}
//
// Finish the process of opening the port up, then return False
// as if no packet was received
//
HostConnectedMessage myHostConnect(
remote_host->GetHostID(),
stream_net_address,
remote_host->GetNetworkSocket());
NetworkClient *client = GetNetworkClientPointer(NetworkManagerClientID);
Check(client);
client->ReceiveNetworkPacket(NULL, &myHostConnect);
CLEAR_CHECK_BUFFERS();
return(False);
}
case L4Host::ListeningConnectionStatus:
{
SOCKET tempSocket = INVALID_SOCKET;
SOCKADDR_IN net_address;
memset(&net_address, 0, sizeof(SOCKADDR_IN));
net_address.sin_family = AF_INET;
if(remote_host->GetHostType() == ConsoleHostType)
{
if((tempSocket = (SOCKET) NetTransport_Get()->Accept(consoleListenerSocket)) != INVALID_SOCKET)
{
NetTransport_Get()->Close(consoleListenerSocket);
consoleListenerSocket = INVALID_SOCKET;
}
}
else
{
if((tempSocket = (SOCKET) NetTransport_Get()->Accept(gameListenerSocket)) == INVALID_SOCKET)
{
continue;
}
}
remote_host->SetNetworkSocket(tempSocket);
if (!CheckSocket(remote_host->GetNetworkSocket(), &net_address))
continue;
char addressString[44];
DWORD bufferSize = sizeof(addressString);
WSAAddressToStringA((LPSOCKADDR)&net_address, sizeof(SOCKADDR_IN), NULL, addressString, &bufferSize);
DEBUG_STREAM << "STATUS: socket accepted from " << addressString << "!\n" << std::flush;
//
// The Waterloo TCP package has a problem with making connections. It always
// seems to connect people to the last socket that was listened on regardless
// of the port or net address settings. Because of this we have to make sure
// the connect we get belongs to the host we connected to, if it doesn't we
// have to find the right host and potentially swap the streams around. We
// also have to have a special case to handle listening for the console. Since
// we don't know the console machine's address in advance we (!!!!for now)
// assume we will only do a listen for the console if it's the only machine
// we're going to listen for.
//
Host *connect_host;
L4Host *connect_L4_host;
SOCKET swap_socket_ptr;
swap_socket_ptr = remote_host->GetNetworkSocket();
if(net_address == *remote_host->GetNetworkAddress())
{
//
// The address of the host that connected on this stream matched the one
// we were expecting (ie: port/network address filtering worked) so we
// just process it straight through. This should handle a host pretending
// to be a console and OPENing to another host.
//
HostConnectedMessage myHostConnect(
remote_host->GetHostID(),
net_address,
remote_host->GetNetworkSocket());
NetworkClient *client = GetNetworkClientPointer(NetworkManagerClientID);
Check(client);
client->ReceiveNetworkPacket(NULL, &myHostConnect);
}
else if(remote_host->GetHostType() == ConsoleHostType)
{
//
// This handles a LISTEN for a console with an unspecified net address
// Because the console uses a different port number than the game does
// whatever connects to a console host should be correct. So whoever
// shows up on this host should be a console (or thinks it is)
// NOTE: We actually set the host's net address here, since we didn't
// know it in advance.
//
remote_host->SetNetworkAddress(&net_address);
HostConnectedMessage myHostConnect(
remote_host->GetHostID(),
net_address,
remote_host->GetNetworkSocket());
NetworkClient *client = GetNetworkClientPointer(NetworkManagerClientID);
Check(client);
client->ReceiveNetworkPacket(NULL, &myHostConnect);
}
else
{
//
// The address of the host that connected didn't match the one we were
// expecting on this stream. So we have to find the right host and swap
// streams with them.
//
HostManager::RemoteHostIterator connect_hosts(application->GetHostManager());
while ((connect_host = connect_hosts.ReadAndNext()) != NULL)
{
connect_L4_host = Cast_Object(L4Host*, connect_host);
if(connect_L4_host->GetConnectStatus() != L4Host::ListeningConnectionStatus)
{
// skip hosts that are not currently listening since they are not
// candidates for swapping.
continue;
}
//
// If the address of this guy matches the address of the person who just
// connected, we swap their stream pointers
//
if(*connect_L4_host->GetNetworkAddress() == net_address)
{
remote_host->SetNetworkSocket(connect_L4_host->GetNetworkSocket());
connect_L4_host->SetNetworkSocket(swap_socket_ptr);
HostConnectedMessage myHostConnect(
connect_L4_host->GetHostID(),
net_address,
connect_L4_host->GetNetworkSocket());
NetworkClient *client = GetNetworkClientPointer(NetworkManagerClientID);
Check(client);
client->ReceiveNetworkPacket(NULL, &myHostConnect);
CLEAR_CHECK_BUFFERS();
return False;
}
}
}
CLEAR_CHECK_BUFFERS();
return False;
}
case L4Host::OnLineConnectionStatus:
// OnLine hosts just fall through so they can be polled
break;
default:
Fail("Host had illegal connection status\n");
break;
}
#if !BATCHED_RECEIVE
//
// If we get this far the host is on line, if there is room to do a receive
// into this buffer then do one.
//
//unsigned long *next_status_ptr = &(multiple_receive_packet_return->Status[0]);
space_left = (short)(remote_host->pad_size - remote_host->pad_tail);
if(space_left >= MAX_RECEIVE_DATA_SIZE)
{
// there was sufficient room for a receive to happen, so do it
// Setup the request in the common area
//Net_Common_Ptr->Function = NETNUB_RECEIVE_PACKET;
//Net_Common_Ptr->Buffer_Length = sizeof(ReceivePacketRequest);
//receive_packet_request = (ReceivePacketRequestPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//receive_packet_request->Socket_Ptr = remote_host->GetNetworkSocket();
// call the network server
//NetShare();
void* buffer = malloc(space_left);
// transport normalizes the would-block/reset cases:
// >0 = data, ReceiveDisconnected = drop, ReceiveNoData = nothing yet
int received = NetTransport_Get()->Receive(remote_host->GetNetworkSocket(), buffer, space_left);
// if we received data, copy it over into the buffer for this host
if(received > 0)
{
// copy the received data over to the host's data buffer
Mem_Copy(
&remote_host->pad_buffer[remote_host->pad_tail],
buffer,
received,
space_left);
remote_host->pad_tail += received;
}
if(received == NetTransport::ReceiveDisconnected)
{
{
HostDisconnectedMessage myHostDisconnected(
remote_host->GetHostID(),
remote_host->GetNetworkSocket());
NetworkClient *client = GetNetworkClientPointer(NetworkManagerClientID);
Check(client);
client->ReceiveNetworkPacket(NULL, &myHostDisconnected);
//break;
}
}
//default:
free(buffer);
}
}
#else
//
// If we get this far the host is on line, see if there is room to do a
// receive into it's buffer.
//
space_left = (short)( remote_host->pad_size - remote_host->pad_tail);
if(space_left >= MAX_RECEIVE_DATA_SIZE)
{
//
// There is room, add it to the list of hosts
//
l4_host_list[host_count++] = remote_host;
*(next_socket_ptr++) = remote_host->GetNetworkSocket();
// DEBUG_STREAM<<"Add stream "<<remote_host->GetNetworkSocket()<<"\n";
}
}
//
// Finish the request to netnub, then send it down
//
if(host_count == 0)
{
CLEAR_CHECK_BUFFERS();
return False;
}
// DEBUG_STREAM<<"Sending command to read "<<host_count<<" streams\n";
multiple_receive_packet->Socket_Count = host_count;
Net_Common_Ptr->Function = NETNUB_MULTIPLE_RECEIVE;
Net_Common_Ptr->Buffer_Length = sizeof(MultipleReceivePacketRequest);
NetNub::SendCommand();
//
// If NETNUB_OK comes back in status, it means we have no data and can quit
//
if(Net_Common_Ptr->Status == NETNUB_OK)
{
// DEBUG_STREAM<<"No data on any stream\n";
CLEAR_CHECK_BUFFERS();
return(False);
}
//
// One or more streams had data or errors
//
for(i = 0; i<host_count; i++)
{
l4host = l4_host_list[i];
status = multiple_receive_packet_return->Status[i];
// if(status != 0)
// DEBUG_STREAM<<"stream "<<l4host->GetNetworkSocket()<<" status "<<status<<"\n";
if(status == NETNUB_OK)
{
// No data or error here, go on to next host
continue;
}
else if(status == NETNUB_STREAM_DISCONNECTED)
{
HostDisconnectedMessage myHostDisconnected(
l4host->GetHostID(),
l4host->GetNetworkSocket());
NetworkClient *client = GetNetworkClientPointer(NetworkManagerClientID);
Check(client);
client->ReceiveNetworkPacket(NULL, &myHostDisconnected);
}
else if(status < 0)
{
// error of some kind, handle it
DEBUG_STREAM<<"MUNGA reported network error "<<status<<"\n";
Fail("MUNGA network error");
}
else
{
// there was data in the message
// copy the received data over to the host's data buffer
Mem_Copy(
&l4host->pad_buffer[l4host->pad_tail],
current_receive_ptr,
status,
(short)(l4host->pad_size - l4host->pad_tail));
l4host->pad_tail += (Word)status;
current_receive_ptr += status;
}
}
#endif
//
// Now loop through all the hosts again till we find one with a complete munga
// message to be returned for processing by the host.
//
get_buffer_status = GetNextMungaPacket(network_packet,&remote_hosts);
CLEAR_CHECK_BUFFERS();
return(get_buffer_status);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// GetNextMungaPacket Checks the internal MUNGA packet assembly buffers to
// see if there are packets available on any open stream
//
Logical
L4NetworkManager::GetNextMungaPacket(
NetworkPacket *network_packet,
HostManager::RemoteHostIterator *remote_hosts)
{
short
i,
host_count,
move_size,
receive_packet_size;
Host
*host;
L4Host
*remote_host;
NetworkPacket
*incoming_packet;
//
// Loop through all the hosts and check their buffers
//
host_count = (short)remote_hosts->GetSize();
for(
i = 0;
i < host_count;
i++)
{
//
// This causes us to start checking hosts where we left off the last time
// it prevents any one host from always getting serviced first.
//
lastHostIteratorPosition++;
if(lastHostIteratorPosition >= remote_hosts->GetSize())
{
lastHostIteratorPosition = 0;
}
if((host = remote_hosts->GetNth(lastHostIteratorPosition)) == NULL)
{
break;
}
//
// get the host pointer and cast it over to an l4 host so we can look at it's buffers
//
remote_host = Cast_Object(L4Host*, host);
Check(remote_host);
//
// If we're in ConsoleOnly state, don't return messages for non-console streams
//
if((currentNetworkState == ConsoleOnly) &&
(remote_host->GetHostType() != ConsoleHostType))
continue;
//
// does this host data buffer contain a complete munga message header
//
if(remote_host->pad_tail >= sizeof(NetworkPacket))
{
//
// enough bytes for a complete message header, read the message length and
// figure how many bytes the complete packet should be
//
incoming_packet = (NetworkPacket*)remote_host->pad_buffer;
receive_packet_size = (short)(incoming_packet->messageData.messageLength + sizeof(NetworkPacketHeader));
Verify(receive_packet_size > 0);
// Are there enough bytes in the buffer to make up this packet?
if(remote_host->pad_tail >= receive_packet_size)
{
// we have a complete packet, copy it into the output buffer and rejustify the host's
// buffer (inefficient as hell but easy to write for now)
Mem_Copy(
network_packet,
remote_host->pad_buffer,
receive_packet_size,
NETWORKMANAGER_BUFFER_SIZE);
move_size = (short)(remote_host->pad_tail - receive_packet_size);
// don't do the next step if the buffer is empty
// we need to use memmove because the source and destination addresses overlap
// and memcopy doesn't know how to deal with that.
Verify(move_size < L4HOST_PAD_BUFFER_SIZE);
if(move_size != 0)
{
memmove(
remote_host->pad_buffer,
&remote_host->pad_buffer[receive_packet_size],
move_size);
}
remote_host->pad_tail -= receive_packet_size;
// Return true (packet received)
return True;
}
else
{
// cout<<"++++++++Waiting for "<<receive_packet_size<<" byte packet, got"<<remote_host->pad_tail<<"\n";
}
}
}
//
// If we get here, all the streams were empty
//
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::RemovePacket If the network implimentation requires us to
// free up a packet buffer, this routine would do it.
//
void
L4NetworkManager::RemovePacket(NetworkPacket*)
{
//
// This function is not required for now
//
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::NetShare This is Gene's implementation of the protected
// to real mode interface.
//
//WinSock support :ADB 01/06/07
//void NetNub::SendCommand()
//{
// struct RMREG
// rmreg;
// union REGS
// regs;
// struct SREGS
// sregs;
//
// SET_CALL_NETNUB();
// //
// // Check a few things before making the DPMI call to the interrupt
// //
// Verify(Net_Common_Ptr->Buffer_Length <= SHARED_MEMORY_SIZE);
// //
// // This assembly routine copies the contents of the NetCommon down into real mode
// //
// setRMBuff();
// //
// // Setup for the call to the DPMI to simulate real mode interrupt
// //
// regs.x.eax = 0x0300; // function of INT31
// regs.h.bl = intno; //
// regs.h.bh = 0; //flags
// regs.x.ecx = 0; //number of words to copy from protected mode to real mode stack
// regs.x.edi =(unsigned int)&rmreg; //es:edi is an address of RMREG structure
// segread(&sregs);
// rmreg.reserved = 0; //default settings:
// rmreg.fs = 0;
// rmreg.gs = 0;
// rmreg.flags = 0;
// rmreg.ss = 0; //real mode stack is provided by DPMI unless ss:sp != 0
// rmreg.sp = 0;
// //
// // Call the DPMI
// //
// int386x(0x31,&regs,&regs,&sregs);
// //
// // Check for an error
// //
// if (regs.x.cflag)
// {
// DEBUG_STREAM<<"int386x():ERROR="<<regs.x.eax<<endl;
// Fail("Error calling netnub\n");
// }
// //
// // Copy the real mode data back up into the protected mode common area
// //
// getRMBuff();
// //
// // Check the version number before returning
// //
// Verify(Net_Common_Ptr->Version_Number == NETCOM_VERSION);
// CLEAR_CALL_NETNUB();
//}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~Encapsulations of netnub calls~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::GetMyAddress This routine calls the netnub and returns
// our network address if everything is ok or zero if it's not. It can also be
// used to tickle the netnub or to check status of the netnub.
//
//WinSock support :ADB 01/06/07
NetworkAddress* L4NetworkManager::GetMyAddress()
{
// the transport owns interface enumeration (it appends loopback)
enum { maxLocalAddresses = 16 };
unsigned long local_addresses[maxLocalAddresses];
int count = NetTransport_Get()->GetLocalAddresses(local_addresses, maxLocalAddresses);
if (count <= 0)
{
return NULL;
}
NetworkAddress* myAddresses = new NetworkAddress[count];
for (int i=0; i<count; i++)
myAddresses[i] = (NetworkAddress) local_addresses[i];
num_addresses = count;
return myAddresses;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::ResolveAddress This routine takes a CString containing
// a host name and makes the appropriate network calls to resolve it to a
// binary internet address.
//
//WinSock support :ADB 01/06/07
bool L4NetworkManager::ResolveAddress(CString host_name, SOCKADDR_IN *address)
{
// numeric ip[:port]; the game port fills in when none was given
// (the old DNS/getaddrinfo path below the early return was dead)
NetTransport_Get()->Resolve((LPSTR)host_name, address);
if (address->sin_port == 0)
address->sin_port = htons(GAME_NET_PORT);
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::CheckSocket This routine does checks a socket and returns
// the state of that socket (connected or not)
//
//WinSock support :ADB 01/06/07
bool L4NetworkManager::CheckSocket(SOCKET socket, SOCKADDR_IN *remoteEndpoint)
{
if (remoteEndpoint)
{
if (NetTransport_Get()->GetRemoteAddress(socket, remoteEndpoint))
return true;
}
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::OpenConnection This routine does the appropriate calls to
// start the open process for another host. You can do an active or passive open
// with this routine by passing the appropriate parameters in. The arguments
// are geared to the typical TCP/IP connection parameters. After calling this
// routine you must create the host yourself.
//
//WinSock support :ADB 01/06/07
//unsigned long OpenConnection(
SOCKET L4NetworkManager::OpenConnection(
int connection_type, // NETNUB_TCP_LISTEN or NETNUB_TCP_OPEN
int local_port,
int remote_port,
int internet_address)
{
//TCPOpenRequestPtr
// tcp_open_request;
//TCPOpenReturnPtr
// tcp_open_return;
//
// Checkup everything
//
//Check_Pointer(Net_Common_Ptr);
//
// Make sure we are using a legal open mode
//
Verify( (connection_type == NETNUB_TCP_LISTEN) ||
(connection_type == NETNUB_TCP_OPEN));
//
// Format the open/listen request
//
//tcp_open_request = (TCPOpenRequestPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//tcp_open_return = (TCPOpenReturnPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//Net_Common_Ptr->Function = (short)connection_type;
//Net_Common_Ptr->Buffer_Length = sizeof(TCPOpenRequest);
//tcp_open_request->Local_Port = (short)local_port;
//tcp_open_request->Remote_Port = (short)remote_port;
//tcp_open_request->Internet_Address = internet_address;
//tcp_open_request->Socket_Ptr = 0; // !!! 0 causes netnub to allocate socket
//NetNub::SendCommand();
//if(Net_Common_Ptr->Status == NETNUB_ERROR)
//{
// DEBUG_STREAM<<"NetNub TCP Open/Listen error #"<<tcp_open_return->Socket_Ptr<<" listening for ";
// DEBUG_STREAM<<((internet_address>>24) & 0xff)<<"."<<((internet_address>>16) & 0xff)<<".";
// DEBUG_STREAM<<((internet_address>>8) & 0xff)<<"."<<(internet_address & 0xff)<<"\n";
// Fail("Netnub error during open/listen\n");
//}
//return(tcp_open_return->Socket_Ptr);
if(connection_type == NETNUB_TCP_OPEN)
{
sockaddr_in remoteEndpoint;
memset(&remoteEndpoint, 0, sizeof(remoteEndpoint));
remoteEndpoint.sin_family = AF_INET;
//VERIFY: Network vs Host byte order?
remoteEndpoint.sin_addr.S_un.S_addr = internet_address;
remoteEndpoint.sin_port = htons(remote_port);
return (SOCKET) NetTransport_Get()->Connect(&remoteEndpoint, local_port);
}
else if(connection_type == NETNUB_TCP_LISTEN)
{
if(gameListenerSocket == NULL)
{
gameListenerSocket = (SOCKET) NetTransport_Get()->Listen(local_port, 25);
if(gameListenerSocket == INVALID_SOCKET)
{
DEBUG_STREAM << "ERROR: Could not open the game listener on port " << local_port << "!\n" << std::flush;
PostQuitMessage(AbortExitCodeID);
}
}
else
DEBUG_STREAM << "Listen requested on port " << local_port << " but gameListenerSocket already existed!\n" << std::flush;
return INVALID_SOCKET;
}
else
return INVALID_SOCKET;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::CloseConnection This routine does the appropriate calls to
// close a connection to another host, it really should wait for an error return
// but doesn't right now.
//
//WinSock support :ADB 01/06/07
void L4NetworkManager::CloseConnection(SOCKET socket_ptr) // socket address from netnub (to close)
{
//TCPCloseRequestPtrclose_request;
//
// Checkup everything
//
Check_Pointer(Net_Common_Ptr);
//
// Do the actual close
//
//Net_Common_Ptr->Function = NETNUB_TCP_CLOSE;
//Net_Common_Ptr->Buffer_Length = sizeof(TCPCloseRequest);
//close_request = (TCPCloseRequestPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//close_request->Socket_Ptr = socket_ptr;
//NetNub::SendCommand();
NetTransport_Get()->Close(socket_ptr);
// Check for errors
//if(Net_Common_Ptr->Status != NETNUB_OK)
//{
// DEBUG_STREAM<<"NetNub close error "<<Net_Common_Ptr->Status<<" on stream "<<socket_ptr<<"\n";
// return;
//}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::Mode does mode settings on the network interface
//
//WinSock support :ADB 01/06/07
void L4NetworkManager::Mode(NetworkMode myMode)
{
//SetSwitchesRequestPtr set_switches_request;
//
// No netnub present? Just return
//
//if(Net_Common_Ptr == NULL)
if(wsaData == NULL)
{
return;
}
//
// Checkup everything
//
//Check_Pointer(Net_Common_Ptr);
//
// Copy the text over (including the 0 terminator)
//
//set_switches_request = (SetSwitchesRequestPtr)Net_Common_Ptr->Shared_Memory_Buffer;
//switch(myMode)
//{
// case ReliableMode:
// set_switches_request->blocking_switch = True;
// break;
// case UnreliableMode:
// set_switches_request->blocking_switch = False;
// break;
//}
//Net_Common_Ptr->Function = NETNUB_SET_SWITCHES;
//Net_Common_Ptr->Buffer_Length = sizeof(SetSwitchesRequest);
//NetNub::SendCommand();
//// Check for errors
//if(Net_Common_Ptr->Status != NETNUB_OK)
//{
// DEBUG_STREAM<<"NetNub mode call failed\n";
// return;
//}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// L4NetworkManager::Marker This routine does the appropriate calls to send
// a text marker down to netnub
//
//WinSock support :ADB 01/06/07
void L4NetworkManager::Marker(char *marker_text) // text message to send down
{
//int
// marker_text_size;
////
//// No netnub present? Just return
// //
//if(Net_Common_Ptr == NULL)
//{
// return;
//}
////
//// Checkup everything
////
//Check_Pointer(Net_Common_Ptr);
////
//// Copy the text over (including the 0 terminator)
////
//marker_text_size = strlen(marker_text)+1;
//Mem_Copy(
// (char*)Net_Common_Ptr->Shared_Memory_Buffer,
// marker_text,
// marker_text_size,
// SHARED_MEMORY_SIZE);
//Net_Common_Ptr->Function = NETNUB_MARKER_TEXT;
//Net_Common_Ptr->Buffer_Length = (short)marker_text_size;
//NetNub::SendCommand();
//// Check for errors
//if(Net_Common_Ptr->Status != NETNUB_OK)
//{
// DEBUG_STREAM<<"NetNub marker text call failed\n";
// return;
//}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
L4NetworkManager::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
#ifdef TEST_CLASS
#include "l4net.tcp"
#endif
#if 0
else if(networkStartupMode == MasterMode && remoteHostCount > 0)
{
enum ConsoleState
{
GetNextHostConsoleState,
OpenNextHostConsoleState,
WaitForConnectConsoleState,
SendEggConsoleState,
WaitForEggAckConsoleState,
WaitForGameConnectConsoleState,
CloseStreamConsoleState,
WaitForAllHostsConsoleState,
DoneConsoleState
};
long
size_of_notation_text;
int
game_machine_up_count;
ConsoleState
consoleState;
NetworkAddress
temp_net_address;
char
*temp_notation_text;
Host
*host;
NotationFile
*temp_notation_file;
//
// Master must send the egg to the other hosts and wait for each to acknowledge
// it's processing before going on to the next host. First we turn the notation
// file into text so we can send it.
//
temp_notation_file = new NotationFile(GlobalEggFileName);
Register_Object(temp_notation_file);
if(temp_notation_file->PageCount() == 0)
{
Fail("Tried to startup with an empty notation file\n");
}
size_of_notation_text = temp_notation_file->SizeOfText();
temp_notation_text = new char[size_of_notation_text];
Register_Pointer(temp_notation_text);
temp_notation_file->WriteText(
temp_notation_text,
size_of_notation_text);
//
// Now setup and run the state machine till everyone has been connected.
//
HostManager::RemoteHostIterator remote_hosts(application->GetHostManager());
currentNetworkState = ConsoleOnly;
eggAcknowledged = False;
consoleState = GetNextHostConsoleState;
while ( consoleState != DoneConsoleState && remoteHostCount > 0)
{
//
// Poll the network (the arrival times of these measages are complicated
// so I don't advise messing with the order of this loop casually)
//
RoutePacket();
//
// Do what we're supposed to based on our current state
//
switch(consoleState)
{
case GetNextHostConsoleState:
//
// Get the next game machine host
//
Tell("GetNextHostConsoleState--Getting next host\n");
game_machine_up_count = numberOfMungaHostsConnected;
remote_hosts.First();
while((host = remote_hosts.ReadAndNext()) != NULL)
{
L4Host* an_l4host = Cast_Object(L4Host*, host);
if(an_l4host->GetHostType() == ConsoleHostType ||
an_l4host->GetConnectStatus() == L4Host::NoNetworkConnectionStatus ||
an_l4host->GetConnectStatus() == L4Host::OnLineConnectionStatus)
continue;
if(an_l4host->GetHostType() == GameMachineHostType)
break;
}
if(host == NULL)
{
consoleState = WaitForAllHostsConsoleState;
}
else
{
consoleState = OpenNextHostConsoleState;
}
break;
case OpenNextHostConsoleState:
// Get the network address of this game machine host and open it
temp_net_address = host->GetNetworkAddress();
Tell("OpenNextHostConsoleState--Opening console to ");
Tell(((temp_net_address>>24) & 0xff)<<"."<<((temp_net_address>>16) & 0xff)<<".");
Tell(((temp_net_address>>8) & 0xff)<<"."<<(temp_net_address & 0xff)<<"\n");
socket_ptr = OpenConnection(
NETNUB_TCP_OPEN,
0,
CONSOLE_NET_PORT,
temp_net_address);
// Create a console host for this guy
myConsoleHost = new L4Host(
FirstLegalHostID,
ConsoleHostType,
temp_net_address,
socket_ptr,
"Console");
Register_Object(myConsoleHost);
// Register the console host with the host manager
Check(application);
Check(application->GetHostManager());
application->GetHostManager()->AdoptRemoteHost(myConsoleHost);
myConsoleHost->SetConnectStatus(L4Host::OpeningConnectionStatus);
numberOfConsoleHostsConnected = 0;
consoleState = WaitForConnectConsoleState;
break;
case WaitForConnectConsoleState:
Tell("C"<<numberOfMungaHostsConnected);
if(numberOfConsoleHostsConnected != 0)
{
consoleState = SendEggConsoleState;
Tell("\nWaitForConnectConsoleState--Connected\n");
}
break;
case SendEggConsoleState:
{
int
bytes_left,
next_send,
sequence;
next_send = 0;
sequence = 0;
// Verify(size_of_notation_text < 1000);
while(next_send < size_of_notation_text)
{
Tell("Sent Egg message #"<<sequence<<"\n");
bytes_left = size_of_notation_text - next_send;
if(bytes_left > 1000)
bytes_left = 1000;
ReceiveEggFileMessage myEggMessage(
sequence,
size_of_notation_text,
temp_notation_text + next_send,
bytes_left);
Send(
&myEggMessage,
NetworkClient::NetworkManagerClientID,
myConsoleHost->GetHostID());
next_send += bytes_left;
sequence++;
}
eggAcknowledged = False;
consoleState = WaitForEggAckConsoleState;
break;
}
case WaitForEggAckConsoleState:
Tell("E"<<numberOfMungaHostsConnected);
if(eggAcknowledged)
{
consoleState = WaitForGameConnectConsoleState;
DEBUG_STREAM<<"\nWaitForEggAckConsoleState--Got one from";
DEBUG_STREAM<<((temp_net_address>>24) & 0xff)<<"."<<((temp_net_address>>16) & 0xff)<<".";
DEBUG_STREAM<<((temp_net_address>>8) & 0xff)<<"."<<(temp_net_address & 0xff)<<"\n";
}
break;
case WaitForGameConnectConsoleState:
Tell("G"<<numberOfMungaHostsConnected);
if(game_machine_up_count < numberOfMungaHostsConnected)
{
consoleState = CloseStreamConsoleState;
Tell("\nWaitForGameConnectConsoleState--Got one\n");
}
break;
case CloseStreamConsoleState:
{
Tell("CloseStreamConsoleState -- closing console\n");
#if 0
HostDisconnectedMessage myHostDisconnected;
Send(
&myHostDisconnected,
NetworkClient::NetworkManagerClientID,
myConsoleHost->GetHostID());
#endif
Check(myConsoleHost);
CloseConnection(myConsoleHost->GetNetworkSocket());
// deregister this host with the host manager
application->GetHostManager()->OrphanRemoteHost(myConsoleHost);
Unregister_Object(myConsoleHost);
delete myConsoleHost;
myConsoleHost = NULL;
consoleState = GetNextHostConsoleState;
break;
}
case WaitForAllHostsConsoleState:
Tell("W"<<numberOfMungaHostsConnected);
if(numberOfMungaHostsConnected >= remoteHostCount)
{
consoleState = DoneConsoleState;
Tell("\WaitForAllHostsConsoleState--done connecting\n");
}
break;
}
}
Unregister_Pointer(temp_notation_text);
delete temp_notation_text;
Unregister_Object(temp_notation_file);
delete temp_notation_file;
currentNetworkState = NormalState;
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~ MessageQueue__SendRequest ~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MessageQueue__SendRequest::MessageQueue__SendRequest(
NetworkClient::ClientID client_ID,
Receiver::Message *message
)
{
//
// Set client ID
//
clientID = client_ID;
//
// Store the message
//
Check(message);
messageToSend = (Receiver::Message*)new char[message->messageLength];
Register_Pointer(messageToSend);
Mem_Copy(
messageToSend,
message,
message->messageLength,
message->messageLength
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MessageQueue__SendRequest::~MessageQueue__SendRequest()
{
Unregister_Pointer(messageToSend);
delete messageToSend;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
MessageQueue__SendRequest::TestInstance() const
{
Check_Pointer(messageToSend);
return True;
}
//~~~~~~~~~~~~~~~~~~~~ HostMessageBuffer__MessageQueue ~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
HostMessageBuffer__MessageQueue::HostMessageBuffer__MessageQueue(
HostID host_ID
):
sendRequestSocket(NULL)
{
hostID = host_ID;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
HostMessageBuffer__MessageQueue::~HostMessageBuffer__MessageQueue()
{
ChainIteratorOf<SendRequest*>
iterator(&sendRequestSocket);
iterator.DeletePlugs();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
HostMessageBuffer__MessageQueue::TestInstance() const
{
Check(&sendRequestSocket);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
HostMessageBuffer__MessageQueue::AddSendRequest(
NetworkClient::ClientID client_ID,
Receiver::Message *message
)
{
Check(this);
Check(message);
//
// Create new send request and add it to the socket
//
SendRequest
*send_request;
send_request = new SendRequest(client_ID, message);
Register_Object(send_request);
sendRequestSocket.Add(send_request);
}
//~~~~~~~~~~~~~~~~~~~~ L4NetworkManager__MessageBuffer ~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
L4NetworkManager__MessageBuffer::L4NetworkManager__MessageBuffer(
L4NetworkManager *network_manager
):
messageQueueSocket(NULL, True)
{
networkManager = network_manager;
currentQueueIndex = 0;
bufferSize = 0;
#ifdef LAB_ONLY
messageCount = 0;
maxBufferSize = 0;
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
L4NetworkManager__MessageBuffer::~L4NetworkManager__MessageBuffer()
{
TableIteratorOf<MessageQueue*, HostID>
iterator(&messageQueueSocket);
iterator.DeletePlugs();
#ifdef LAB_ONLY
cout << "L4NetworkManager__MessageBuffer::" <<
"~L4NetworkManager__MessageBuffer" <<
" messageCount=" << messageCount << "\n";;
cout << "L4NetworkManager__MessageBuffer::" <<
"~L4NetworkManager__MessageBuffer" <<
" maxBufferSize=" << maxBufferSize << "\n";;
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
L4NetworkManager__MessageBuffer::TestInstance() const
{
Check(&messageQueueSocket);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
L4NetworkManager__MessageBuffer::AddSendRequest(
HostID host_ID,
NetworkClient::ClientID client_ID,
Receiver::Message *message
)
{
Check(this);
Check(message);
//
// Get this hosts message queue
//
MessageQueue
*message_queue;
if ((message_queue = messageQueueSocket.Find(host_ID)) == NULL)
{
message_queue = new MessageQueue(host_ID);
Register_Object(message_queue);
messageQueueSocket.AddValue(message_queue, host_ID);
}
Check(message_queue);
//
// Add the send request
//
message_queue->AddSendRequest(client_ID, message);
bufferSize++;
#ifdef LAB_ONLY
messageCount++;
maxBufferSize = Max(maxBufferSize, bufferSize);
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
L4NetworkManager__MessageBuffer::AttemptToSend()
{
Check(this);
//
//--------------------------------------------------------------------------
// Verify that there exist non-empty queues and that the buffer size is
// correct
//--------------------------------------------------------------------------
//
#if DEBUG_LEVEL>0
{
TableIteratorOf<MessageQueue*, HostID>
iterator(&messageQueueSocket);
MessageQueue
*message_queue;
CollectionSize
counter = 0;
while ((message_queue = iterator.ReadAndNext()) != NULL)
{
Check(message_queue);
ChainIteratorOf<MessageQueue::SendRequest*>
message_iterator(&message_queue->sendRequestSocket);
counter += message_iterator.GetSize();
}
Verify(counter > 0);
Verify(counter == bufferSize);
}
#endif
//
//--------------------------------------------------------------------------
// Increment the index to the next non-empty queue
//--------------------------------------------------------------------------
//
TableIteratorOf<MessageQueue*, HostID>
queue_iterator(&messageQueueSocket);
MessageQueue
*message_queue;
MessageQueue::SendRequest
*send_request;
do
{
//
// Increment the counter
//
if (++currentQueueIndex >= queue_iterator.GetSize())
currentQueueIndex = 0;
//
// Get the message queue
//
message_queue = queue_iterator.GetNth(currentQueueIndex);
Check(message_queue);
//
// Get the message
//
ChainIteratorOf<MessageQueue::SendRequest*>
message_iterator(&message_queue->sendRequestSocket);
send_request = message_iterator.GetCurrent();
}
while (send_request == NULL);
Check(send_request);
//
//--------------------------------------------------------------------------
// Attempt to send
//--------------------------------------------------------------------------
//
Check(networkManager);
if (
networkManager->SendMessageToNetnub(
send_request->messageToSend,
send_request->clientID,
message_queue->hostID
)
)
{
Unregister_Object(send_request);
delete send_request;
bufferSize--;
}
}