CnC_Remastered_Collection

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

SEQCONN.CPP (24567B)


      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\seqconn.cpv   1.9   16 Oct 1995 16:51:30   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 : SEQCONN.CPP                              *
     24  *                                                                         *
     25  *                   Programmer : Bill Randolph                            *
     26  *                                                                         *
     27  *                   Start Date : December 20, 1994                        *
     28  *                                                                         *
     29  *                  Last Update : April 9, 1995 [BRR]								*
     30  *                                                                         *
     31  *-------------------------------------------------------------------------*
     32  * Functions:    			                                                   *
     33  *   SequencedConnClass::SequencedConnClass -- class constructor           *
     34  *   SequencedConnClass::~SequencedConnClass -- class destructor           *
     35  *   SequencedConnClass::Init -- Initializes connection queue to empty		*
     36  *   SequencedConnClass::Send_Packet -- adds a packet to the send queue		*
     37  *   SequencedConnClass::Receive_Packet -- adds packet to receive queue		*
     38  *   SequencedConnClass::Get_Packet -- gets a packet from receive queue		*
     39  *   SequencedConnClass::Service_Send_Queue -- services the send queue		*
     40  *   SequencedConnClass::Service_Receive_Queue -- services recieve queue	*
     41  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     42 
     43 #include "function.h"
     44 
     45 // PG_TO_FIX
     46 #if (0)
     47 
     48 /***************************************************************************
     49  * SequencedConnClass::SequencedConnClass -- class constructor             *
     50  *                                                                         *
     51  * INPUT:                                                                  *
     52  *		numsend			desired # of entries for the send queue					*
     53  *		numreceive		desired # of entries for the recieve queue				*
     54  *		maxlen			max length of an application packet							*
     55  *		magicnum			the packet "magic number" for this connection			*
     56  *		retry_delta		the time to wait between sends								*
     57  *		max_retries		the max # of retries allowed for a packet					*
     58  *							(-1 means retry forever, based on this parameter)		*
     59  *		timeout			the max amount of time before we give up on a packet	*
     60  *							(-1 means retry forever, based on this parameter)		*
     61  *                                                                         *
     62  * OUTPUT:                                                                 *
     63  *		none.																						*
     64  *                                                                         *
     65  * WARNINGS:                                                               *
     66  *		none.																						*
     67  *                                                                         *
     68  * HISTORY:                                                                *
     69  *   12/20/1994 BR : Created.                                              *
     70  *=========================================================================*/
     71 SequencedConnClass::SequencedConnClass (int numsend, int numreceive, 
     72 	int maxlen, unsigned short magicnum, unsigned long retry_delta,
     73 	unsigned long max_retries, unsigned long timeout) :
     74 	ConnectionClass (maxlen, magicnum, retry_delta, max_retries, timeout)
     75 {
     76 	NumRecNoAck = 0;
     77 	NumRecAck = 0;
     78 	NumSendNoAck = 0;
     79 	NumSendAck = 0;
     80 
     81 	/*------------------------------------------------------------------------
     82 	Allocate the packet Queue.  This will store incoming packets (which will
     83 	be placed there by the Connection Manager), and outgoing packets (which
     84 	are placed there by this class when it "sends" a packet).
     85 	------------------------------------------------------------------------*/
     86 	Queue = new CommQueueClass (numsend, numreceive, MaxPacketLen);
     87 
     88 }	/* end of SequencedConnClass */
     89 
     90 
     91 /***************************************************************************
     92  * SequencedConnClass::~SequencedConnClass -- class destructor             *
     93  *                                                                         *
     94  * INPUT:                                                                  *
     95  *		none.																						*
     96  *                                                                         *
     97  * OUTPUT:                                                                 *
     98  *		none.																						*
     99  *                                                                         *
    100  * WARNINGS:                                                               *
    101  *		none.																						*
    102  *                                                                         *
    103  * HISTORY:                                                                *
    104  *   12/20/1994 BR : Created.                                              *
    105  *=========================================================================*/
    106 SequencedConnClass::~SequencedConnClass ()
    107 {
    108 	delete Queue;
    109 }
    110 
    111 
    112 /***************************************************************************
    113  * SequencedConnClass::Init -- Initializes connection queue to empty			*
    114  *                                                                         *
    115  * INPUT:                                                                  *
    116  *		none.																						*
    117  *                                                                         *
    118  * OUTPUT:                                                                 *
    119  *		none.																						*
    120  *                                                                         *
    121  * WARNINGS:                                                               *
    122  *		none.																						*
    123  *                                                                         *
    124  * HISTORY:                                                                *
    125  *   12/20/1994 BR : Created.                                              *
    126  *=========================================================================*/
    127 void SequencedConnClass::Init (void)
    128 {
    129 	Queue->Init();
    130 
    131 }	/* end of Init */
    132 
    133 
    134 /***************************************************************************
    135  * SequencedConnClass::Send_Packet -- adds a packet to the send queue		*
    136  *                                                                         *
    137  * This routine prefixes the given buffer with a CommHeaderType and			*
    138  * queues the resulting packet into the Send Queue.  (It's actually the		*
    139  * Service() routine that handles the hardware-dependent Send of the data).*
    140  * The packet's MagicNumber, Code, and PacketID are set here.					*
    141  *                                                                         *
    142  * INPUT:                                                                  *
    143  *		buf			buffer to send															*
    144  *		buflen		length of buffer														*
    145  *		ack_req		true = ACK is required for this packet; false = isn't		*
    146  *                                                                         *
    147  * OUTPUT:                                                                 *
    148  *		1 = packet was queue'd OK, 0 = wasn't											*
    149  *                                                                         *
    150  * WARNINGS:                                                               *
    151  *		none.																						*
    152  *                                                                         *
    153  * HISTORY:                                                                *
    154  *   12/20/1994 BR : Created.                                              *
    155  *=========================================================================*/
    156 int SequencedConnClass::Send_Packet (void * buf, int buflen, int ack_req)
    157 {
    158 	/*........................................................................
    159 	Set the magic # for the packet
    160 	........................................................................*/
    161 	((CommHeaderType *)PacketBuf)->MagicNumber = MagicNum;
    162 
    163 	/*........................................................................
    164 	Set the packet Code: DATA_ACK if it requires an ACK, NOACK if it doesn't
    165 	Set the packet ID to the appropriate counter value.
    166 	........................................................................*/
    167 	if (ack_req) {
    168 		((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_ACK;
    169 		((CommHeaderType *)PacketBuf)->PacketID = NumSendAck;
    170 	} else {
    171 		((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_NOACK;
    172 		((CommHeaderType *)PacketBuf)->PacketID = NumSendNoAck;
    173 	}
    174 
    175 	/*........................................................................
    176 	Now build the packet
    177 	........................................................................*/
    178 	memcpy(PacketBuf + sizeof(CommHeaderType), buf, buflen);
    179 
    180 	/*........................................................................
    181 	Add it to the queue.
    182 	........................................................................*/
    183 	if (Queue->Queue_Send(PacketBuf,buflen + sizeof(CommHeaderType))) {
    184 		if (ack_req) {
    185 			NumSendAck++;
    186 		} else {
    187 			NumSendNoAck++;
    188 		}
    189 		return(true);
    190 
    191 	} else {
    192 		return(false);
    193 	}
    194 }
    195 
    196 
    197 /***************************************************************************
    198  * SequencedConnClass::Receive_Packet -- adds packet to the receive queue	*
    199  *                                                                         *
    200  * INPUT:                                                                  *
    201  *		buf		buffer to process (already includes CommHeaderType)			*
    202  *		buflen	length of buffer to process											*
    203  *                                                                         *
    204  * OUTPUT:                                                                 *
    205  *		1 = packet was processed OK, 0 = error											*
    206  *                                                                         *
    207  * WARNINGS:                                                               *
    208  *		none.																						*
    209  *                                                                         *
    210  * HISTORY:                                                                *
    211  *   12/20/1994 BR : Created.                                              *
    212  *=========================================================================*/
    213 int SequencedConnClass::Receive_Packet (void * buf, int buflen)
    214 {
    215 	CommHeaderType *packet;					// ptr to this packet
    216 	SendQueueType *send_entry;				// ptr to send entry header
    217 	ReceiveQueueType *rec_entry;			// ptr to receive entry header
    218 	CommHeaderType *entry_data;			// ptr to queue entry data
    219 	int save_packet = 1;						// 0 = this is a resend, or 
    220 													//  out-of-order packet
    221 
    222 	/*
    223 	--------------------------- Check the magic # ----------------------------
    224 	*/
    225 	packet = (CommHeaderType *)buf;
    226 	if (packet->MagicNumber!=MagicNum)
    227 		return(false);
    228 	
    229 	/*------------------------------------------------------------------------
    230 	Process the packet based on its Code
    231 	------------------------------------------------------------------------*/
    232 	switch (packet->Code) {
    233 		/*.....................................................................
    234 		DATA: If this is a No-Ack packet, always save it.  Otherwise, only
    235 		save it if it's received in the proper sequence.
    236 		.....................................................................*/
    237 		case PACKET_DATA_ACK:
    238 		case PACKET_DATA_NOACK:
    239 			if (packet->Code == PACKET_DATA_NOACK) {
    240 #ifdef DEBUG_SEQ
    241 printf("PACKET_DATA_NOACK received (%d)\n",packet->PacketID);
    242 #endif
    243 				save_packet = 1;
    244 			} else {
    245 #ifdef DEBUG_SEQ
    246 printf("PACKET_DATA_ACK received (%d)\n",packet->PacketID);
    247 #endif
    248 				if ((packet->PacketID == NumRecAck)) {
    249 					save_packet = 1;
    250 				} else {
    251 					save_packet = 0;
    252 					/*...............................................................
    253 					If this is a resend of our next-available received message, it 
    254 					means the other app didn't get our ACK, so mark it as 
    255 					non-acknowledged to tell Service_Receive_Queue to send an ACK.
    256 					...............................................................*/
    257 					rec_entry = Queue->Next_Receive();
    258 					if (rec_entry) {
    259 						entry_data = (CommHeaderType *)rec_entry->Buffer;
    260 						if (entry_data->PacketID==packet->PacketID &&
    261 							entry_data->Code == PACKET_DATA_ACK) {
    262 							rec_entry->IsACK = 0;
    263 #ifdef DEBUG_SEQ
    264 printf("(Resend)\n");
    265 #endif
    266 						}
    267 					}
    268 				}
    269 			}
    270 
    271 			/*
    272 			...................... queue this packet ........................
    273 			*/
    274 			if (save_packet) {
    275 				if (!Queue->Queue_Receive(buf, buflen)) {
    276 					return(false);
    277 				}
    278 				if (packet->Code == PACKET_DATA_ACK) {
    279 					NumRecAck++;
    280 				} else {
    281 					NumRecNoAck++;
    282 				}
    283 			}
    284 			break;
    285 
    286 		/*.....................................................................
    287 		ACK: If this ACK is for the latest-sent packet, mark that packet as 
    288 		acknowledged, then throw this packet away.  Otherwise, ignore the ACK 
    289 		(if we re-sent before we received the other system's first ACK, this 
    290 		ACK will be a leftover)
    291 		.....................................................................*/
    292 		case PACKET_ACK:
    293 #ifdef DEBUG_SEQ
    294 printf("ACK received (%d)\n",packet->PacketID);
    295 #endif
    296 			/*
    297 			....................... Get queue entry ptr ........................
    298 			*/
    299 			send_entry = Queue->Next_Send();
    300 			/*
    301 			............... If ptr is valid, get ptr to its data ...............
    302 			*/
    303 			if (send_entry!=NULL) {
    304 				entry_data = (CommHeaderType *)send_entry->Buffer;
    305 
    306 				/*
    307 				.............. If ACK is for this entry, mark it ................
    308 				*/
    309 				if (packet->PacketID==entry_data->PacketID && 
    310 					entry_data->Code == PACKET_DATA_ACK) {
    311 					send_entry->IsACK = 1;
    312 				}
    313 			}
    314 			break;
    315 		
    316 		/*.....................................................................
    317 		Default: ignore the packet
    318 		.....................................................................*/
    319 		default:
    320 			break;
    321 
    322 	}	/* end of switch */
    323 
    324 	return(true);
    325 }
    326 
    327 
    328 /***************************************************************************
    329  * SequencedConnClass::Get_Packet -- gets a packet from the receive queue	*
    330  *                                                                         *
    331  * INPUT:                                                                  *
    332  *		buf		location to store buffer												*
    333  *		buflen	filled in with length of 'buf'										*
    334  *                                                                         *
    335  * OUTPUT:                                                                 *
    336  *		1 = packet was read, 0 = wasn't													*
    337  *                                                                         *
    338  * WARNINGS:                                                               *
    339  *		none.																						*
    340  *                                                                         *
    341  * HISTORY:                                                                *
    342  *   12/20/1994 BR : Created.                                              *
    343  *=========================================================================*/
    344 int SequencedConnClass::Get_Packet (void * buf, int *buflen)
    345 {
    346 	ReceiveQueueType *rec_entry;					// ptr to receive entry header
    347 	int packetlen;										// size of received packet
    348 
    349 	/*
    350 	------------------ Get ptr to the next available entry -------------------
    351 	*/
    352 	rec_entry = Queue->Next_Receive();
    353 
    354 	/*
    355 	------------------------ Read it if it's un-read -------------------------
    356 	*/
    357 	if (rec_entry!=NULL && rec_entry->IsRead==0) {
    358 		/*
    359 		........................... Mark as read ..............................
    360 		*/
    361 		rec_entry->IsRead = 1;
    362 
    363 		/*
    364 		.......................... Copy data packet ...........................
    365 		*/
    366 		packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
    367 		if (packetlen > 0) {
    368 			memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType), packetlen);
    369 		}
    370 		(*buflen) = packetlen;
    371 		return(true);
    372 	}
    373 
    374 	return(false);
    375 }
    376 
    377 
    378 /***************************************************************************
    379  * SequencedConnClass::Service_Send_Queue -- services the send queue			*
    380  *                                                                         *
    381  * INPUT:                                                                  *
    382  *		none.																						*
    383  *                                                                         *
    384  * OUTPUT:                                                                 *
    385  *		1 = OK, 0 = error																		*
    386  *                                                                         *
    387  * WARNINGS:                                                               *
    388  *		none.																						*
    389  *                                                                         *
    390  * HISTORY:                                                                *
    391  *   12/20/1994 BR : Created.                                              *
    392  *=========================================================================*/
    393 int SequencedConnClass::Service_Send_Queue (void)
    394 {
    395 	SendQueueType *send_entry;						// ptr to send queue entry
    396 	CommHeaderType *packet_hdr;					// packet header
    397 	unsigned long curtime;							// current time
    398 
    399 	/*------------------------------------------------------------------------
    400 	- If the next packet is ACK'd remove it from the queue
    401 	- If the next packet isn't ACK'd, [re-]send it
    402 	------------------------------------------------------------------------*/
    403 	/*
    404 	......................... Get ptr to data to send ........................
    405 	*/
    406 	send_entry = Queue->Next_Send();
    407 	if (send_entry==NULL)
    408 		return(true);
    409 
    410 	/*
    411 	------------------ If ACK has been received, unqueue it ------------------
    412 	*/
    413 	if (send_entry->IsACK) {
    414 
    415 		/*
    416 		.................. Update this queue's response time ..................
    417 		*/
    418 		packet_hdr = (CommHeaderType *)send_entry->Buffer;
    419 		if (packet_hdr->Code == PACKET_DATA_ACK) {
    420 			Queue->Add_Delay(Time() - send_entry->FirstTime);
    421 		}
    422 
    423 		/*
    424 		......................... unqueue the packet ..........................
    425 		*/
    426 #ifdef DEBUG_SEQ
    427 printf(">>>Unqueueing Receive packet #%d<<<\n",packet_hdr->PacketID);
    428 #endif
    429 		Queue->UnQueue_Send(NULL,NULL);
    430 	} else {
    431 
    432 		/*
    433 		----------------- ACK not received yet, [re-]send packet -----------------
    434 		*/
    435 		/*.....................................................................
    436 		Only send the message if time has elapsed.  (The message's Time
    437 		fields are init'd to 0 when a message is queue'd or unqueue'd, so the
    438 		first time through, the delta time will appear large.)
    439 		.....................................................................*/
    440 		curtime = Time();
    441 		if (curtime - send_entry->LastTime > RetryDelta) {
    442 			/*
    443 			......................... Send the message .........................
    444 			*/
    445 			Send (send_entry->Buffer, send_entry->BufLen);
    446 			/*
    447 			....................... Fill in Time fields ........................
    448 			*/
    449 			send_entry->LastTime = curtime;
    450 			if (send_entry->SendCount==0) {
    451 				send_entry->FirstTime = curtime;
    452 				/*...............................................................
    453 				If this is the 1st time we're sending this packet, and it doesn't
    454 				require an ACK, mark it as ACK'd; then, the next time through,
    455 				it will just be removed from the queue.
    456 				...............................................................*/
    457 				packet_hdr = (CommHeaderType *)send_entry->Buffer;
    458 				if (packet_hdr->Code == PACKET_DATA_NOACK)
    459 					send_entry->IsACK = 1;
    460 			}
    461 
    462 #ifdef DEBUG_SEQ
    463 packet_hdr = (CommHeaderType *)send_entry->Buffer;
    464 if (packet_hdr->Code == PACKET_DATA_NOACK) {
    465 	printf("Sending PACKET_DATA_NOACK (%d)\n",packet_hdr->PacketID);
    466 } else {
    467 	printf("Sending PACKET_DATA_ACK (%d)\n",packet_hdr->PacketID);
    468 }
    469 #endif
    470 			/*
    471 			......................... Update SendCount .........................
    472 			*/
    473 			send_entry->SendCount++;
    474 			/*..................................................................
    475 			Perform error detection, based on either MaxRetries or Timeout
    476 			..................................................................*/
    477 			if (MaxRetries != -1 && send_entry->SendCount > MaxRetries)
    478 				return(false);
    479 			if (Timeout != -1 && send_entry->LastTime - 
    480 				send_entry->FirstTime > Timeout)
    481 				return(false);
    482 
    483 		}
    484 	}
    485 
    486 	return(true);
    487 }
    488 
    489 
    490 /***************************************************************************
    491  * SequencedConnClass::Service_Receive_Queue -- services the recieve queue	*
    492  *                                                                         *
    493  * INPUT:                                                                  *
    494  *		none.																						*
    495  *                                                                         *
    496  * OUTPUT:                                                                 *
    497  *		1 = OK, 0 = error																		*
    498  *                                                                         *
    499  * WARNINGS:                                                               *
    500  *		none.																						*
    501  *                                                                         *
    502  * HISTORY:                                                                *
    503  *   12/20/1994 BR : Created.                                              *
    504  *=========================================================================*/
    505 int SequencedConnClass::Service_Receive_Queue (void)
    506 {
    507 	CommHeaderType ackpacket;						// ACK packet to send
    508 	ReceiveQueueType *rec_entry;					// ptr to receive entry header
    509 	CommHeaderType *packet_hdr;					// packet header
    510 
    511 	/*------------------------------------------------------------------------
    512 	Get a pointer to the next received entry
    513 	------------------------------------------------------------------------*/
    514 	rec_entry = Queue->Next_Receive();
    515 	if (rec_entry==NULL)
    516 		return(true);
    517 
    518 	/*------------------------------------------------------------------------
    519 	If this packet doesn't require an ACK, mark it as ACK'd.
    520 	------------------------------------------------------------------------*/
    521 	packet_hdr = (CommHeaderType *)(rec_entry->Buffer);
    522 	if (packet_hdr->Code==PACKET_DATA_NOACK)
    523 		rec_entry->IsACK = 1;
    524 
    525 	/*------------------------------------------------------------------------
    526 	If this packet hasn't been ACK'd, send an ACK:
    527 	- Fill in the MagicNum & the Code
    528 	- Set the PacketID to the same ID that the sending system used, so the
    529 	  sending system knows which packet the ACK is for
    530 	------------------------------------------------------------------------*/
    531 	if (rec_entry->IsACK==0) {
    532 #ifdef DEBUG_SEQ
    533 printf("Sending ACK (%d)\n",packet_hdr->PacketID);
    534 #endif
    535 		ackpacket.MagicNumber = MagicNum;
    536 		ackpacket.Code = PACKET_ACK;
    537 		ackpacket.PacketID = packet_hdr->PacketID;
    538 
    539 		Send((char *)&ackpacket, sizeof(CommHeaderType));
    540 
    541 		rec_entry->IsACK = 1;
    542 	}
    543 			
    544 	/*------------------------------------------------------------------------
    545 	If this packet has been read by the application, and has been ACK'd, and
    546 	there is another packet in the queue behind this one, it means the other
    547 	system got the ACK we sent for this packet; remove this packet from the
    548 	queue.
    549 	------------------------------------------------------------------------*/
    550 	if (rec_entry!=NULL && rec_entry->IsRead && rec_entry->IsACK &&
    551 		Queue->Num_Receive() > 1) {
    552 #ifdef DEBUG_SEQ
    553 printf(">>>Unqueueing Send packet #%d<<<\n",packet_hdr->PacketID);
    554 #endif
    555 		Queue->UnQueue_Receive(NULL,NULL);
    556 	}
    557 
    558 	return(true);
    559 }
    560 
    561 #endif