CnC_Remastered_Collection

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

IPXGCONN.CPP (22629B)


      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:   F:\projects\c&c\vcs\code\ipxgconn.cpv   1.9   16 Oct 1995 16:51:00   JOE_BOSTIC  $ */
     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 recieve queue	*
     39  *   IPXGlobalConnClass::Set_Bridge -- Sets up connection to cross a bridge*
     40 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     41 
     42 #include "function.h"
     43 
     44 
     45 /***************************************************************************
     46  * IPXGlobalConnClass::IPXGlobalConnClass -- class constructor             *
     47  *                                                                         *
     48  * This routine chains to the parent constructor, but it adjusts the size	*
     49  * of the packet by the added bytes in the GlobalHeaderType structure.  	*
     50  * This forces the parent classes to allocate the proper sized PacketBuf	*
     51  * for outgoing packets, and to set MaxPacketLen to the proper value.		*
     52  *                                                                         *
     53  * INPUT:                                                                  *
     54  *		numsend			desired # of entries for the send queue					*
     55  *		numreceive		desired # of entries for the recieve queue				*
     56  *		maxlen			max length of an application packet							*
     57  *		product_id		unique ID for this product										*
     58  *                                                                         *
     59  * OUTPUT:                                                                 *
     60  *		none.																						*
     61  *                                                                         *
     62  * WARNINGS:                                                               *
     63  *		none.																						*
     64  *                                                                         *
     65  * HISTORY:                                                                *
     66  *   12/20/1994 BR : Created.                                              *
     67  *=========================================================================*/
     68 IPXGlobalConnClass::IPXGlobalConnClass (int numsend, int numreceive, int maxlen,
     69 	unsigned short product_id) :
     70 	IPXConnClass (numsend, numreceive,
     71 		maxlen + sizeof(GlobalHeaderType) - sizeof(CommHeaderType),
     72 		GLOBAL_MAGICNUM, 		// magic number for this connection
     73 		NULL,						// IPX Address (none)
     74 		0, 						// Connection ID
     75 		"")						// Connection Name
     76 {
     77 	ProductID = product_id;
     78 	IsBridge = 0;
     79 
     80 }	/* end of IPXGlobalConnClass */
     81 
     82 
     83 /***************************************************************************
     84  * IPXGlobalConnClass::Send_Packet -- adds a packet to the send queue		*
     85  *                                                                         *
     86  * This routine prefixes the given buffer with a GlobalHeaderType and		*
     87  * queues the resulting packet into the Send Queue.  The packet's 			*
     88  * MagicNumber, Code, PacketID, destination Address and ProductID are set 	*
     89  * here. 																						*
     90  *                                                                         *
     91  * INPUT:                                                                  *
     92  *		buf			buffer to send															*
     93  *		buflen		length of buffer														*
     94  *		address		address to send the packet to (NULL = Broadcast)			*
     95  *		ack_req		true = ACK is required for this packet; false = isn't		*
     96  *                                                                         *
     97  * OUTPUT:                                                                 *
     98  *		1 = OK, 0 = error																		*
     99  *                                                                         *
    100  * WARNINGS:                                                               *
    101  *		none.																						*
    102  *                                                                         *
    103  * HISTORY:                                                                *
    104  *   12/20/1994 BR : Created.                                              *
    105  *=========================================================================*/
    106 int IPXGlobalConnClass::Send_Packet (void * buf, int buflen,
    107 	IPXAddressClass *address, int ack_req)
    108 {
    109 	/*------------------------------------------------------------------------
    110 	Store the packet's Magic Number
    111 	------------------------------------------------------------------------*/
    112 	((GlobalHeaderType *)PacketBuf)->Header.MagicNumber = MagicNum;
    113 
    114 	/*------------------------------------------------------------------------
    115 	If this is a ACK-required packet, sent to a specific system, mark it as
    116 	ACK-required; otherwise, mark as no-ACK-required.
    117 	------------------------------------------------------------------------*/
    118 	if (ack_req && address != NULL) {
    119 		((GlobalHeaderType *)PacketBuf)->Header.Code = PACKET_DATA_ACK;
    120 	} else {
    121 		((GlobalHeaderType *)PacketBuf)->Header.Code = PACKET_DATA_NOACK;
    122 	}
    123 
    124 	/*------------------------------------------------------------------------
    125 	Fill in the packet ID.  This will have very limited meaning; it only
    126 	allows us to determine if an ACK packet we receive later goes with this
    127 	packet; it doesn't let us detect re-sends of other systems' packets.
    128 	------------------------------------------------------------------------*/
    129 	((GlobalHeaderType *)PacketBuf)->Header.PacketID = Queue->Send_Total();
    130 
    131 	/*------------------------------------------------------------------------
    132 	Set the product ID for this packet.
    133 	------------------------------------------------------------------------*/
    134 	((GlobalHeaderType *)PacketBuf)->ProductID = ProductID;
    135 
    136 	/*------------------------------------------------------------------------
    137 	Set this packet's destination address.  If no address is specified, use
    138 	a Broadcast address (which IPXAddressClass's default constructor creates).
    139 	------------------------------------------------------------------------*/
    140 	if (address != NULL) {
    141 		((GlobalHeaderType *)PacketBuf)->Address = (*address);
    142 	} else {
    143 		((GlobalHeaderType *)PacketBuf)->Address = IPXAddressClass();
    144 	}
    145 
    146 	/*------------------------------------------------------------------------
    147 	Copy the application's data
    148 	------------------------------------------------------------------------*/
    149 	memcpy(PacketBuf + sizeof(GlobalHeaderType), buf, buflen);
    150 
    151 	/*------------------------------------------------------------------------
    152 	Queue it
    153 	------------------------------------------------------------------------*/
    154 	return(Queue->Queue_Send(PacketBuf,buflen + sizeof(GlobalHeaderType)));
    155 
    156 }	/* end of Send_Packet */
    157 
    158 
    159 /***************************************************************************
    160  * IPXGlobalConnClass::Receive_Packet -- adds packet to the receive queue	*
    161  *                                                                         *
    162  * INPUT:                                                                  *
    163  *		buf		buffer to process (already includes GlobalHeaderType)			*
    164  *		buflen	length of buffer to process											*
    165  *		address	the address of the sender (the IPX Manager class must			*
    166  *					extract this from the IPX Header of the received packet.)	*
    167  *                                                                         *
    168  * OUTPUT:                                                                 *
    169  *		1 = OK, 0 = error																		*
    170  *                                                                         *
    171  * WARNINGS:                                                               *
    172  *		none.																						*
    173  *                                                                         *
    174  * HISTORY:                                                                *
    175  *   12/20/1994 BR : Created.                                              *
    176  *=========================================================================*/
    177 int IPXGlobalConnClass::Receive_Packet (void * buf, int buflen,
    178 	IPXAddressClass *address)
    179 {
    180 	GlobalHeaderType *packet;				// ptr to this packet
    181 	SendQueueType *send_entry;				// ptr to send entry header
    182 	GlobalHeaderType *entry_data;			// ptr to queue entry data
    183 	int i;
    184 
    185 	/*
    186 	--------------------------- Check the magic # ----------------------------
    187 	*/
    188 	packet = (GlobalHeaderType *)buf;
    189 	if (packet->Header.MagicNumber!=MagicNum) {
    190 		return(false);
    191 	}
    192 
    193 	/*------------------------------------------------------------------------
    194 	Process the packet based on its Code
    195 	------------------------------------------------------------------------*/
    196 	switch (packet->Header.Code) {
    197 		/*.....................................................................
    198 		DATA: Save the given address in the message buffer (so Get_Message()
    199 		can extract it later), and queue this message.
    200 		Don't bother checking for a Re-Send; since this queue is receiving data
    201 		from multiple systems, the Total_Receive() value for this queue will
    202 		have nothing to do with the packet's ID.  The application must deal
    203 		with this by being able to handle multiple receipts of the same packet.
    204 		.....................................................................*/
    205 		case PACKET_DATA_ACK:
    206 		case PACKET_DATA_NOACK:
    207 			packet->Address = (*address);
    208 			Queue->Queue_Receive (buf, buflen);
    209 			break;
    210 
    211 		/*.....................................................................
    212 		ACK: If this ACK is for any of my packets, mark that packet as
    213 		acknowledged, then throw this packet away.  Otherwise, ignore the ACK
    214 		(if we re-sent before we received the other system's first ACK, this
    215 		ACK will be a leftover)
    216 		.....................................................................*/
    217 		case PACKET_ACK:
    218 			for (i = 0; i < Queue->Num_Send(); i++) {
    219 				/*
    220 				..................... Get queue entry ptr .......................
    221 				*/
    222 				send_entry = Queue->Get_Send(i);
    223 				/*
    224 				............. If ptr is valid, get ptr to its data ..............
    225 				*/
    226 				entry_data = (GlobalHeaderType *)(send_entry->Buffer);
    227 				/*
    228 				.............. If ACK is for this entry, mark it ................
    229 				*/
    230 				if (packet->Header.PacketID==entry_data->Header.PacketID &&
    231 					entry_data->Header.Code == PACKET_DATA_ACK) {
    232 					send_entry->IsACK = 1;
    233 					break;
    234 				}
    235 			}
    236 			break;
    237 
    238 		/*.....................................................................
    239 		Default: ignore the packet
    240 		.....................................................................*/
    241 		default:
    242 			break;
    243 
    244 	}	/* end of switch */
    245 
    246 	return(true);
    247 }
    248 
    249 
    250 /***************************************************************************
    251  * IPXGlobalConnClass::Get_Packet -- gets a packet from the receive queue	*
    252  *                                                                         *
    253  * INPUT:                                                                  *
    254  *		buf			location to store buffer											*
    255  *		buflen		filled in with length of 'buf'									*
    256  *		address		filled in with sender's address									*
    257  *		product_id	filled in with sender's ProductID								*
    258  *                                                                         *
    259  * OUTPUT:                                                                 *
    260  *		1 = OK, 0 = error																		*
    261  *                                                                         *
    262  * WARNINGS:                                                               *
    263  *		none.																						*
    264  *                                                                         *
    265  * HISTORY:                                                                *
    266  *   12/20/1994 BR : Created.                                              *
    267  *=========================================================================*/
    268 int IPXGlobalConnClass::Get_Packet (void * buf, int *buflen,
    269 	IPXAddressClass *address, unsigned short *product_id)
    270 {
    271 	ReceiveQueueType *rec_entry;					// ptr to receive entry header
    272 	GlobalHeaderType *packet;
    273 	int packetlen;										// size of received packet
    274 
    275 	/*
    276 	------------------------ Return if nothing to do -------------------------
    277 	*/
    278 	if (Queue->Num_Receive() == 0) {
    279 		return(false);
    280 	}
    281 
    282 	/*
    283 	------------------ Get ptr to the next available entry -------------------
    284 	*/
    285 	rec_entry = Queue->Get_Receive(0);
    286 
    287 	/*
    288 	------------------------ Read it if it's un-read -------------------------
    289 	*/
    290 	if (rec_entry!=NULL && rec_entry->IsRead==0) {
    291 		/*
    292 		........................... Mark as read ..............................
    293 		*/
    294 		rec_entry->IsRead = 1;
    295 
    296 		/*
    297 		.......................... Copy data packet ...........................
    298 		*/
    299 		packet = (GlobalHeaderType *)(rec_entry->Buffer);
    300 		packetlen = rec_entry->BufLen - sizeof(GlobalHeaderType);
    301 		if (packetlen > 0)
    302 			memcpy(buf, rec_entry->Buffer + sizeof(GlobalHeaderType), packetlen);
    303 		(*buflen) = packetlen;
    304 		(*address) = packet->Address;
    305 		(*product_id) = packet->ProductID;
    306 
    307 		return(true);
    308 	}
    309 
    310 	return(false);
    311 }
    312 
    313 
    314 /***************************************************************************
    315  * IPXGlobalConnClass::Send -- sends a packet										*
    316  *                                                                         *
    317  * This routine gets invoked by NonSequencedConn, when it's processing		*
    318  * the Send & Receive Queues.  The buffer provided will already have the	*
    319  * GlobalHeaderType header embedded in it.											*
    320  *                                                                         *
    321  * INPUT:                                                                  *
    322  *		buf		buffer to send																*
    323  *		buflen	length of buffer															*
    324  *                                                                         *
    325  * OUTPUT:                                                                 *
    326  *		1 = OK, 0 = error																		*
    327  *                                                                         *
    328  * WARNINGS:                                                               *
    329  *		none.																						*
    330  *                                                                         *
    331  * HISTORY:                                                                *
    332  *   12/20/1994 BR : Created.                                              *
    333  *=========================================================================*/
    334 int IPXGlobalConnClass::Send(char *buf, int buflen)
    335 {
    336 	IPXAddressClass *addr;
    337 	int rc;
    338 
    339 	/*------------------------------------------------------------------------
    340 	Extract the packet's embedded IPX address
    341 	------------------------------------------------------------------------*/
    342 	addr = &(((GlobalHeaderType *)buf)->Address);
    343 
    344 	/*------------------------------------------------------------------------
    345 	If it's a broadcast address, broadcast it
    346 	------------------------------------------------------------------------*/
    347 	if (addr->Is_Broadcast()) {
    348 		return(Broadcast (buf, buflen));
    349 	}  else {
    350 		/*------------------------------------------------------------------------
    351 		Otherwise, send it
    352 		------------------------------------------------------------------------*/
    353 		if (IsBridge && !memcmp (addr, BridgeNet, 4)) {
    354 			rc = Send_To (buf, buflen, &(((GlobalHeaderType *)buf)->Address),
    355 				BridgeNode);
    356 		} else {
    357 			rc = Send_To (buf, buflen, &(((GlobalHeaderType *)buf)->Address), NULL);
    358 		}
    359 		return (rc);
    360 	}
    361 
    362 }	/* end of Send */
    363 
    364 
    365 /***************************************************************************
    366  * IPXGlobalConnClass::Service_Receive_Queue -- services the recieve queue	*
    367  *                                                                         *
    368  * This routine is necessary because the Global Connection has to ACK		*
    369  * a packet differently from other types of connections; its Send routine	*
    370  * assumes that the destination address is embedded within the outgoing		*
    371  * packet, so we have to create our ACK Packet using the GlobalHeaderType,	*
    372  * not the CommHeaderType.																	*
    373  *                                                                         *
    374  * INPUT:                                                                  *
    375  *		none.																						*
    376  *                                                                         *
    377  * OUTPUT:                                                                 *
    378  *		1 = OK, 0 = error																		*
    379  *                                                                         *
    380  * WARNINGS:                                                               *
    381  *		none.																						*
    382  *                                                                         *
    383  * HISTORY:                                                                *
    384  *   12/20/1994 BR : Created.                                              *
    385  *=========================================================================*/
    386 int IPXGlobalConnClass::Service_Receive_Queue (void)
    387 {
    388 	GlobalHeaderType ackpacket;					// ACK packet to send
    389 	ReceiveQueueType *rec_entry;					// ptr to receive entry header
    390 	GlobalHeaderType *packet_hdr;					// packet header
    391 
    392 	/*------------------------------------------------------------------------
    393 	Get a pointer to the next received entry
    394 	------------------------------------------------------------------------*/
    395 	rec_entry = Queue->Get_Receive(0);
    396 	if (rec_entry==NULL)
    397 		return(1);
    398 
    399 	/*------------------------------------------------------------------------
    400 	If this packet doesn't require an ACK, mark it as ACK'd.
    401 	------------------------------------------------------------------------*/
    402 	packet_hdr = (GlobalHeaderType *)(rec_entry->Buffer);
    403 	if (packet_hdr->Header.Code==PACKET_DATA_NOACK)
    404 		rec_entry->IsACK = 1;
    405 
    406 	/*------------------------------------------------------------------------
    407 	If this packet hasn't been ACK'd, send an ACK:
    408 	- Fill in the MagicNum & the Code
    409 	- Set the PacketID to the same ID that the sending system used, so the
    410 	  sending system knows which packet the ACK is for
    411 	------------------------------------------------------------------------*/
    412 	if (rec_entry->IsACK==0) {
    413 		ackpacket.Header.MagicNumber = MagicNum;
    414 		ackpacket.Header.Code = PACKET_ACK;
    415 		ackpacket.Header.PacketID = packet_hdr->Header.PacketID;
    416 		ackpacket.Address = packet_hdr->Address;
    417 		ackpacket.ProductID = ProductID;
    418 
    419 		Send ((char *)&ackpacket, sizeof(GlobalHeaderType));
    420 
    421 		rec_entry->IsACK = 1;
    422 	}
    423 
    424 	/*------------------------------------------------------------------------
    425 	If this packet has been read by the application, and has been ACK'd, and
    426 	there is another packet in the queue behind this one, it means the other
    427 	system got the ACK we sent for this packet; remove this packet from the
    428 	queue.
    429 	------------------------------------------------------------------------*/
    430 	if (rec_entry!=NULL && rec_entry->IsRead && rec_entry->IsACK &&
    431 		Queue->Num_Receive() > 1)
    432 		Queue->UnQueue_Receive(NULL,NULL,0);
    433 
    434 	return(1);
    435 
    436 }	/* end of Service_Receive_Queue */
    437 
    438 /***************************************************************************
    439  * Set_Bridge -- Sets up connection to cross a bridge                      *
    440  *                                                                         *
    441  * This routine is designed to prevent the connection from having to			*
    442  * call Get_Local_Target, except the minimum number of times, since that	*
    443  * routine is buggy & goes away for long periods sometimes.						*
    444  *                                                                         *
    445  * INPUT:                                                                  *
    446  *		bridge		network number of the destination bridge						*
    447  *                                                                         *
    448  * OUTPUT:                                                                 *
    449  *		none																						*
    450  *                                                                         *
    451  * WARNINGS:                                                               *
    452  *		none																						*
    453  *                                                                         *
    454  * HISTORY:                                                                *
    455  *   07/06/1995 BRR : Created.                                             *
    456  *=========================================================================*/
    457 void IPXGlobalConnClass::Set_Bridge(NetNumType bridge)
    458 {
    459 	if (Configured) {
    460 		memcpy (BridgeNet, bridge, 4);
    461 		memset (BridgeNode, 0xff, 6);
    462 
    463 		if (IPX_Get_Local_Target (BridgeNet, BridgeNode, Socket, BridgeNode)==0) {
    464 			IsBridge = 1;
    465 		} else {
    466 			IsBridge = 0;
    467 		}
    468 	}
    469 }
    470