// // Copyright 2020 Electronic Arts Inc. // // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free // software: you can redistribute it and/or modify it under the terms of // the GNU General Public License as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed // in the hope that it will be useful, but with permitted additional restrictions // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT // distributed with this program. You should have received a copy of the // GNU General Public License along with permitted additional restrictions // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection /* $Header: /CounterStrike/IPXMGR.CPP 3 10/13/97 2:20p Steve_t $ */ /*************************************************************************** ** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ** *************************************************************************** * * * Project Name : Command & Conquer * * * * File Name : IPXMGR.CPP * * * * Programmer : Bill Randolph * * * * Start Date : December 20, 1994 * * * * Last Update : May 4, 1995 [BRR] * * * *-------------------------------------------------------------------------* * Functions: * * IPXManagerClass::IPXManagerClass -- class constructor * * IPXManagerClass::~IPXManagerClass -- class destructor * * IPXManagerClass::Init -- initialization routine * * IPXManagerClass::Is_IPX -- tells if IPX is installed or not * * IPXManagerClass::Set_Timing -- sets timing for all connections * * IPXManagerClass::Create_Connection -- creates a new connection * * IPXManagerClass::Delete_Connection -- deletes a connection * * IPXManagerClass::Num_Connections -- gets the # of connections * * IPXManagerClass::Connection_ID -- gets the given connection's ID * * IPXManagerClass::Connection_Name -- gets name for given connection * * IPXManagerClass::Connection_Address -- retrieves connection's address * * IPXManagerClass::Connection_Index -- gets given connection's index * * IPXManagerClass::Set_Connection_Parms -- sets connection's name & id * * IPXManagerClass::Send_Global_Message -- sends a Global Message * * IPXManagerClass::Get_Global_Message -- polls the Global Message queue * * IPXManagerClass::Send_Private_Message -- Sends a Private Message * * IPXManagerClass::Get_Private_Message -- Polls Private Message queue * * IPXManagerClass::Service -- main polling routine for IPX Connections * * IPXManagerClass::Get_Bad_Connection -- returns bad connection ID * * IPXManagerClass::Global_Num_Send -- gets # entries in send queue * * IPXManagerClass::Global_Num_Receive -- gets # entries in recv queue * * IPXManagerClass::Private_Num_Send -- gets # entries in send queue * * IPXManagerClass::Private_Num_Receive -- gets # entries in recv queue * * IPXManagerClass::Set_Bridge -- prepares to cross a bridge * * IPXManagerClass::Set_Socket -- sets socket ID for all connections * * IPXManagerClass::Response_Time -- Returns largest Avg Response Time * * IPXManagerClass::Global_Response_Time -- Returns Avg Response Time * * IPXManagerClass::Reset_Response_Time -- Reset response time * * IPXManagerClass::Oldest_Send -- gets ptr to oldest send buf * * IPXManagerClass::Mono_Debug_Print -- debug output routine * * IPXManagerClass::Alloc_RealMode_Mem -- allocates real-mode memory * * IPXManagerClass::Free_RealMode_Mem -- frees real-mode memory * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "function.h" #include //#include PG //#include PG #include "ipxmgr.h" #include "wwlib32.h" // to enable mono output #ifdef WINSOCK_IPX #include "WSProto.h" #include "WSPIPX.h" #else //WINSOCK_IPX #include "ipx95.h" #ifdef WIN32 #include "tcpip.h" #else #include "fakesock.h" #endif //WIN32 #endif //WINSOCK_IPX // Turn off "expression is not meaningful". //#pragma warning 628 9 //#include "WolDebug.h" /*************************************************************************** * IPXManagerClass::IPXManagerClass -- class constructor * * * * INPUT: * * glb_maxlen Global Channel maximum packet length * * pvt_maxlen Private Channel maximum packet length * * socket socket ID to use * * product_id a unique numerical ID for this product * * * * OUTPUT: * * none. * * * * WARNINGS: * * The socket number is byte-swapped, since IPX requires socket ID's * * to be stored high/low. * * * * HISTORY: * * 12/20/1994 BR : Created. * *=========================================================================*/ IPXManagerClass::IPXManagerClass (int glb_maxlen, int pvt_maxlen, int glb_num_packets, int pvt_num_packets, unsigned short socket, unsigned short product_id) { int i; #ifdef WINSOCK_IPX /* ** Find out if Packet protocol services are available through Winsock. */ if ( PacketTransport ) { delete PacketTransport; PacketTransport = NULL; } PacketTransport = new WinsockInterfaceClass; assert ( PacketTransport != NULL ); if ( PacketTransport->Init() ){ IPXStatus = 1; }else{ IPXStatus = 0; } delete PacketTransport; PacketTransport = NULL; #else //WINSOCK_IPX //------------------------------------------------------------------------ // Initialize data members //------------------------------------------------------------------------ //........................................................................ // IPXStatus = 1 if IPX is installed, 0 if not //........................................................................ if (IPX_SPX_Installed()==0) { IPXStatus = 0; } else { IPXStatus = 1; } #endif //WINSOCK_IPX //........................................................................ // Set listening state flag to off //........................................................................ Listening = 0; //........................................................................ // No memory has been alloc'd yet //........................................................................ RealMemAllocd = 0; //........................................................................ // Set max packet sizes, for allocating real-mode memory //........................................................................ Glb_MaxPacketLen = glb_maxlen; Glb_NumPackets = glb_num_packets; Pvt_MaxPacketLen = pvt_maxlen; Pvt_NumPackets = pvt_num_packets; //........................................................................ // Save the app's product ID //........................................................................ ProductID = product_id; //........................................................................ // Save our socket ID number //........................................................................ Socket = (unsigned short)( (((unsigned long)socket & 0x00ff) << 8) | (((unsigned long)socket & 0xff00) >> 8)); //------------------------------------------------------------------------ // Get the user's IPX local connection number //------------------------------------------------------------------------ ConnectionNum = 0; #ifndef WINSOCK_IPX if (IPXStatus) { ConnectionNum = IPX_Get_Connection_Number(); } #endif //WINSOCK_IPX //------------------------------------------------------------------------ // Init connection states //------------------------------------------------------------------------ NumConnections = 0; CurConnection = 0; for (i = 0; i < CONNECT_MAX; i++) { Connection[i] = 0; } GlobalChannel = 0; SendOverflows = 0; ReceiveOverflows = 0; BadConnection = CONNECTION_NONE; //------------------------------------------------------------------------ // Init timing parameters //------------------------------------------------------------------------ RetryDelta = 2; // 2 ticks between retries MaxRetries = -1; // disregard # retries Timeout = 60; // report bad connection after 1 second } /* end of IPXManagerClass */ /*************************************************************************** * IPXManagerClass::~IPXManagerClass -- class destructor * * * * INPUT: * * none. * * * * OUTPUT: * * none. * * * * WARNINGS: * * none. * * * * HISTORY: * * 12/20/1994 BR : Created. * *=========================================================================*/ IPXManagerClass::~IPXManagerClass() { int i; //------------------------------------------------------------------------ // Stop all IPX events //------------------------------------------------------------------------ if (Listening) { IPXConnClass::Stop_Listening(); Listening = 0; } //------------------------------------------------------------------------ // Free all protected-mode memory //------------------------------------------------------------------------ if (GlobalChannel) { delete GlobalChannel; GlobalChannel = 0; } for (i = 0; i < NumConnections; i++) { delete Connection[i]; Connection[i] = 0; } NumConnections = 0; //------------------------------------------------------------------------ // Free all real-mode memory //------------------------------------------------------------------------ if (RealMemAllocd) { Free_RealMode_Mem(); RealMemAllocd = 0; } #ifdef FIXIT_CSII // checked - ajw 9/28/98 #ifdef WIN32 #ifndef WINSOCK_IPX //PG Unload_IPX_Dll(); #endif #endif #endif } /* end of ~IPXManagerClass */ /*************************************************************************** * IPXManagerClass::Init -- initialization routine * * * * This routine allocates memory, & initializes variables * * * * INPUT: * * none. * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 12/20/1994 BR : Created. * *=========================================================================*/ int IPXManagerClass::Init() { int i; if (Session.Type != GAME_INTERNET) { //------------------------------------------------------------------------ // Error if IPX not installed //------------------------------------------------------------------------ if (!IPXStatus) { return(0); } //------------------------------------------------------------------------ // Stop Listening //------------------------------------------------------------------------ if (Listening) { IPXConnClass::Stop_Listening(); Listening = 0; } //------------------------------------------------------------------------ // Free Real-mode memory //------------------------------------------------------------------------ if (RealMemAllocd) { Free_RealMode_Mem(); RealMemAllocd = 0; } } else { /* ** Pretend IPX is available for Internet games whether it is or not */ IPXStatus = 1; } //------------------------------------------------------------------------ // Free protected-mode memory //------------------------------------------------------------------------ if (GlobalChannel) { delete GlobalChannel; GlobalChannel = 0; } for (i = 0; i < NumConnections; i++) { delete Connection[i]; Connection[i] = 0; } NumConnections = 0; if (Session.Type != GAME_INTERNET) { //------------------------------------------------------------------------ // Allocate real-mode memory //------------------------------------------------------------------------ if (!Alloc_RealMode_Mem()) return(0); RealMemAllocd = 1; } //------------------------------------------------------------------------ // Allocate the Global Channel //------------------------------------------------------------------------ GlobalChannel = new IPXGlobalConnClass (Glb_NumPackets, Glb_NumPackets, Glb_MaxPacketLen, ProductID); if (!GlobalChannel) { return(0); } GlobalChannel->Init(); GlobalChannel->Set_Retry_Delta (RetryDelta); GlobalChannel->Set_Max_Retries (MaxRetries); GlobalChannel->Set_TimeOut (Timeout); //------------------------------------------------------------------------ // Configure the IPX Connections //------------------------------------------------------------------------ IPXConnClass::Configure(Socket, ConnectionNum, ListenECB, SendECB, FirstHeaderBuf, SendHeader, FirstDataBuf, SendBuf, Handler, PacketLen); //------------------------------------------------------------------------ // Start Listening //------------------------------------------------------------------------ if (Session.Type != GAME_INTERNET) { if (!IPXConnClass::Start_Listening()) return(0); } Listening = 1; return(1); } /* end of Init */ /*************************************************************************** * IPXManagerClass::Is_IPX -- tells if IPX is installed or not * * * * INPUT: * * none. * * * * OUTPUT: * * 1 = IPX is installed; 0 = isn't * * * * WARNINGS: * * none. * * * * HISTORY: * * 12/20/1994 BR : Created. * *=========================================================================*/ int IPXManagerClass::Is_IPX(void) { return(IPXStatus); } /* end of Is_IPX */ /*************************************************************************** * IPXManagerClass::Set_Timing -- sets timing for all connections * * * * This will set the timing parameters for all existing connections, and * * all connections created from now on. This allows an application to * * measure the Response_Time while running, and adjust timing accordingly. * * * * INPUT: * * retrydelta value to set for retry delta * * maxretries value to set for max # retries * * timeout value to set for connection timeout * * * * OUTPUT: * * none. * * * * WARNINGS: * * none. * * * * HISTORY: * * 07/02/1995 BR : Created. * *=========================================================================*/ void IPXManagerClass::Set_Timing (unsigned long retrydelta, unsigned long maxretries, unsigned long timeout) { int i; RetryDelta = retrydelta; MaxRetries = maxretries; Timeout = timeout; if (GlobalChannel) { GlobalChannel->Set_Retry_Delta (RetryDelta); GlobalChannel->Set_Max_Retries (MaxRetries); GlobalChannel->Set_TimeOut (Timeout); } for (i = 0; i < NumConnections; i++) { Connection[i]->Set_Retry_Delta (RetryDelta); Connection[i]->Set_Max_Retries (MaxRetries); Connection[i]->Set_TimeOut (Timeout); } } /* end of Set_Timing */ /*************************************************************************** * IPXManagerClass::Create_Connection -- creates a new connection * * * * INPUT: * * id application-specific numerical ID for this connection * * node ptr to IPXNodeIDType (name & address) * * address IPX address for this connection * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * Never create a connection with an 'id' of -1. * * * * HISTORY: * * 12/20/1994 BR : Created. * *=========================================================================*/ int IPXManagerClass::Create_Connection(int id, char *name, IPXAddressClass *address) { //------------------------------------------------------------------------ // Error if IPX not installed //------------------------------------------------------------------------ if (!IPXStatus) { return(0); } //------------------------------------------------------------------------ // Error if no more room //------------------------------------------------------------------------ if (NumConnections==CONNECT_MAX) { return(0); } //------------------------------------------------------------------------ // Create new connection //------------------------------------------------------------------------ Connection[NumConnections] = new IPXConnClass(Pvt_NumPackets, Pvt_NumPackets, Pvt_MaxPacketLen, ProductID, address, id, name); if (!Connection[NumConnections]) { return(0); } Connection[NumConnections]->Init (); Connection[NumConnections]->Set_Retry_Delta (RetryDelta); Connection[NumConnections]->Set_Max_Retries (MaxRetries); Connection[NumConnections]->Set_TimeOut (Timeout); NumConnections++; return(1); } /* end of Create_Connection */ /*************************************************************************** * IPXManagerClass::Delete_Connection -- deletes a connection * * * * INPUT: * * id ID of connection to delete * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 12/20/1994 BR : Created. * *=========================================================================*/ int IPXManagerClass::Delete_Connection(int id) { int i,j; //------------------------------------------------------------------------ // Error if IPX not installed //------------------------------------------------------------------------ if (!IPXStatus) { return(0); } //------------------------------------------------------------------------ // Error if no connections to delete //------------------------------------------------------------------------ if (NumConnections==0) { return(0); } //------------------------------------------------------------------------ // Loop through all connections //------------------------------------------------------------------------ for (i = 0; i < NumConnections; i++) { //..................................................................... // If a match, delete it //..................................................................... if (Connection[i]->ID==id) { delete Connection[i]; //.................................................................. // Move array elements back one index //.................................................................. for (j = i; j < NumConnections - 1; j++) { Connection[j] = Connection[j+1]; } //.................................................................. // Adjust counters //.................................................................. NumConnections--; if (CurConnection >= NumConnections) CurConnection = 0; return(1); } } //------------------------------------------------------------------------ // No match; error //------------------------------------------------------------------------ return(0); } /* end of Delete_Connection */ /*************************************************************************** * IPXManagerClass::Num_Connections -- gets the # of connections * * * * INPUT: * * none. * * * * OUTPUT: * * # of connections * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Num_Connections(void) { return(NumConnections); } /* end of Num_Connections */ /*************************************************************************** * IPXManagerClass::Connection_ID -- gets the given connection's ID * * * * INPUT: * * index index of connection to retrieve * * * * OUTPUT: * * ID for that connection, CONNECTION_NONE if invalid index * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Connection_ID(int index) { if (index >= 0 && index < NumConnections) { return(Connection[index]->ID); } else { return(CONNECTION_NONE); } } /* end of Connection_ID */ /*************************************************************************** * IPXManagerClass::Connection_Name -- retrieves name for given connection * * * * INPUT: * * id ID of connection to get name of * * * * OUTPUT: * * ptr to connection's name, NULL if not found * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/19/1995 BR : Created. * *=========================================================================*/ char *IPXManagerClass::Connection_Name(int id) { int i; for (i = 0; i < NumConnections; i++) { if (Connection[i]->ID==id) { return(Connection[i]->Name); } } return(NULL); } /* end of Connection_Name */ /*************************************************************************** * IPXManagerClass::Connection_Address -- retrieves connection's address * * * * INPUT: * * id ID of connection to get address for * * * * OUTPUT: * * pointer to IXPAddressClass, NULL if not found * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/19/1995 BR : Created. * *=========================================================================*/ IPXAddressClass * IPXManagerClass::Connection_Address(int id) { int i; for (i = 0; i < NumConnections; i++) { if (Connection[i]->ID==id) { return(&Connection[i]->Address); } } return(NULL); } /* end of Connection_Address */ /*************************************************************************** * IPXManagerClass::Connection_Index -- gets given connection's index * * * * INPUT: * * ID to retrieve index for * * * * OUTPUT: * * index for this connection, CONNECTION_NONE if not found * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Connection_Index(int id) { int i; for (i = 0; i < NumConnections; i++) { if (Connection[i]->ID==id) { return(i); } } return(CONNECTION_NONE); } /* end of Connection_Index */ /*************************************************************************** * IPXManagerClass::Set_Connection_Parms -- sets connection's name & id * * * * INPUT: * * index connection index * * id new connection ID * * name new connection name * * * * OUTPUT: * * none. * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ void IPXManagerClass::Set_Connection_Parms(int index, int id, char *name) { if (index >= NumConnections) return; Connection[index]->ID = id; strcpy(Connection[index]->Name,name); } /* end of Set_Connection_Parms */ /*************************************************************************** * IPXManagerClass::Send_Global_Message -- sends a Global Message * * * * INPUT: * * buf buffer to send * * buflen length of buf * * ack_req 1 = ACK required; 0 = no ACK required * * address address to send to; NULL = broadcast * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Send_Global_Message(void *buf, int buflen, int ack_req, IPXAddressClass *address) { int rc; //------------------------------------------------------------------------ // Error if IPX not installed or not Listening //------------------------------------------------------------------------ if (!IPXStatus || !Listening) return(0); rc = GlobalChannel->Send_Packet (buf, buflen, address, ack_req); if (!rc) { SendOverflows++; } return(rc); } /* end of Send_Global_Message */ /*************************************************************************** * IPXManagerClass::Get_Global_Message -- polls the Global Message queue * * * * INPUT: * * buf buffer to store received packet * * buflen length of data placed in 'buf' * * address IPX address of sender * * product_id product ID of sender * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Get_Global_Message(void *buf, int *buflen, IPXAddressClass *address, unsigned short *product_id) { //------------------------------------------------------------------------ // Error if IPX not installed or not Listening //------------------------------------------------------------------------ if (!IPXStatus || !Listening) return(0); return(GlobalChannel->Get_Packet (buf, buflen, address, product_id)); } /* end of Get_Global_Message */ /*************************************************************************** * IPXManagerClass::Send_Private_Message -- Sends a Private Message * * * * INPUT: * * buf buffer to send * * buflen length of 'buf' * * conn_id connection ID to send to (CONNECTION_NONE = all) * * ack_req 1 = ACK required; 0 = no ACK required * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Send_Private_Message(void *buf, int buflen, int ack_req, int conn_id) { int i; // loop counter int connect_idx; // index of channel to send to, if specified //------------------------------------------------------------------------ // Error if IPX not installed or not Listening //------------------------------------------------------------------------ if (!IPXStatus || !Listening || (NumConnections==0)) { return(0); } //------------------------------------------------------------------------ // Send the message to all connections //------------------------------------------------------------------------ if (conn_id==CONNECTION_NONE) { //..................................................................... // Check for room in all connections //..................................................................... for (i = 0; i < NumConnections; i++) { if (Connection[i]->Queue->Num_Send() == Connection[i]->Queue->Max_Send()) { SendOverflows++; return(0); } } //..................................................................... // Send packet to all connections //..................................................................... for (i = 0; i < NumConnections; i++) { Connection[i]->Send_Packet (buf, buflen, ack_req); } return(1); } //------------------------------------------------------------------------ // Send the message to the specified connection //------------------------------------------------------------------------ else { connect_idx = Connection_Index (conn_id); if (connect_idx == CONNECTION_NONE) { SendOverflows++; return(0); } //..................................................................... // Check for room in the connection //..................................................................... if (Connection[connect_idx]->Queue->Num_Send() == Connection[connect_idx]->Queue->Max_Send()) { SendOverflows++; return(0); } //..................................................................... // Send the packet to that connection //..................................................................... Connection[connect_idx]->Send_Packet (buf, buflen, ack_req); return(1); } } /* end of Send_Private_Message */ /*************************************************************************** * IPXManagerClass::Get_Private_Message -- Polls the Private Message queue * * * * INPUT: * * buf buffer to store incoming packet * * buflen length of data placed in 'buf' * * conn_id filled in with connection ID of sender * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Get_Private_Message(void *buf, int *buflen, int *conn_id) { int i; int rc; int c_id; //------------------------------------------------------------------------ // Error if IPX not installed or not Listening //------------------------------------------------------------------------ if (!IPXStatus || !Listening || (NumConnections==0)) { return(0); } //------------------------------------------------------------------------ // Safety check: ensure CurConnection is in range. //------------------------------------------------------------------------ if (CurConnection >= NumConnections) { CurConnection = 0; } //------------------------------------------------------------------------ // Scan all connections for a received packet, starting with 'CurConnection' //------------------------------------------------------------------------ for (i = 0; i < NumConnections; i++) { //..................................................................... // Check this connection for a packet //..................................................................... rc = Connection[CurConnection]->Get_Packet (buf, buflen); c_id = Connection[CurConnection]->ID; //..................................................................... // Increment CurConnection to the next connection index //..................................................................... CurConnection++; if (CurConnection >= NumConnections) { CurConnection = 0; } //..................................................................... // If we got a packet, return the connection ID //..................................................................... if (rc) { (*conn_id) = c_id; return(1); } } return(0); } /* end of Get_Private_Message */ /*************************************************************************** * IPXManagerClass::Service -- main polling routine for IPX Connections * * * * INPUT: * * none. * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Service(void) { int rc = 1; int i; CommHeaderType *packet; int packetlen; IPXAddressClass address; #ifdef WINSOCK_IPX unsigned char temp_receive_buffer[1024]; int temp_receive_buffer_len; int temp_address_len; char temp_address [128]; if ( PacketTransport ) { do { temp_receive_buffer_len = sizeof (temp_receive_buffer); temp_address_len = sizeof (temp_address); packetlen = PacketTransport->Read ( temp_receive_buffer, temp_receive_buffer_len, temp_address, temp_address_len ); if ( packetlen ) { CurDataBuf = (char*)temp_receive_buffer; address = *((IPXAddressClass*) temp_address); packet = (CommHeaderType *)CurDataBuf; if (packet->MagicNumber == GlobalChannel->Magic_Num()) { /* ** Put the packet in the Global Queue */ if (!GlobalChannel->Receive_Packet (packet, packetlen, &address)) ReceiveOverflows++; } else { if (packet->MagicNumber == ProductID) { /* ** Find the Private Queue that this packet is for */ bool found_address = false; for (i = 0; i < NumConnections; i++) { if (Connection[i]->Address == address) { found_address = true; if (!Connection[i]->Receive_Packet (packet, packetlen)) ReceiveOverflows++; break; } } if( Session.Type == GAME_INTERNET ) { /* ** This packet came from an unknown source. If it looks like one of our players ** packets then it might be from a player whos IP has changed. */ if (!found_address) { if (packet->Code == ConnectionClass::PACKET_DATA_NOACK){ /* ** Magic number and packet code are valid. It's probably a C&C packet. */ EventClass *event = (EventClass*) (((char*) packet) + sizeof (CommHeaderType)); /* ** If this is a framesync packet then grab the address and match it to an existing player. */ if (event->Type == EventClass::FRAMESYNC) { int id = event->ID; assert (id != PlayerPtr->ID); for ( int i=1 ; iPlayer.ID == id) { int iConnectionIndex = Connection_Index(id); if( iConnectionIndex != CONNECTION_NONE ) // (else Create_Connections() has not yet been called) { /* ** Found a likely candidate. Update his address. It should be OK to drop this ** packet since it's a framesync packet and will will pick up the next one. */ Session.Players[i]->Address = address; Connection[iConnectionIndex]->Address = address; } break; } } } } } } } } } } while (packetlen); } #else //WINSOCK_IPX #ifdef WIN32 unsigned char temp_receive_buffer[1024]; int recv_length; if (Winsock.Get_Connected() || Special.IsFromWChat) { if (!Winsock.Get_Connected()) return (0); /* ** This is an internet connection so get the packets from winsock */ while ((recv_length = Winsock.Read(temp_receive_buffer, 1024))!=0) { CurHeaderBuf = NULL; CurDataBuf = (char*)&temp_receive_buffer[0]; /*..................................................................... Compute the length of the packet (byte-swap the length in the IPX hdr) .....................................................................*/ packetlen = recv_length; /*..................................................................... Extract the sender's address from the IPX header .....................................................................*/ address.Set_Address (CurHeaderBuf); /*..................................................................... Examine the Magic Number of the received packet to determine if this packet goes into the Global Queue, or into one of the Private Queues .....................................................................*/ packet = (CommHeaderType *)CurDataBuf; if (packet->MagicNumber == GlobalChannel->Magic_Num()) { /*.................................................................. Put the packet in the Global Queue ..................................................................*/ if (!GlobalChannel->Receive_Packet (packet, packetlen, &address)) ReceiveOverflows++; } else { if (packet->MagicNumber == ProductID) { /*.................................................................. Find the Private Queue that this packet is for ..................................................................*/ for (i = 0; i < NumConnections; i++) { if (Connection[i]->Address == address) { if (!Connection[i]->Receive_Packet (packet, packetlen)) ReceiveOverflows++; break; } } } } } } else { #if(0)//PG while (IPX_Get_Outstanding_Buffer95(&temp_receive_buffer[0])) { CurHeaderBuf = (IPXHEADER*)&temp_receive_buffer[0]; CurDataBuf = (char*)&temp_receive_buffer[sizeof(IPXHeaderType)]; /*..................................................................... Compute the length of the packet (byte-swap the length in the IPX hdr) .....................................................................*/ packetlen = ((CurHeaderBuf->Length & 0xff) << 8) | (CurHeaderBuf->Length >> 8); packetlen -= sizeof(IPXHeaderType); /*..................................................................... Extract the sender's address from the IPX header .....................................................................*/ address.Set_Address (CurHeaderBuf); /*..................................................................... Examine the Magic Number of the received packet to determine if this packet goes into the Global Queue, or into one of the Private Queues .....................................................................*/ packet = (CommHeaderType *)CurDataBuf; if (packet->MagicNumber == GlobalChannel->Magic_Num()) { /*.................................................................. Put the packet in the Global Queue ..................................................................*/ if (!GlobalChannel->Receive_Packet (packet, packetlen, &address)) ReceiveOverflows++; } else { if (packet->MagicNumber == ProductID) { /*.................................................................. Find the Private Queue that this packet is for ..................................................................*/ for (i = 0; i < NumConnections; i++) { if (Connection[i]->Address == address) { if (!Connection[i]->Receive_Packet (packet, packetlen)) ReceiveOverflows++; break; } } } } } #endif } #else //WIN32 //------------------------------------------------------------------------ // Error if IPX not installed or not Listening //------------------------------------------------------------------------ if (!IPXStatus || !Listening) { return(0); } //------------------------------------------------------------------------ // Loop until there are no more packets to process. //------------------------------------------------------------------------ while (1) { //..................................................................... // Check the BufferFlags for the "current" buffer; if it's empty, // break; out of the loop. //..................................................................... if (BufferFlags[CurIndex]==0) { break; } //..................................................................... // Compute the length of the packet (byte-swap the length in the IPX hdr) //..................................................................... packetlen = ((CurHeaderBuf->Length & 0xff) << 8) | (CurHeaderBuf->Length >> 8); packetlen -= sizeof(IPXHeaderType); //..................................................................... // Extract the sender's address from the IPX header //..................................................................... address.Set_Address (CurHeaderBuf); //..................................................................... // Examine the Magic Number of the received packet to determine if this // packet goes into the Global Queue, or into one of the Private Queues //..................................................................... packet = (CommHeaderType *)CurDataBuf; if (packet->MagicNumber == GlobalChannel->Magic_Num()) { //.................................................................. // Put the packet in the Global Queue //.................................................................. if (!GlobalChannel->Receive_Packet (packet, packetlen, &address)) { ReceiveOverflows++; } } //..................................................................... // Find the Private Queue that this packet is for //..................................................................... else if (packet->MagicNumber == ProductID) { for (i = 0; i < NumConnections; i++) { if (Connection[i]->Address == address) { if (!Connection[i]->Receive_Packet (packet, packetlen)) { ReceiveOverflows++; } break; } } } //..................................................................... // Set the current BufferFlags to 0 (since we've cleaned out this buffer) //..................................................................... BufferFlags[CurIndex] = 0; //..................................................................... // Go to the next packet buffer //..................................................................... CurIndex++; CurHeaderBuf = (IPXHeaderType *)(((char *)CurHeaderBuf) + FullPacketLen); CurDataBuf = ((char *)CurDataBuf) + FullPacketLen; if (CurIndex >= NumBufs) { CurHeaderBuf = FirstHeaderBuf; CurDataBuf = FirstDataBuf; CurIndex = 0; } } #endif //WIN32 #endif //WINSOCK_IPX //------------------------------------------------------------------------ // Service all connections. If a connection reports that it's gone "bad", // report an error to the caller. If it's the Global Channel, un-queue the // send entry that's holding things up. This will keep the Global Channel // from being clogged by one un-ACK'd outgoing packet. //------------------------------------------------------------------------ if (GlobalChannel) { if (!GlobalChannel->Service()) { GlobalChannel->Queue->UnQueue_Send (NULL, NULL, 0); rc = 0; } } for (i = 0; i < NumConnections; i++) { if (!Connection[i]->Service()) { rc = 0; BadConnection = Connection[i]->ID; } } if (rc) { BadConnection = CONNECTION_NONE; } return(rc); } /* end of Service */ /*************************************************************************** * IPXManagerClass::Get_Bad_Connection -- returns bad connection ID * * * * INPUT: * * none. * * * * OUTPUT: * * ID of bad connection; CONNECTION_NONE if none. * * * * WARNINGS: * * none. * * * * HISTORY: * * 05/04/1995 BRR : Created. * *=========================================================================*/ int IPXManagerClass::Get_Bad_Connection(void) { return(BadConnection); } /* end of Get_Bad_Connection */ /*************************************************************************** * IPXManagerClass::Global_Num_Send -- reports # entries in send queue * * * * INPUT: * * none. * * * * OUTPUT: * * # entries in the Global Send Queue * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Global_Num_Send(void) { //------------------------------------------------------------------------ // Error if IPX not installed or not Listening //------------------------------------------------------------------------ if (!IPXStatus || !Listening) { return(0); } return(GlobalChannel->Queue->Num_Send()); } /* end of Global_Num_Send */ /*************************************************************************** * IPXManagerClass::Global_Num_Receive -- reports # entries in recv queue * * * * INPUT: * * none. * * * * OUTPUT: * * # entries in the Global Receive Queue * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Global_Num_Receive(void) { //------------------------------------------------------------------------ // Error if IPX not installed or not Listening //------------------------------------------------------------------------ if (!IPXStatus || !Listening) { return(0); } return(GlobalChannel->Queue->Num_Receive()); } /* end of Global_Num_Receive */ /*************************************************************************** * IPXManagerClass::Private_Num_Send -- reports # entries in send queue * * * * INPUT: * * # entries in the Private Send Queue * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Private_Num_Send(int id) { int i; int maxnum; //------------------------------------------------------------------------ // Error if IPX not installed or not Listening //------------------------------------------------------------------------ if (!IPXStatus || !Listening || (NumConnections==0)) { return(0); } //------------------------------------------------------------------------ // If connection ID specified, return that connection's # of packets //------------------------------------------------------------------------ if (id != CONNECTION_NONE) { i = Connection_Index(id); if (i != CONNECTION_NONE) { return(Connection[i]->Queue->Num_Send()); } else { return(0); } } //------------------------------------------------------------------------ // Otherwise, return the max # of all connections //------------------------------------------------------------------------ else { maxnum = 0; for (i = 0; i < NumConnections; i++) { if (Connection[i]->Queue->Num_Send() > maxnum) { maxnum = Connection[i]->Queue->Num_Send(); } } return(maxnum); } } /* end of Private_Num_Send */ /*************************************************************************** * IPXManagerClass::Private_Num_Receive -- reports # entries in recv queue * * * * INPUT: * * id ID of connection to query * * * * OUTPUT: * * # entries in the Private Receive Queue * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ int IPXManagerClass::Private_Num_Receive(int id) { int i; int maxnum; //------------------------------------------------------------------------ // Error if IPX not installed or not Listening //------------------------------------------------------------------------ if (!IPXStatus || !Listening || (NumConnections==0)) return(0); //------------------------------------------------------------------------ // If connection ID specified, return that connection's # of packets //------------------------------------------------------------------------ if (id != CONNECTION_NONE) { i = Connection_Index(id); if (i != CONNECTION_NONE) { return(Connection[i]->Queue->Num_Receive()); } else { return(0); } } //------------------------------------------------------------------------ // Otherwise, return the max # of all connections //------------------------------------------------------------------------ else { maxnum = 0; for (i = 0; i < NumConnections; i++) { if (Connection[i]->Queue->Num_Receive() > maxnum) { maxnum = Connection[i]->Queue->Num_Receive(); } } return(maxnum); } } /* end of Private_Num_Receive */ /*************************************************************************** * IPXManagerClass::Set_Socket -- sets socket ID for all connections * * * * INPUT: * * socket new socket ID to use * * * * OUTPUT: * * none. * * * * WARNINGS: * * Do not call this function after communications have started; you * * must call it before calling Init(). * * The socket number is byte-swapped, since IPX requires socket ID's * * to be stored high/low. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ void IPXManagerClass::Set_Socket(unsigned short socket) { Socket = (unsigned short)( (((unsigned long)socket & 0x00ff) << 8) | (((unsigned long)socket & 0xff00) >> 8)); } /* end of Set_Socket */ /*************************************************************************** * IPXManagerClass::Response_Time -- Returns largest Avg Response Time * * * * INPUT: * * none. * * * * OUTPUT: * * largest avg response time * * * * WARNINGS: * * none. * * * * HISTORY: * * 05/04/1995 BRR : Created. * *=========================================================================*/ unsigned long IPXManagerClass::Response_Time(void) { unsigned long resp; unsigned long maxresp = 0; int i; for (i = 0; i < NumConnections; i++) { resp = Connection[i]->Queue->Avg_Response_Time(); if (resp > maxresp) { maxresp = resp; } } return(maxresp); } /* end of Response_Time */ /*************************************************************************** * IPXManagerClass::Global_Response_Time -- Returns Avg Response Time * * * * INPUT: * * none. * * * * OUTPUT: * * avg global channel response time * * * * WARNINGS: * * none. * * * * HISTORY: * * 05/04/1995 BRR : Created. * *=========================================================================*/ unsigned long IPXManagerClass::Global_Response_Time(void) { if (GlobalChannel) { return (GlobalChannel->Queue->Avg_Response_Time()); } else { return (0); } } /* end of Global_Response_Time */ /*************************************************************************** * IPXManagerClass::Reset_Response_Time -- Reset response time * * * * INPUT: * * none. * * * * OUTPUT: * * none. * * * * WARNINGS: * * none. * * * * HISTORY: * * 05/04/1995 BRR : Created. * *=========================================================================*/ void IPXManagerClass::Reset_Response_Time(void) { int i; for (i = 0; i < NumConnections; i++) { Connection[i]->Queue->Reset_Response_Time(); } if (GlobalChannel) GlobalChannel->Queue->Reset_Response_Time(); } /* end of Reset_Response_Time */ /*************************************************************************** * IPXManagerClass::Oldest_Send -- gets ptr to oldest send buf * * * * INPUT: * * none. * * * * OUTPUT: * * buf ptr * * * * WARNINGS: * * none. * * * * HISTORY: * * 05/04/1995 BRR : Created. * *=========================================================================*/ void * IPXManagerClass::Oldest_Send(void) { int i,j; unsigned long time; unsigned long mintime = 0xffffffff; SendQueueType *send_entry; // ptr to send entry header CommHeaderType *packet; void *buf = NULL; for (i = 0; i < NumConnections; i++) { send_entry = NULL; for (j = 0; j < Connection[i]->Queue->Num_Send(); j++) { send_entry = Connection[i]->Queue->Get_Send(j); if (send_entry) { packet = (CommHeaderType *)send_entry->Buffer; if (packet->Code == ConnectionClass::PACKET_DATA_ACK && send_entry->IsACK == 0) { break; } else { send_entry = NULL; } } } if (send_entry!=NULL) { time = send_entry->FirstTime; if (time < mintime) { mintime = time; buf = send_entry->Buffer; } } } return(buf); } /* end of Oldest_Send */ /*************************************************************************** * IPXManagerClass::Set_Bridge -- prepares to cross a bridge * * * * This routine is designed to prevent the connection from having to * * call Get_Local_Target, except the minimum number of times, since that * * routine is buggy & goes away for long periods sometimes. * * * * INPUT: * * bridge network number of the destination bridge * * * * OUTPUT: * * none * * * * WARNINGS: * * none * * * * HISTORY: * * 07/06/1995 BRR : Created. * *=========================================================================*/ void IPXManagerClass::Set_Bridge(NetNumType bridge) { if (GlobalChannel) { GlobalChannel->Set_Bridge(bridge); } } /* end of Set_Bridge */ /*************************************************************************** * IPXManagerClass::Configure_Debug -- sets up special debug values * * * * Mono_Debug_Print2() can look into a packet to pull out a particular * * ID, and can print both that ID and a string corresponding to * * that ID. This routine configures these values so it can find * * and decode the ID. This ID is used in addition to the normal * * CommHeaderType values. * * * * INPUT: * * index connection index to configure (-1 = Global Channel) * * type_offset ID's byte offset into packet * * type_size size of ID, in bytes; 0 if none * * names ptr to array of names; use ID as an index into this * * namestart numerical value of 1st name in the array * * namecount # in the names array; 0 if none. * * * * OUTPUT: * * none. * * * * WARNINGS: * * Names shouldn't be longer than 12 characters. * * * * HISTORY: * * 05/31/1995 BRR : Created. * *=========================================================================*/ void IPXManagerClass::Configure_Debug(int index, int type_offset, int type_size, char **names, int namestart, int namecount) { if (index == -1) { GlobalChannel->Queue->Configure_Debug (type_offset, type_size, names, namestart, namecount); } else if (Connection[index]) { Connection[index]->Queue->Configure_Debug (type_offset, type_size, names, namestart, namecount); } } /* end of Configure_Debug */ /*************************************************************************** * IPXManagerClass::Mono_Debug_Print -- debug output routine * * * * INPUT: * * index index of connection to display (-1 = Global Channel) * * refresh 1 = complete screen refresh * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 01/25/1995 BR : Created. * *=========================================================================*/ void IPXManagerClass::Mono_Debug_Print(int index, int refresh) { #ifdef WWLIB32_H char txt[80]; int i; if (index == -1) GlobalChannel->Queue->Mono_Debug_Print (refresh); else if (Connection[index]) Connection[index]->Queue->Mono_Debug_Print (refresh); if (refresh) { Mono_Set_Cursor (20,1); Mono_Printf ("IPX Queue:"); Mono_Set_Cursor (9,2); Mono_Printf ("Average Response Time:"); Mono_Set_Cursor (43,1); Mono_Printf ("Send Overflows:"); Mono_Set_Cursor (40,2); Mono_Printf ("Receive Overflows:"); } Mono_Set_Cursor (32,1); Mono_Printf ("%d",index); Mono_Set_Cursor (32,2); if (index == -1) { Mono_Printf ("%d ", GlobalChannel->Queue->Avg_Response_Time()); } else { Mono_Printf ("%d ", Connection[index]->Queue->Avg_Response_Time()); } Mono_Set_Cursor (59,1); Mono_Printf ("%d ", SendOverflows); Mono_Set_Cursor (59,2); Mono_Printf ("%d ", ReceiveOverflows); for (i = 0; i < NumBufs; i++) { if (BufferFlags[i]) { txt[i] = 'X'; } else { txt[i] = '_'; } } txt[i] = 0; Mono_Set_Cursor ((80-NumBufs)/2,3); Mono_Printf ("%s",txt); #else index = index; refresh = refresh; #endif } /* end of Mono_Debug_Print */ /*************************************************************************** * IPXManagerClass::Alloc_RealMode_Mem -- allocates real-mode memory * * * * INPUT: * * none. * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 12/20/1994 BR : Created. * *=========================================================================*/ int IPXManagerClass::Alloc_RealMode_Mem(void) { #ifdef WIN32 return (1); #else union REGS regs; struct SREGS sregs; int size; // required size of allocation unsigned char *realmode; // start addresses of real-mode data int realmodelen; // length of real-mode data unsigned long func_val; char *p; // for parsing buffer int i; //------------------------------------------------------------------------ // Compute # of buffers we need to allocate, & the max size of each one //------------------------------------------------------------------------ NumBufs = Glb_NumPackets + (Pvt_NumPackets * CONNECT_MAX); PacketLen = Glb_MaxPacketLen + sizeof (GlobalHeaderType); if (Pvt_MaxPacketLen + sizeof (CommHeaderType) > PacketLen) PacketLen = Pvt_MaxPacketLen + sizeof (CommHeaderType); FullPacketLen = PacketLen + sizeof(IPXHeaderType); //------------------------------------------------------------------------ // Compute the size of everything we'll ever need, allocate it in one big // chunk. The memory is used as follows: // - Real-mode assembly IPX callback routine, plus its data, // (which includes the ListenECB) // - Array of IPX Packet buffers (IPXHeader plus data buffer) // - SendECB: ECB for sending // - SendHeader: IPX Header for sending // - SendBuf: Packet buffer for sending // - BufferFlags: 1 byte for each incoming packet buffer; 1=in use, 0=free //------------------------------------------------------------------------ realmode = (unsigned char *)Get_RM_IPX_Address(); realmodelen = Get_RM_IPX_Size(); size = realmodelen + // assembly routine & its data (FullPacketLen * NumBufs) + // array of packet buffers sizeof(ECBType) + // SendECB FullPacketLen + // SendHeader & SendBuf NumBufs; // BufferFlags if (size > 65535) { return(0); } //------------------------------------------------------------------------ // Allocate DOS memory for the ECB, IPXHeader & packet buffers: // AX = 0x100 // BX = # paragraphs to allocate // - if Success, AX = real-mode segment, DX = selector // - if Failure, carry flag is set //------------------------------------------------------------------------ memset (®s, 0 ,sizeof(regs)); segread (&sregs); regs.x.eax = DPMI_ALLOC_DOS_MEM; // DPMI function to call regs.x.ebx = ((size + 15) >> 4); // # paragraphs to allocate int386x (DPMI_INT, ®s, ®s, &sregs); // allocate the memory //------------------------------------------------------------------------ // If the carry flag is set, DPMI is indicating an error. //------------------------------------------------------------------------ if (regs.x.cflag) { return(0); } //------------------------------------------------------------------------ // Save the values of the returned segment & selector //------------------------------------------------------------------------ Selector = regs.w.dx; Segment = regs.w.ax; RealMemSize = size; RealModeData = (RealModeDataType *)(((long)Segment) << 4); //------------------------------------------------------------------------ // Lock the memory (since we're servicing interrupts with it) // AX = 0x600 // BX:CX = starting linear address of memory to lock // SI:DI = size of region to lock (in bytes) // - If Failure, carry flag is set. //------------------------------------------------------------------------ memset (®s, 0 ,sizeof(regs)); segread (&sregs); regs.x.eax = DPMI_LOCK_MEM; // DPMI function to call regs.x.ebx = ((long)RealModeData & 0xffff0000) >> 16; regs.x.ecx = ((long)RealModeData & 0x0000ffff); regs.x.esi = ((long)RealMemSize & 0xffff0000) >> 16; regs.x.edi = ((long)RealMemSize & 0x0000ffff); int386x (DPMI_INT, ®s, ®s, &sregs); // call DPMI //------------------------------------------------------------------------ // If the carry flag is set, DPMI is indicating an error. //------------------------------------------------------------------------ if (regs.x.cflag) { memset (®s, 0 ,sizeof(regs)); segread (&sregs); regs.x.eax = DPMI_FREE_DOS_MEM; // DPMI function to call regs.x.edx = Selector; // ptr to free int386x (DPMI_INT, ®s, ®s, &sregs); // free the memory return(0); } //------------------------------------------------------------------------ // Copy the Real-mode code into our memory buffer //------------------------------------------------------------------------ p = (char *)(((long)Segment) << 4); memcpy (p,realmode,realmodelen); p += realmodelen; //------------------------------------------------------------------------ // Compute & save the entry point for the real-mode packet handler //------------------------------------------------------------------------ func_val = (unsigned long)RealModeData; Handler = (((func_val & 0xffff0) << 12) | ((func_val & 0x000f) + RealModeData->FuncOffset)); //------------------------------------------------------------------------ // Fill in buffer pointers //------------------------------------------------------------------------ ListenECB = &(RealModeData->ListenECB); FirstHeaderBuf = (IPXHeaderType *)p; FirstDataBuf = (((char *)FirstHeaderBuf) + sizeof(IPXHeaderType)); CurIndex = 0; CurHeaderBuf = FirstHeaderBuf; CurDataBuf = FirstDataBuf; p += FullPacketLen * NumBufs; SendECB = (ECBType *)p; p += sizeof (ECBType); SendHeader = (IPXHeaderType *)p; p += sizeof (IPXHeaderType); SendBuf = (char *)p; p += PacketLen; BufferFlags = (char *)p; //------------------------------------------------------------------------ // Fill in the real-mode routine's data (The ECB will be filled in when we // command IPX to Listen). //------------------------------------------------------------------------ RealModeData->NumBufs = (short)NumBufs; RealModeData->BufferFlags = (char *) ((((long)BufferFlags & 0xffff0) << 12) | ((long)BufferFlags & 0x0000f)); RealModeData->PacketSize = (short)FullPacketLen; RealModeData->FirstPacketBuf = (IPXHeaderType *) ((((long)FirstHeaderBuf & 0xffff0) << 12) | ((long)FirstHeaderBuf & 0x0000f)); RealModeData->CurIndex = 0; RealModeData->CurPacketBuf = RealModeData->FirstPacketBuf; RealModeData->Semaphore = 0; RealModeData->ReEntrantCount = 0; //------------------------------------------------------------------------ // Init state of all buffers to empty //------------------------------------------------------------------------ for (i = 0; i < NumBufs; i++) { BufferFlags[i] = 0; } //------------------------------------------------------------------------ // Check the start & end markers in the real-mode memory area //------------------------------------------------------------------------ if (RealModeData->Marker1 != 0x1111 || RealModeData->Marker2 != 0x2222) { Free_RealMode_Mem(); return(0); } else { return(1); } #endif //WIN32 } /* end of Alloc_Realmode_Mem */ /*************************************************************************** * IPXManagerClass::Free_RealMode_Mem -- frees real-mode memory * * * * INPUT: * * none. * * * * OUTPUT: * * 1 = OK, 0 = error * * * * WARNINGS: * * none. * * * * HISTORY: * * 12/20/1994 BR : Created. * *=========================================================================*/ int IPXManagerClass::Free_RealMode_Mem(void) { #ifdef WIN32 return (1); #else //WIN32 union REGS regs; struct SREGS sregs; int rc = 1; //------------------------------------------------------------------------ // Unlock the memory //------------------------------------------------------------------------ memset (®s, 0 ,sizeof(regs)); segread (&sregs); regs.x.eax = DPMI_UNLOCK_MEM; // DPMI function to call regs.x.ebx = ((long)RealModeData & 0xffff0000) >> 16; regs.x.ecx = ((long)RealModeData & 0x0000ffff); regs.x.esi = ((long)RealMemSize & 0xffff0000) >> 16; regs.x.edi = ((long)RealMemSize & 0x0000ffff); int386x (DPMI_INT, ®s, ®s, &sregs); // call DPMI //------------------------------------------------------------------------ // If the carry flag is set, DPMI is indicating an error. //------------------------------------------------------------------------ if (regs.x.cflag) { rc = 0; } //------------------------------------------------------------------------ // Free DOS memory //------------------------------------------------------------------------ memset (®s, 0 ,sizeof(regs)); segread (&sregs); regs.x.eax = DPMI_FREE_DOS_MEM; // DPMI function to call regs.x.edx = Selector; // ptr to free int386x (DPMI_INT, ®s, ®s, &sregs); // free the memory return(rc); #endif //WIN32 } /* end of Free_Realmode_Mem */ /*************************** end of ipxmgr.cpp *****************************/