CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

IPXGCONN.CPP (24226B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /* $Header: /CounterStrike/IPXGCONN.CPP 3     10/13/97 2:20p Steve_t $ */
     17 /***************************************************************************
     18  **   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        **
     19  ***************************************************************************
     20  *                                                                         *
     21  *                 Project Name : Command & Conquer                        *
     22  *                                                                         *
     23  *                    File Name : IPXGCONN.CPP                             *
     24  *                                                                         *
     25  *                   Programmer : Bill Randolph                            *
     26  *                                                                         *
     27  *                   Start Date : December 20, 1994                        *
     28  *                                                                         *
     29  *                  Last Update : July 6, 1995 [BRR]                       *
     30  *-------------------------------------------------------------------------*
     31  * Functions:    			                                                   *
     32  *   IPXGlobalConnClass::IPXGlobalConnClass -- class constructor           *
     33  *   IPXGlobalConnClass::~IPXGlobalConnClass -- class destructor           *
     34  *   IPXGlobalConnClass::Send_Packet -- adds a packet to the send queue		*
     35  *   IPXGlobalConnClass::Receive_Packet -- adds packet to the receive queue*
     36  *   IPXGlobalConnClass::Get_Packet -- gets a packet from the receive queue*
     37  *   IPXGlobalConnClass::Send -- sends a packet										*
     38  *   IPXGlobalConnClass::Service_Receive_Queue -- services receive queue	*
     39  *   IPXGlobalConnClass::Set_Bridge -- Sets up connection to cross a bridge*
     40  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     41 
     42 #include "function.h"
     43 #include <stdio.h>
     44 //#include <mem.h>
     45 #include "ipxgconn.h"
     46 
     47 
     48 /***************************************************************************
     49  * IPXGlobalConnClass::IPXGlobalConnClass -- class constructor             *
     50  *                                                                         *
     51  * This routine chains to the parent constructor, but it adjusts the size	*
     52  * of the packet by the added bytes in the GlobalHeaderType structure.  	*
     53  * This forces the parent classes to allocate the proper sized PacketBuf	*
     54  * for outgoing packets, and to set MaxPacketLen to the proper value.		*
     55  *                                                                         *
     56  * INPUT:                                                                  *
     57  *		numsend			desired # of entries for the send queue					*
     58  *		numreceive		desired # of entries for the receive queue				*
     59  *		maxlen			max length of an application packet							*
     60  *		product_id		unique ID for this product										*
     61  *                                                                         *
     62  * OUTPUT:                                                                 *
     63  *		none.																						*
     64  *                                                                         *
     65  * WARNINGS:                                                               *
     66  *		none.																						*
     67  *                                                                         *
     68  * HISTORY:                                                                *
     69  *   12/20/1994 BR : Created.                                              *
     70  *=========================================================================*/
     71 IPXGlobalConnClass::IPXGlobalConnClass (int numsend, int numreceive,
     72 	int maxlen, unsigned short product_id) :
     73 	IPXConnClass (numsend, numreceive,
     74 		maxlen + sizeof(GlobalHeaderType) - sizeof(CommHeaderType),
     75 		GLOBAL_MAGICNUM, 		// magic number for this connection
     76 		NULL,						// IPX Address (none)
     77 		0, 						// Connection ID
     78 		"",						// Connection Name
     79 		sizeof (IPXAddressClass))	// extra storage for the sender's address
     80 {
     81 	int i;
     82 
     83 	ProductID = product_id;
     84 	IsBridge = 0;
     85 
     86 	for (i = 0; i < 4; i++) {
     87 		LastPacketID[i] = 0xffffffff;
     88 	}
     89 	LastRXIndex = 0;
     90 
     91 }	/* end of IPXGlobalConnClass */
     92 
     93 
     94 /***************************************************************************
     95  * IPXGlobalConnClass::Send_Packet -- adds a packet to the send queue		*
     96  *                                                                         *
     97  * This routine prefixes the given buffer with a GlobalHeaderType and		*
     98  * queues the resulting packet into the Send Queue.  The packet's 			*
     99  * MagicNumber, Code, PacketID, destination Address and ProductID are set 	*
    100  * here. 																						*
    101  *                                                                         *
    102  * INPUT:                                                                  *
    103  *		buf			buffer to send															*
    104  *		buflen		length of buffer														*
    105  *		address		address to send the packet to (NULL = Broadcast)			*
    106  *		ack_req		1 = ACK is required for this packet; 0 = isn't				*
    107  *                                                                         *
    108  * OUTPUT:                                                                 *
    109  *		1 = OK, 0 = error																		*
    110  *                                                                         *
    111  * WARNINGS:                                                               *
    112  *		none.																						*
    113  *                                                                         *
    114  * HISTORY:                                                                *
    115  *   12/20/1994 BR : Created.                                              *
    116  *=========================================================================*/
    117 int IPXGlobalConnClass::Send_Packet (void * buf, int buflen,
    118 	IPXAddressClass *address, int ack_req)
    119 {
    120 	IPXAddressClass dest_addr;
    121 
    122 	/*------------------------------------------------------------------------
    123 	Store the packet's Magic Number
    124 	------------------------------------------------------------------------*/
    125 	((GlobalHeaderType *)PacketBuf)->Header.MagicNumber = MagicNum;
    126 
    127 	/*------------------------------------------------------------------------
    128 	If this is a ACK-required packet, sent to a specific system, mark it as
    129 	ACK-required; otherwise, mark as no-ACK-required.
    130 	------------------------------------------------------------------------*/
    131 	if (ack_req && address != NULL) {
    132 		((GlobalHeaderType *)PacketBuf)->Header.Code = PACKET_DATA_ACK;
    133 	}
    134 	else {
    135 		((GlobalHeaderType *)PacketBuf)->Header.Code = PACKET_DATA_NOACK;
    136 	}
    137 
    138 	/*------------------------------------------------------------------------
    139 	Fill in the packet ID.  This will have very limited meaning; it only
    140 	allows us to determine if an ACK packet we receive later goes with this
    141 	packet; it doesn't let us detect re-sends of other systems' packets.
    142 	------------------------------------------------------------------------*/
    143 	((GlobalHeaderType *)PacketBuf)->Header.PacketID = Queue->Send_Total();
    144 
    145 	/*------------------------------------------------------------------------
    146 	Set the product ID for this packet.
    147 	------------------------------------------------------------------------*/
    148 	((GlobalHeaderType *)PacketBuf)->ProductID = ProductID;
    149 
    150 	/*------------------------------------------------------------------------
    151 	Set this packet's destination address.  If no address is specified, use
    152 	a Broadcast address (which IPXAddressClass's default constructor creates).
    153 	------------------------------------------------------------------------*/
    154 	if (address != NULL) {
    155 		dest_addr = (*address);
    156 	}
    157 
    158 	/*------------------------------------------------------------------------
    159 	Copy the application's data
    160 	------------------------------------------------------------------------*/
    161 	memcpy(PacketBuf + sizeof(GlobalHeaderType), buf, buflen);
    162 
    163 	/*------------------------------------------------------------------------
    164 	Queue it, along with the destination address
    165 	------------------------------------------------------------------------*/
    166 	return(Queue->Queue_Send(PacketBuf,buflen + sizeof(GlobalHeaderType),
    167 		&dest_addr, sizeof (IPXAddressClass)));
    168 
    169 }	/* end of Send_Packet */
    170 
    171 
    172 /***************************************************************************
    173  * IPXGlobalConnClass::Receive_Packet -- adds packet to the receive queue	*
    174  *                                                                         *
    175  * INPUT:                                                                  *
    176  *		buf		buffer to process (already includes GlobalHeaderType)			*
    177  *		buflen	length of buffer to process											*
    178  *		address	the address of the sender (the IPX Manager class must			*
    179  *					extract this from the IPX Header of the received packet.)	*
    180  *                                                                         *
    181  * OUTPUT:                                                                 *
    182  *		1 = OK, 0 = error																		*
    183  *                                                                         *
    184  * WARNINGS:                                                               *
    185  *		none.																						*
    186  *                                                                         *
    187  * HISTORY:                                                                *
    188  *   12/20/1994 BR : Created.                                              *
    189  *=========================================================================*/
    190 int IPXGlobalConnClass::Receive_Packet (void * buf, int buflen,
    191 	IPXAddressClass *address)
    192 {
    193 	GlobalHeaderType *packet;				// ptr to this packet
    194 	SendQueueType *send_entry;				// ptr to send entry header
    195 	GlobalHeaderType *entry_data;			// ptr to queue entry data
    196 	GlobalHeaderType ackpacket;			// ACK packet to send
    197 	int i;
    198 	int resend;
    199 
    200 	/*------------------------------------------------------------------------
    201 	Check the magic #
    202 	------------------------------------------------------------------------*/
    203 	packet = (GlobalHeaderType *)buf;
    204 	if (packet->Header.MagicNumber!=MagicNum) {
    205 		return(0);
    206 	}
    207 
    208 	/*------------------------------------------------------------------------
    209 	Process the packet based on its Code
    210 	------------------------------------------------------------------------*/
    211 	switch (packet->Header.Code) {
    212 		//.....................................................................
    213 		// DATA_ACK: Check for a resend by comparing the source address &
    214 		// ID of this packet with our last 4 received packets.
    215 		// Send an ACK for the packet, regardless of whether it's a resend
    216 		// or not.
    217 		//.....................................................................
    218 		case PACKET_DATA_ACK:
    219 		{
    220 			//..................................................................
    221 			// Check for a resend
    222 			//..................................................................
    223 			resend = 0;
    224 			for (i = 0; i < 4; i++) {
    225 				if ((unsigned int)i >= Queue->Receive_Total()) {
    226 					break;
    227 				}
    228 				if ((*address)==LastAddress[i] &&
    229 					packet->Header.PacketID==LastPacketID[i]) {
    230 					resend = 1;
    231 					break;
    232 				}
    233 			}
    234 
    235 			bool send_ack = true;
    236 
    237 			//..................................................................
    238 			// If it's not a resend, queue it; then, record the sender's address
    239 			// & the packet ID for future resend detection.
    240 			//..................................................................
    241 			if (!resend) {
    242 				if (Queue->Queue_Receive (buf, buflen, address, sizeof(IPXAddressClass))) {
    243 					LastAddress[LastRXIndex] = (*address);
    244 					LastPacketID[LastRXIndex] = packet->Header.PacketID;
    245 					LastRXIndex++;
    246 					if (LastRXIndex >= 4) {
    247 						LastRXIndex = 0;
    248 					}
    249 				}else{
    250 					//..................................................................
    251 					// Don't send an ack if we didn't have room to store the packet.
    252 					//..................................................................
    253 					send_ack = false;
    254 				}
    255 			}
    256 
    257 
    258 			//..................................................................
    259 			// Send an ACK for this packet
    260 			//..................................................................
    261 			if (send_ack) {
    262 				ackpacket.Header.MagicNumber = MagicNum;
    263 				ackpacket.Header.Code = PACKET_ACK;
    264 				ackpacket.Header.PacketID = packet->Header.PacketID;
    265 				ackpacket.ProductID = ProductID;
    266 				Send ((char *)&ackpacket, sizeof(GlobalHeaderType),
    267 					address, sizeof(IPXAddressClass));
    268 			}
    269 
    270 
    271 			break;
    272 		}
    273 		/*.....................................................................
    274 		DATA_NOACK: Queue this message, along with the sender's address.
    275 		Don't bother checking for a Re-Send, since the other system will only
    276 		send this packet once.
    277 		.....................................................................*/
    278 		case PACKET_DATA_NOACK:
    279 			Queue->Queue_Receive (buf, buflen, address, sizeof(IPXAddressClass));
    280 			break;
    281 
    282 		/*.....................................................................
    283 		ACK: If this ACK is for any of my packets, mark that packet as
    284 		acknowledged, then throw this packet away.  Otherwise, ignore the ACK
    285 		(if we re-sent before we received the other system's first ACK, this
    286 		ACK will be a leftover)
    287 		.....................................................................*/
    288 		case PACKET_ACK:
    289 			for (i = 0; i < Queue->Num_Send(); i++) {
    290 				/*...............................................................
    291 				Get queue entry ptr
    292 				...............................................................*/
    293 				send_entry = Queue->Get_Send(i);
    294 
    295 				/*...............................................................
    296 				If ptr is valid, get ptr to its data
    297 				...............................................................*/
    298 				entry_data = (GlobalHeaderType *)(send_entry->Buffer);
    299 
    300 				/*...............................................................
    301 				If ACK is for this entry, mark it
    302 				...............................................................*/
    303 				if (packet->Header.PacketID==entry_data->Header.PacketID &&
    304 					entry_data->Header.Code == PACKET_DATA_ACK) {
    305 					send_entry->IsACK = 1;
    306 					break;
    307 				}
    308 			}
    309 			break;
    310 
    311 		/*.....................................................................
    312 		Default: ignore the packet
    313 		.....................................................................*/
    314 		default:
    315 			break;
    316 	}
    317 
    318 	return(1);
    319 
    320 }	/* end of Receive_Packet */
    321 
    322 
    323 /***************************************************************************
    324  * IPXGlobalConnClass::Get_Packet -- gets a packet from the receive queue	*
    325  *                                                                         *
    326  * INPUT:                                                                  *
    327  *		buf			location to store buffer											*
    328  *		buflen		filled in with length of 'buf'									*
    329  *		address		filled in with sender's address									*
    330  *		product_id	filled in with sender's ProductID								*
    331  *                                                                         *
    332  * OUTPUT:                                                                 *
    333  *		1 = OK, 0 = error																		*
    334  *                                                                         *
    335  * WARNINGS:                                                               *
    336  *		none.																						*
    337  *                                                                         *
    338  * HISTORY:                                                                *
    339  *   12/20/1994 BR : Created.                                              *
    340  *=========================================================================*/
    341 int IPXGlobalConnClass::Get_Packet (void * buf, int *buflen,
    342 	IPXAddressClass *address, unsigned short *product_id)
    343 {
    344 	ReceiveQueueType *rec_entry;					// ptr to receive entry header
    345 	GlobalHeaderType *packet;
    346 	int packetlen;										// size of received packet
    347 
    348 	/*------------------------------------------------------------------------
    349 	Return if nothing to do
    350 	------------------------------------------------------------------------*/
    351 	if (Queue->Num_Receive() == 0) {
    352 		return(0);
    353 	}
    354 
    355 	/*------------------------------------------------------------------------
    356 	Get ptr to the next available entry
    357 	------------------------------------------------------------------------*/
    358 	rec_entry = Queue->Get_Receive(0);
    359 
    360 	/*------------------------------------------------------------------------
    361 	Read it if it's un-read
    362 	------------------------------------------------------------------------*/
    363 	if (rec_entry!=NULL && rec_entry->IsRead==0) {
    364 
    365 		/*.....................................................................
    366 		Mark as read
    367 		.....................................................................*/
    368 		rec_entry->IsRead = 1;
    369 
    370 		/*.....................................................................
    371 		Copy data packet
    372 		.....................................................................*/
    373 		packet = (GlobalHeaderType *)(rec_entry->Buffer);
    374 		packetlen = rec_entry->BufLen - sizeof(GlobalHeaderType);
    375 		if (packetlen > 0) {
    376 			memcpy(buf, rec_entry->Buffer + sizeof(GlobalHeaderType), packetlen);
    377 		}
    378 		(*buflen) = packetlen;
    379 		(*product_id) = packet->ProductID;
    380 		(*address) = (*((IPXAddressClass *)(rec_entry->ExtraBuffer)));
    381 
    382 		return(1);
    383 	}
    384 
    385 	return(0);
    386 
    387 }	/* end of Get_Packet */
    388 
    389 
    390 /***************************************************************************
    391  * IPXGlobalConnClass::Send -- sends a packet										*
    392  *                                                                         *
    393  * This routine gets invoked by NonSequencedConn, when it's processing		*
    394  * the Send & Receive Queues.  The buffer provided will already have the	*
    395  * GlobalHeaderType header embedded in it.											*
    396  *                                                                         *
    397  * INPUT:                                                                  *
    398  *		buf			buffer to send															*
    399  *		buflen		length of buffer														*
    400  *		extrabuf		extra buffer to send													*
    401  *		extralen		length of extra buffer												*
    402  *                                                                         *
    403  * OUTPUT:                                                                 *
    404  *		1 = OK, 0 = error																		*
    405  *                                                                         *
    406  * WARNINGS:                                                               *
    407  *		none.																						*
    408  *                                                                         *
    409  * HISTORY:                                                                *
    410  *   12/20/1994 BR : Created.                                              *
    411  *=========================================================================*/
    412 int IPXGlobalConnClass::Send(char *buf, int buflen, void *extrabuf, int )
    413 {
    414 	IPXAddressClass *addr;
    415 	int rc;
    416 
    417 	/*------------------------------------------------------------------------
    418 	Extract the packet's embedded IPX address
    419 	------------------------------------------------------------------------*/
    420 	addr = (IPXAddressClass *)extrabuf;
    421 
    422 	/*------------------------------------------------------------------------
    423 	If it's a broadcast address, broadcast it
    424 	------------------------------------------------------------------------*/
    425 	if (addr->Is_Broadcast()) {
    426 		return(Broadcast (buf, buflen));
    427 	}
    428 
    429 	/*------------------------------------------------------------------------
    430 	Otherwise, send it
    431 	------------------------------------------------------------------------*/
    432 	else {
    433 		if (IsBridge && !memcmp (addr, BridgeNet, 4)) {
    434 			rc = Send_To (buf, buflen, addr, BridgeNode);
    435 		}
    436 		else {
    437 			rc = Send_To (buf, buflen, addr, NULL);
    438 		}
    439 		return (rc);
    440 	}
    441 
    442 } 	/* end of Send */
    443 
    444 
    445 /***************************************************************************
    446  * IPXGlobalConnClass::Service_Receive_Queue -- services the receive queue	*
    447  *                                                                         *
    448  * This routine is necessary because the regular ConnectionClass checks		*
    449  * for sequential packet ID's before removing them from the receive queue;	*
    450  * this class cannot do that.																*
    451  *                                                                         *
    452  * INPUT:                                                                  *
    453  *		none.																						*
    454  *                                                                         *
    455  * OUTPUT:                                                                 *
    456  *		1 = OK, 0 = error																		*
    457  *                                                                         *
    458  * WARNINGS:                                                               *
    459  *		none.																						*
    460  *                                                                         *
    461  * HISTORY:                                                                *
    462  *   12/20/1994 BR : Created.                                              *
    463  *=========================================================================*/
    464 int IPXGlobalConnClass::Service_Receive_Queue (void)
    465 {
    466 	int i;
    467 	ReceiveQueueType *rec_entry;					// ptr to receive entry header
    468 
    469 	//------------------------------------------------------------------------
    470 	// Remove all dead packets:  If a packet's been read, throw it away.
    471 	//------------------------------------------------------------------------
    472 	for (i = 0; i < Queue->Num_Receive(); i++) {
    473 		rec_entry = Queue->Get_Receive(i);
    474 
    475 		if (rec_entry->IsRead) {
    476 			Queue->UnQueue_Receive(NULL,NULL,i,NULL,NULL);
    477 			i--;
    478 		}
    479 	}
    480 
    481 	return (1);
    482 
    483 } 	/* end of Service_Receive_Queue */
    484 
    485 
    486 /***************************************************************************
    487  * Set_Bridge -- Sets up connection to cross a bridge                      *
    488  *                                                                         *
    489  * This routine is designed to prevent the connection from having to			*
    490  * call Get_Local_Target, except the minimum number of times, since that	*
    491  * routine is buggy & goes away for long periods sometimes.						*
    492  *                                                                         *
    493  * INPUT:                                                                  *
    494  *		bridge		network number of the destination bridge						*
    495  *                                                                         *
    496  * OUTPUT:                                                                 *
    497  *		none																						*
    498  *                                                                         *
    499  * WARNINGS:                                                               *
    500  *		none																						*
    501  *                                                                         *
    502  * HISTORY:                                                                *
    503  *   07/06/1995 BRR : Created.                                             *
    504  *=========================================================================*/
    505 void IPXGlobalConnClass::Set_Bridge(NetNumType bridge)
    506 {
    507 #ifdef WINSOCK_IPX
    508 
    509 	if (Configured) {
    510 		bridge = bridge;
    511 		IsBridge = 0;
    512 	}
    513 
    514 #else	//WINSOCK_IPX
    515 	if (Configured) {
    516 		memcpy (BridgeNet, bridge, 4);
    517 		memset (BridgeNode, 0xff, 6);
    518 
    519 		if (IPX_Get_Local_Target (BridgeNet, BridgeNode, Socket, BridgeNode)==0) {
    520 			IsBridge = 1;
    521 		}
    522 		else {
    523 			IsBridge = 0;
    524 		}
    525 	}
    526 #endif	//WINSOCK_IPX
    527 
    528 } 	/* end of Set_Bridge */
    529 
    530 
    531 /************************** end of ipxgconn.cpp ****************************/