CnC_Remastered_Collection

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

NOSEQCON.CPP (29631B)


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