Imports the current Win32 source for the pod-racing game 'Red Planet', built on the MUNGA engine and its L4 (Win32/DirectX) platform layer: - MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend - RP / RP_L4: Red Planet game logic and Win32 application - DivLoader, Setup1: asset loader and installer project - lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies Removed stale Subversion metadata and added .gitignore/.gitattributes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3447 lines
103 KiB
C++
3447 lines
103 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 "..\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;
|
|
|
|
int iResult = WSAStartup(MAKEWORD(2,2), wsaData);
|
|
if(iResult != NO_ERROR)
|
|
{
|
|
DEBUG_STREAM << "ERROR: WSAStartup() failed with " << iResult << "!\n" << std::flush;
|
|
WSACleanup();
|
|
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";
|
|
WSACleanup();
|
|
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(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if(consoleListenerSocket == INVALID_SOCKET)
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not create console listener socket; socket() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
return;
|
|
}
|
|
sockaddr_in localEndpoint;
|
|
memset(&localEndpoint, 0, sizeof(localEndpoint));
|
|
localEndpoint.sin_family = AF_INET;
|
|
localEndpoint.sin_port = htons(networkPort);
|
|
localEndpoint.sin_addr.S_un.S_addr = INADDR_ANY;
|
|
if(bind(consoleListenerSocket, (sockaddr*)&localEndpoint, sizeof(localEndpoint)))
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not bind console listener socket; bind() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
return;
|
|
}
|
|
if(listen(consoleListenerSocket, 1))
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not listen on console listener socket; listen() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
return;
|
|
}
|
|
//set to non blocking
|
|
unsigned long enable = 1;
|
|
if(ioctlsocket(consoleListenerSocket, FIONBIO, &enable))
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not set console listener socket to nonblocking; ioctlsocket() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
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::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;
|
|
int bufferSize = sizeof(SOCKADDR_IN);
|
|
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);
|
|
WSAStringToAddressA((LPSTR)host_name, AF_INET, NULL, (LPSOCKADDR)&net_address, &bufferSize);
|
|
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;
|
|
}
|
|
|
|
WSACleanup();
|
|
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.
|
|
//
|
|
shutdown(gameListenerSocket, SD_BOTH);
|
|
closesocket(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();
|
|
send(l4host->GetNetworkSocket(), (char *)my_temp_packet, packet_size, 0);
|
|
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();
|
|
send(receiving_host->GetNetworkSocket(), (char *)network_packet, munga_network_message_size, 0);
|
|
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++)
|
|
{
|
|
send(l4host_array[i]->GetNetworkSocket(), (char *)network_packet, sizeof(network_packet), 0);
|
|
}
|
|
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 = accept(consoleListenerSocket, NULL, 0)) != INVALID_SOCKET)
|
|
{
|
|
closesocket(consoleListenerSocket);
|
|
consoleListenerSocket = INVALID_SOCKET;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((tempSocket = accept(gameListenerSocket, NULL, 0)) == 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);
|
|
int received = recv(remote_host->GetNetworkSocket(), (char*)buffer, space_left, 0);
|
|
// if we received data, copy it over into the buffer for this host
|
|
//switch(Net_Common_Ptr->Status)
|
|
if(received > 0)
|
|
{
|
|
//case NETNUB_RECEIVED_PACKET:
|
|
// copy the received data over to the host's data buffer
|
|
Mem_Copy(
|
|
&remote_host->pad_buffer[remote_host->pad_tail],
|
|
//Net_Common_Ptr->Shared_Memory_Buffer,
|
|
buffer,
|
|
//Net_Common_Ptr->Buffer_Length,
|
|
received,
|
|
space_left);
|
|
//remote_host->pad_tail += Net_Common_Ptr->Buffer_Length;
|
|
remote_host->pad_tail += received;
|
|
//break;
|
|
}
|
|
//case NETNUB_OK:
|
|
else if(received == SOCKET_ERROR)
|
|
{
|
|
//this indicates that no data is available and the socket is non blocking
|
|
//break;
|
|
DWORD error = WSAGetLastError();
|
|
switch (error)
|
|
{
|
|
case WSAECONNRESET:
|
|
// this will cause us to execute our disconnect code
|
|
received = 0;
|
|
break;
|
|
case WSAEWOULDBLOCK:
|
|
// this is expected when there is no data
|
|
break;
|
|
default:
|
|
DEBUG_STREAM << "L4NetworkManager::CheckBuffers: Socket recv returned an unexpected error: WSAGetLastError = " << error << std::endl << std::flush;
|
|
}
|
|
}
|
|
// case NETNUB_STREAM_DISCONNECTED:
|
|
if(received == 0)
|
|
{
|
|
{
|
|
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,®s,®s,&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()
|
|
{
|
|
char name[255];
|
|
PHOSTENT hostinfo;
|
|
|
|
if (gethostname(name, sizeof(name)) != 0)
|
|
{
|
|
DEBUG_STREAM << "ERROR: gethostname() failed!" << std::endl << std::flush;
|
|
return NULL;
|
|
}
|
|
|
|
if ((hostinfo = gethostbyname(name)) == NULL)
|
|
{
|
|
DEBUG_STREAM << "ERROR: gethostbyname() failed!" << std::endl << std::flush;
|
|
return NULL;
|
|
}
|
|
|
|
// count how many addresses we have
|
|
for (num_addresses = 0; hostinfo->h_addr_list[num_addresses]; num_addresses++);
|
|
|
|
NetworkAddress* myAddresses = new NetworkAddress[num_addresses + 1];
|
|
for (int i=0; i<num_addresses; i++)
|
|
myAddresses[i] = *((NetworkAddress*)hostinfo->h_addr_list[i]);
|
|
|
|
// add 127.0.0.1 to list
|
|
myAddresses[num_addresses++] = (NetworkAddress)0x0100007F;
|
|
|
|
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)
|
|
{
|
|
//if (strstr(host_name, ":"))
|
|
{
|
|
// this address contains a colon so we'll do things a little differently
|
|
int bufferSize = sizeof(SOCKADDR_IN);
|
|
WSAStringToAddressA((LPSTR)host_name, AF_INET, NULL, (LPSOCKADDR)address, &bufferSize);
|
|
if (address->sin_port == 0)
|
|
address->sin_port = htons(GAME_NET_PORT);
|
|
return true;
|
|
}
|
|
|
|
addrinfo* hostAddrinfo = NULL;
|
|
addrinfo aiHints;
|
|
memset(&aiHints, 0, sizeof(aiHints));
|
|
aiHints.ai_family = AF_INET;
|
|
aiHints.ai_socktype = SOCK_STREAM;
|
|
aiHints.ai_protocol = IPPROTO_TCP;
|
|
|
|
int iResult = getaddrinfo((char*)host_name, NULL, &aiHints , &hostAddrinfo);
|
|
if(iResult != 0)
|
|
{
|
|
DEBUG_STREAM<<"ERROR: getaddrinfo() failed with " << WSAGetLastError() << "!\n";
|
|
return NULL;
|
|
}
|
|
|
|
addrinfo* addr = hostAddrinfo;
|
|
while(addr != NULL)
|
|
{
|
|
if(addr->ai_addr->sa_family == AF_INET)
|
|
break;
|
|
addr = addr->ai_next;
|
|
}
|
|
|
|
memset(address, 0, sizeof(SOCKADDR_IN));
|
|
*address = *((sockaddr_in*)&addr->ai_addr->sa_data);
|
|
if (address->sin_port == 32778)
|
|
address->sin_port = htons(CONSOLE_NET_PORT);
|
|
|
|
freeaddrinfo(hostAddrinfo);
|
|
|
|
//
|
|
// Check the status returns and return the address if we got one ok
|
|
//
|
|
if(!address || address->sin_addr.S_un.S_addr == 0 || address->sin_port == 0)
|
|
{
|
|
DEBUG_STREAM << "Couldn't resolve " << host_name << " to a net address\n";
|
|
Fail("unresolvable network address\n");
|
|
}
|
|
|
|
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)
|
|
{
|
|
int size = sizeof(SOCKADDR_IN);
|
|
memset(remoteEndpoint, 0, size);
|
|
if(!getpeername(socket, (sockaddr*)remoteEndpoint, &size))
|
|
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)
|
|
{
|
|
DEBUG_STREAM << "Opening connection to " << inet_ntoa(*(in_addr*)&internet_address) << ":" << remote_port << "...\n" << std::flush;
|
|
|
|
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if(sock == INVALID_SOCKET)
|
|
{
|
|
DEBUG_STREAM << "ERROR: socket() failed with " << WSAGetLastError() << "!\n";
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
bool reuseAddr = true;
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&reuseAddr, sizeof(bool)))
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not set SO_REUSEADDR on socket; setsockopt() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
sockaddr_in localEndpoint;
|
|
memset(&localEndpoint, 0, sizeof(localEndpoint));
|
|
localEndpoint.sin_family = AF_INET;
|
|
localEndpoint.sin_port = htons(local_port);
|
|
localEndpoint.sin_addr.S_un.S_addr = INADDR_ANY;
|
|
if(bind(sock, (sockaddr*)&localEndpoint, sizeof(localEndpoint)))
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not bind local socket; bind() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
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);
|
|
int wsaError, iResult;
|
|
|
|
do
|
|
{
|
|
iResult = connect(sock, (sockaddr*)&remoteEndpoint, sizeof(remoteEndpoint));
|
|
|
|
if (iResult != 0)
|
|
{
|
|
wsaError = WSAGetLastError();
|
|
}
|
|
} while (iResult != 0 && wsaError == 10061);
|
|
|
|
if(iResult != 0)
|
|
{
|
|
DEBUG_STREAM << "ERROR: connect() failed with " << wsaError << "!\n" << std::flush;
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
//set to non blocking
|
|
unsigned long enable = 1;
|
|
if(ioctlsocket(sock, FIONBIO, &enable))
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not set actively opened socket to nonblocking; ioctlsocket() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
}
|
|
return sock;
|
|
}
|
|
else if(connection_type == NETNUB_TCP_LISTEN)
|
|
{
|
|
if(gameListenerSocket == NULL)
|
|
{
|
|
DEBUG_STREAM << "Starting to listen on port " << local_port << "...\n" << std::flush;
|
|
|
|
gameListenerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if(gameListenerSocket == INVALID_SOCKET)
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not create game listener socket; socket() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
}
|
|
|
|
bool reuseAddr = true;
|
|
if (setsockopt(gameListenerSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuseAddr, sizeof(bool)))
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not set SO_REUSEADDR on game listener socket; setsockopt() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
sockaddr_in localEndpoint;
|
|
memset(&localEndpoint, 0, sizeof(localEndpoint));
|
|
localEndpoint.sin_family = AF_INET;
|
|
localEndpoint.sin_port = htons(local_port);
|
|
localEndpoint.sin_addr.S_un.S_addr = INADDR_ANY;
|
|
if(bind(gameListenerSocket, (sockaddr*)&localEndpoint, sizeof(localEndpoint)))
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not bind game listener socket; bind() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
return INVALID_SOCKET;
|
|
}
|
|
if(listen(gameListenerSocket, 25))
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not listen on game listener socket; listen() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
return INVALID_SOCKET;
|
|
}
|
|
//set to non blocking
|
|
unsigned long enable = 1;
|
|
if(ioctlsocket(gameListenerSocket, FIONBIO, &enable))
|
|
{
|
|
DEBUG_STREAM << "ERROR: Could not set game listener socket to nonblocking; ioctlsocket() failed with " << WSAGetLastError() << "!\n" << std::flush;
|
|
WSACleanup();
|
|
PostQuitMessage(AbortExitCodeID);
|
|
return INVALID_SOCKET;
|
|
}
|
|
}
|
|
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();
|
|
shutdown(socket_ptr, SD_BOTH);
|
|
closesocket(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--;
|
|
}
|
|
}
|