CnC_Remastered_Collection

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

SEQCONN.CPP (24580B)


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