CnC_Remastered_Collection

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

NOSEQCON.CPP (29602B)


      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\noseqcon.cpv   1.9   16 Oct 1995 16:49:38   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  *   NonSequencedConnClass::NonSequencedConnClass -- class constructor     *
     34  *   NonSequencedConnClass::~NonSequencedConnClass -- class destructor     *
     35  *   NonSequencedConnClass::Init -- Initializes connection queue to empty	*
     36  *   NonSequencedConnClass::Send_Packet -- adds a packet to the send queue	*
     37  *   NonSequencedConnClass::Receive_Packet -- adds packet to receive queue	*
     38  *   NonSequencedConnClass::Get_Packet -- gets a packet from receive queue	*
     39  *   NonSequencedConnClass::Service_Send_Queue -- services the send queue	*
     40  *   NonSequencedConnClass::Service_Receive_Queue -- services recieve queue*
     41  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     42 
     43 #include "function.h"
     44 
     45 
     46 /***************************************************************************
     47  * NonSequencedConnClass::NonSequencedConnClass -- class constructor       *
     48  *                                                                         *
     49  * INPUT:                                                                  *
     50  *		numsend			desired # of entries for the send queue					*
     51  *		numreceive		desired # of entries for the recieve queue				*
     52  *		maxlen			max length of an application packet							*
     53  *		magicnum			the packet "magic number" for this connection			*
     54  *		retry_delta		the time to wait between sends								*
     55  *		max_retries		the max # of retries allowed for a packet					*
     56  *							(-1 means retry forever, based on this parameter)		*
     57  *		timeout			the max amount of time before we give up on a packet	*
     58  *							(-1 means retry forever, based on this parameter)		*
     59  *                                                                         *
     60  * OUTPUT:                                                                 *
     61  *		none.																						*
     62  *                                                                         *
     63  * WARNINGS:                                                               *
     64  *		none.																						*
     65  *                                                                         *
     66  * HISTORY:                                                                *
     67  *   12/20/1994 BR : Created.                                              *
     68  *=========================================================================*/
     69 NonSequencedConnClass::NonSequencedConnClass (int numsend, int numreceive,
     70 	int maxlen, unsigned short magicnum, unsigned long retry_delta,
     71 	unsigned long max_retries, unsigned long timeout) :
     72 	ConnectionClass (maxlen, magicnum, retry_delta, max_retries, timeout)
     73 {
     74 	/*------------------------------------------------------------------------
     75 	Allocate the packet Queue.  This will store incoming packets (which will
     76 	be placed there by the Connection Manager), and outgoing packets (which
     77 	are placed there by this class when it "sends" a packet).
     78 	------------------------------------------------------------------------*/
     79 	Queue = new CommBufferClass (numsend, numreceive, MaxPacketLen);
     80 }
     81 
     82 
     83 /***************************************************************************
     84  * NonSequencedConnClass::~NonSequencedConnClass -- class destructor       *
     85  *                                                                         *
     86  * INPUT:                                                                  *
     87  *		none.																						*
     88  *                                                                         *
     89  * OUTPUT:                                                                 *
     90  *		none.																						*
     91  *                                                                         *
     92  * WARNINGS:                                                               *
     93  *		none.																						*
     94  *                                                                         *
     95  * HISTORY:                                                                *
     96  *   12/20/1994 BR : Created.                                              *
     97  *=========================================================================*/
     98 NonSequencedConnClass::~NonSequencedConnClass ()
     99 {
    100 	delete Queue;
    101 }
    102 
    103 
    104 /***************************************************************************
    105  * NonSequencedConnClass::Init -- Initializes connection queue to empty		*
    106  *                                                                         *
    107  * INPUT:                                                                  *
    108  *		none.																						*
    109  *                                                                         *
    110  * OUTPUT:                                                                 *
    111  *		none.																						*
    112  *                                                                         *
    113  * WARNINGS:                                                               *
    114  *		none.																						*
    115  *                                                                         *
    116  * HISTORY:                                                                *
    117  *   12/20/1994 BR : Created.                                              *
    118  *=========================================================================*/
    119 void NonSequencedConnClass::Init (void)
    120 {
    121 	NumRecNoAck = 0;
    122 	NumRecAck = 0;
    123 	NumSendNoAck = 0;
    124 	NumSendAck = 0;
    125 
    126 	LastSeqID = 0xffffffff;
    127 	LastReadID = 0xffffffff;
    128 
    129 	Queue->Init();
    130 }
    131 
    132 
    133 /***************************************************************************
    134  * NonSequencedConnClass::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 NonSequencedConnClass::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 // Smart_Printf( "Packet ack Queued ID %d \n", ((CommHeaderType *)PacketBuf)->PacketID );
    185 			NumSendAck++;
    186 		} else {
    187 // Smart_Printf( "Packet noack Queued ID %d \n", ((CommHeaderType *)PacketBuf)->PacketID );
    188 			NumSendNoAck++;
    189 		}
    190 		return(true);
    191 	} else {
    192 // Smart_Printf( "Packet not Queued ID %d \n", ((CommHeaderType *)PacketBuf)->PacketID );
    193 		return(false);
    194 	}
    195 }
    196 
    197 
    198 /***************************************************************************
    199  * NonSequencedConnClass::Receive_Packet -- adds packet to the receive queue	*
    200  *                                                                         *
    201  * INPUT:                                                                  *
    202  *		buf		buffer to process (already includes CommHeaderType)			*
    203  *		buflen	length of buffer to process											*
    204  *                                                                         *
    205  * OUTPUT:                                                                 *
    206  *		1 = packet was processed OK, 0 = error											*
    207  *                                                                         *
    208  * WARNINGS:                                                               *
    209  *		none.																						*
    210  *                                                                         *
    211  * HISTORY:                                                                *
    212  *   12/20/1994 BR : Created.                                              *
    213  *=========================================================================*/
    214 int NonSequencedConnClass::Receive_Packet (void * buf, int buflen)
    215 {
    216 	CommHeaderType *packet;								// ptr to packet header
    217 	SendQueueType *send_entry;							// ptr to send entry header
    218 	ReceiveQueueType *rec_entry;						// ptr to recv entry header
    219 	CommHeaderType *entry_data;						// ptr to queue entry data
    220 	CommHeaderType ackpacket;							// ACK packet to send
    221 	int i;
    222 	int save_packet = 1;									// 0 = this is a resend
    223 	int found;
    224 
    225 	/*
    226 	--------------------------- Check the magic # ----------------------------
    227 	*/
    228 	packet = (CommHeaderType *)buf;
    229 	if (packet->MagicNumber != MagicNum) {
    230 // Smart_Printf( "Bad Magic Number\n" );
    231 		return(false);
    232 	}
    233 
    234 	/*------------------------------------------------------------------------
    235 	Handle an incoming ACK
    236 	------------------------------------------------------------------------*/
    237 	if (packet->Code == PACKET_ACK) {
    238 
    239 		for (i = 0; i < Queue->Num_Send(); i++) {
    240 			/*
    241 			....................... Get queue entry ptr ........................
    242 			*/
    243 			send_entry = Queue->Get_Send(i);
    244 			/*
    245 			............... If ptr is valid, get ptr to its data ...............
    246 			*/
    247 			if (send_entry != NULL) {
    248 				entry_data = (CommHeaderType *)send_entry->Buffer;
    249 				/*
    250 				.............. If ACK is for this entry, mark it ................
    251 				*/
    252 				if (packet->PacketID==entry_data->PacketID &&
    253 					entry_data->Code == PACKET_DATA_ACK) {
    254 // Smart_Printf( "Received ACK for %d \n", packet->PacketID );
    255 					send_entry->IsACK = 1;
    256 					break;
    257 				}
    258 			}
    259 		}
    260 
    261 //{
    262 //		if (i == Queue->Num_Send() ) {
    263 // Smart_Printf( "Received bad ACK for %d \n", packet->PacketID );
    264 //		}
    265 //}
    266 
    267 		return(true);
    268 	}
    269 
    270 	/*------------------------------------------------------------------------
    271 	Handle an incoming PACKET_DATA_NOACK packet
    272 	------------------------------------------------------------------------*/
    273 	else if (packet->Code == PACKET_DATA_NOACK) {
    274 		/*---------------------------------------------------------------------
    275 		If there's only one slot left, don't tie up the queue with this packet
    276 		---------------------------------------------------------------------*/
    277 		if (Queue->Max_Receive() - Queue->Num_Receive() <= 1) {
    278 // Smart_Printf( "Only one slot left don't tie up with DATA NOACK packet %d \n", packet->PacketID );
    279 				return(false);
    280 		}
    281 
    282 		/*---------------------------------------------------------------------
    283 		Error if we can't queue the packet
    284 		---------------------------------------------------------------------*/
    285 		if (!Queue->Queue_Receive (buf, buflen)) {
    286 // Smart_Printf( "Can't Queue the packet %d \n", packet->PacketID );
    287 			return(false);
    288 		}
    289 
    290 // Smart_Printf( "Queued DATA NOACK for %d \n", packet->PacketID );
    291 		NumRecNoAck++;
    292 
    293 		return(true);
    294 	}
    295 
    296 	/*------------------------------------------------------------------------
    297 	Handle an incoming PACKET_DATA_ACK packet
    298 	------------------------------------------------------------------------*/
    299 	else if (packet->Code == PACKET_DATA_ACK) {
    300 // Smart_Printf( "Looking at ID %d, LastSeqID=%d \n", packet->PacketID, LastSeqID );
    301 		/*....................................................................
    302 		If this is a packet requires an ACK, and it's ID is older than our
    303 		"oldest" ID, we know it's a resend; send an ACK, but don't queue it
    304 		....................................................................*/
    305 		if (packet->PacketID <= LastSeqID && LastSeqID != 0xffffffff) {
    306 // Smart_Printf( "Older than oldest\n" );
    307 			save_packet = 0;
    308 		}
    309 		/*....................................................................
    310 		Otherwise, scan the queue for this entry; if it's found, it's a
    311 		resend, so don't save it.
    312 		....................................................................*/
    313 		else {
    314 			save_packet = 1;
    315 			for (i = 0; i < Queue->Num_Receive(); i++) {
    316 				rec_entry = Queue->Get_Receive(i);
    317 				if (rec_entry) {
    318 					entry_data = (CommHeaderType *)rec_entry->Buffer;
    319 					/*...........................................................
    320 					Packet is found; it's a resend
    321 					...........................................................*/
    322 					if (entry_data->Code == PACKET_DATA_ACK &&
    323 						entry_data->PacketID == packet->PacketID) {
    324 // Smart_Printf( "It's a resend\n" );
    325 						save_packet = 0;
    326 						break;
    327 					}
    328 				}
    329 			}
    330 		}	/* end of scan for resend */
    331 
    332 		/*---------------------------------------------------------------------
    333 		Queue the packet & update our LastSeqID value.
    334 		---------------------------------------------------------------------*/
    335 		if (save_packet) {
    336 			/*------------------------------------------------------------------
    337 			If there's only one slot left, make sure we only put a packet in it if
    338 			this packet will let us increment our LastSeqID; otherwise, we'll get
    339 			stuck, forever unable to increment LastSeqID.
    340 			------------------------------------------------------------------*/
    341 			if (Queue->Max_Receive() - Queue->Num_Receive() <= 1) {
    342 				if (packet->PacketID != (LastSeqID + 1) ) {
    343 // Smart_Printf( "One slot left not what we looking for max=%d,num=%d \n",
    344 //	Queue->Max_Receive(), Queue->Num_Receive() );
    345 					return(0);
    346 				}
    347 			}
    348 
    349 			/*------------------------------------------------------------------
    350 			If we can't queue the packet, return; don't send an ACK.
    351 			------------------------------------------------------------------*/
    352 			if (!Queue->Queue_Receive (buf, buflen)) {
    353 // Smart_Printf( "unable to queue packet\n" );
    354 				return(0);
    355 			}
    356 
    357 			NumRecAck++;
    358 
    359 			/*------------------------------------------------------------------
    360 			Update our LastSeqID value if we can.  Anything less than LastSeqID
    361 			we'll know is a resend.
    362 			------------------------------------------------------------------*/
    363 			if (packet->PacketID == (LastSeqID + 1)) {
    364 				LastSeqID = packet->PacketID;
    365 				/*............................................................
    366 				Now that we have a new 'LastSeqID', search our Queue to see if
    367 				the next ID is there; if so, keep checking for the next one;
    368 				break only when the next one isn't found.  This forces
    369 				LastSeqID to be the largest possible value.
    370 				............................................................*/
    371 				do {
    372 					found = 0;
    373 					for (i = 0; i < Queue->Num_Receive(); i++) {
    374 
    375 						rec_entry = Queue->Get_Receive(i);
    376 
    377 						if (rec_entry) {
    378 							entry_data = (CommHeaderType *)rec_entry->Buffer;
    379 
    380 							/*......................................................
    381 							Entry is found
    382 							......................................................*/
    383 							if (entry_data->Code == PACKET_DATA_ACK &&
    384 								entry_data->PacketID == (LastSeqID + 1)) {
    385 
    386 								LastSeqID = entry_data->PacketID;
    387 								found = 1;
    388 								break;
    389 							}
    390 						}
    391 					}
    392 				} while (found);
    393 			}
    394 		}	/* end of save packet */
    395 
    396 		/*---------------------------------------------------------------------
    397 		Send an ACK, regardless of whether this was a resend or not.
    398 		---------------------------------------------------------------------*/
    399 		ackpacket.MagicNumber = Magic_Num();
    400 		ackpacket.Code = PACKET_ACK;
    401 		ackpacket.PacketID = packet->PacketID;
    402 // Smart_Printf( "Sending ACK for %d \n", packet->PacketID );
    403 		Send ((char *)&ackpacket, sizeof(CommHeaderType));
    404 
    405 		return(true);
    406 
    407 	} else {
    408 // Smart_Printf( "invalid packet type %d \n", packet->Code );
    409 	}
    410 
    411 	return(false);
    412 }
    413 
    414 
    415 /***************************************************************************
    416  * NonSequencedConnClass::Get_Packet -- gets a packet from receive queue	*
    417  *                                                                         *
    418  * INPUT:                                                                  *
    419  *		buf		location to store buffer												*
    420  *		buflen	filled in with length of 'buf'										*
    421  *                                                                         *
    422  * OUTPUT:                                                                 *
    423  *		1 = packet was read, 0 = wasn't													*
    424  *                                                                         *
    425  * WARNINGS:                                                               *
    426  *		none.																						*
    427  *                                                                         *
    428  * HISTORY:                                                                *
    429  *   12/20/1994 BR : Created.                                              *
    430  *=========================================================================*/
    431 int NonSequencedConnClass::Get_Packet (void * buf, int *buflen)
    432 {
    433 	ReceiveQueueType *rec_entry;					// ptr to receive entry header
    434 	int packetlen;										// size of received packet
    435 	CommHeaderType *entry_data;
    436 	int i;
    437 
    438 	/*------------------------------------------------------------------------
    439 	Ensure that we read the packets in order.  LastReadID is the ID of the
    440 	last PACKET_DATA_ACK packet we read.
    441 	------------------------------------------------------------------------*/
    442 	for (i = 0; i < Queue->Num_Receive(); i++) {
    443 
    444 		rec_entry = Queue->Get_Receive(i);
    445 
    446 		/*.....................................................................
    447 		Only read this entry if it hasn't been yet
    448 		.....................................................................*/
    449 		if (rec_entry && rec_entry->IsRead==0) {
    450 
    451 			entry_data = (CommHeaderType *)rec_entry->Buffer;
    452 
    453 			/*..................................................................
    454 			If this is a DATA_ACK packet, its ID must be one greater than
    455 			the last one we read.
    456 			..................................................................*/
    457 			if ( (entry_data->Code == PACKET_DATA_ACK) &&
    458 				(entry_data->PacketID == (LastReadID + 1))) {
    459 
    460 				LastReadID = entry_data->PacketID;
    461 				rec_entry->IsRead = 1;
    462 
    463 				packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
    464 				if (packetlen > 0) {
    465 					memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType), packetlen);
    466 				}
    467 				(*buflen) = packetlen;
    468 				return(true);
    469 			}
    470 			/*..................................................................
    471 			If this is a DATA_NOACK packet, who cares what the ID is?
    472 			..................................................................*/
    473 			else if (entry_data->Code == PACKET_DATA_NOACK) {
    474 
    475 				rec_entry->IsRead = 1;
    476 
    477 				packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
    478 				if (packetlen > 0) {
    479 					memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType), packetlen);
    480 				}
    481 				(*buflen) = packetlen;
    482 				return(true);
    483 			}
    484 		}
    485 	}
    486 
    487 	return(false);
    488 }
    489 
    490 
    491 /***************************************************************************
    492  * NonSequencedConnClass::Service_Send_Queue -- services the send queue		*
    493  *                                                                         *
    494  * INPUT:                                                                  *
    495  *		none.																						*
    496  *                                                                         *
    497  * OUTPUT:                                                                 *
    498  *		1 = OK, 0 = error																		*
    499  *                                                                         *
    500  * WARNINGS:                                                               *
    501  *		none.																						*
    502  *                                                                         *
    503  * HISTORY:                                                                *
    504  *   12/20/1994 BR : Created.                                              *
    505  *=========================================================================*/
    506 int NonSequencedConnClass::Service_Send_Queue (void)
    507 {
    508 	int i;
    509 	int num_entries;
    510 	SendQueueType *send_entry;						// ptr to send queue entry
    511 	CommHeaderType *packet_hdr;					// packet header
    512 	unsigned long curtime;							// current time
    513 	int bad_conn = 0;
    514 
    515 	/*------------------------------------------------------------------------
    516 	Remove any ACK'd packets from the queue
    517 	------------------------------------------------------------------------*/
    518 	for (i = 0; i < Queue->Num_Send(); i++) {
    519 		/*
    520 		------------------------- Get this queue entry ------------------------
    521 		*/
    522 		send_entry = Queue->Get_Send(i);
    523 		/*
    524 		---------------- If ACK has been received, unqueue it -----------------
    525 		*/
    526 		if (send_entry->IsACK) {
    527 			/*
    528 			................ Update this queue's response time .................
    529 			*/
    530 			packet_hdr = (CommHeaderType *)send_entry->Buffer;
    531 			if (packet_hdr->Code == PACKET_DATA_ACK) {
    532 				Queue->Add_Delay(Time() - send_entry->FirstTime);
    533 			}
    534 			/*
    535 			....................... unqueue the packet .........................
    536 			*/
    537 			Queue->UnQueue_Send(NULL,NULL,i);
    538 			i--;
    539 		}
    540 	}
    541 
    542 	/*------------------------------------------------------------------------
    543 	Loop through all entries in the Send queue.  [Re]Send any entries that
    544 	need it.
    545 	------------------------------------------------------------------------*/
    546 	num_entries = Queue->Num_Send();
    547 
    548 	for (i = 0; i < num_entries; i++) {
    549 		send_entry = Queue->Get_Send(i);
    550 
    551 		if (send_entry->IsACK) {
    552 			continue;
    553 		}
    554 
    555 		/*.....................................................................
    556 		Only send the message if time has elapsed.  (The message's Time
    557 		fields are init'd to 0 when a message is queue'd or unqueue'd, so the
    558 		first time through, the delta time will appear large.)
    559 		.....................................................................*/
    560 		curtime = Time();
    561 		if (curtime - send_entry->LastTime > RetryDelta) {
    562 			/*
    563 			......................... Send the message .........................
    564 			*/
    565 #if(0)
    566 {
    567 			packet_hdr = (CommHeaderType *)send_entry->Buffer;
    568 			if (send_entry->SendCount) {
    569 				if (packet_hdr->Code == PACKET_DATA_NOACK) {
    570 // Smart_Printf( "Resending DATA NOACK for %d \n", packet_hdr->PacketID );
    571 				} else {
    572 					if (packet_hdr->Code == PACKET_DATA_ACK) {
    573 // Smart_Printf( "Resending DATA ACK for %d \n", packet_hdr->PacketID );
    574 					}
    575 				}
    576 			} else {
    577 				if (packet_hdr->Code == PACKET_DATA_NOACK) {
    578 // Smart_Printf( "Sending DATA NOACK for %d \n", packet_hdr->PacketID );
    579 				} else {
    580 					if (packet_hdr->Code == PACKET_DATA_ACK) {
    581 // Smart_Printf( "Sending DATA ACK for %d \n", packet_hdr->PacketID );
    582 					}
    583 				}
    584 			}
    585 }
    586 #endif
    587 			Send (send_entry->Buffer, send_entry->BufLen);
    588 
    589 			/*
    590 			....................... Fill in Time fields ........................
    591 			*/
    592 			send_entry->LastTime = curtime;
    593 			if (send_entry->SendCount==0) {
    594 				send_entry->FirstTime = curtime;
    595 				/*...............................................................
    596 				If this is the 1st time we're sending this packet, and it doesn't
    597 				require an ACK, mark it as ACK'd; then, the next time through,
    598 				it will just be removed from the queue.
    599 				...............................................................*/
    600 				packet_hdr = (CommHeaderType *)send_entry->Buffer;
    601 				if (packet_hdr->Code == PACKET_DATA_NOACK) {
    602 					send_entry->IsACK = 1;
    603 				}
    604 			}
    605 			/*
    606 			......................... Update SendCount .........................
    607 			*/
    608 			send_entry->SendCount++;
    609 			/*..................................................................
    610 			Perform error detection, based on either MaxRetries or Timeout
    611 			..................................................................*/
    612 			if (MaxRetries != -1 && send_entry->SendCount > MaxRetries) {
    613 // Smart_Printf( "Max Retries!!! %d !!! \n", MaxRetries );
    614 				bad_conn = 1;
    615 			}
    616 
    617 			if (Timeout != -1 &&
    618 				(send_entry->LastTime - send_entry->FirstTime) > Timeout) {
    619 // Smart_Printf( "Timed out!!! Time %d, Timeout %d, buflen %d !!! \n",
    620 //	(send_entry->LastTime - send_entry->FirstTime), Timeout,
    621 //	send_entry->BufLen );
    622 				bad_conn = 1;
    623 			}
    624 		}
    625 	}
    626 
    627 	/*------------------------------------------------------------------------
    628 	If the connection is going bad, return an error
    629 	------------------------------------------------------------------------*/
    630 	if (bad_conn) {
    631 // Smart_Printf( "Connection going bad!!! \n" );
    632 		return(false);
    633 	} else {
    634 		return(true);
    635 	}
    636 }
    637 
    638 
    639 /***************************************************************************
    640  * NonSequencedConnClass::Service_Receive_Queue -- services recieve queue	*
    641  *                                                                         *
    642  * INPUT:                                                                  *
    643  *		none.																						*
    644  *                                                                         *
    645  * OUTPUT:                                                                 *
    646  *		1 = OK, 0 = error																		*
    647  *                                                                         *
    648  * WARNINGS:                                                               *
    649  *		none.																						*
    650  *                                                                         *
    651  * HISTORY:                                                                *
    652  *   12/20/1994 BR : Created.                                              *
    653  *=========================================================================*/
    654 int NonSequencedConnClass::Service_Receive_Queue (void)
    655 {
    656 	ReceiveQueueType *rec_entry;					// ptr to receive entry header
    657 	CommHeaderType *packet_hdr;					// packet header
    658 	int i;
    659 
    660 	/*------------------------------------------------------------------------
    661 	Remove all dead packets.
    662 	PACKET_DATA_NOACK: if it's been read, throw it away.
    663 	PACKET_DATA_ACK: if it's been read, and its ID is older than LastSeqID,
    664 	throw it away.
    665 	------------------------------------------------------------------------*/
    666 	for (i = 0; i < Queue->Num_Receive(); i++) {
    667 		rec_entry = Queue->Get_Receive(i);
    668 
    669 		if (rec_entry->IsRead) {
    670 			packet_hdr = (CommHeaderType *)(rec_entry->Buffer);
    671 
    672 			if (packet_hdr->Code == PACKET_DATA_NOACK) {
    673 				Queue->UnQueue_Receive(NULL,NULL,i);
    674 				i--;
    675 			} else {
    676 				if (packet_hdr->PacketID < LastSeqID) {
    677 					Queue->UnQueue_Receive(NULL,NULL,i);
    678 					i--;
    679 				}
    680 			}
    681 		}
    682 	}
    683 
    684 	return(true);
    685 }
    686 
    687