CnC_Remastered_Collection

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

CONNECT.CPP (36022B)


      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: /CounterStrike/CONNECT.CPP 1     3/03/97 10:24a 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 : CONNECT.CPP                              *
     24  *                                                                         *
     25  *                   Programmer : Bill Randolph                            *
     26  *                                                                         *
     27  *                   Start Date : December 20, 1994                        *
     28  *                                                                         *
     29  *                  Last Update : May 31, 1995 [BRR]								*
     30  *-------------------------------------------------------------------------*
     31  * Functions:    			                                                   *
     32  *   ConnectionClass::ConnectionClass -- class constructor                 *
     33  *   ConnectionClass::~ConnectionClass -- class destructor                 *
     34  *   ConnectionClass::Init -- Initializes connection queue to empty			*
     35  *   ConnectionClass::Send_Packet -- adds a packet to the send queue			*
     36  *   ConnectionClass::Receive_Packet -- adds packet to receive queue			*
     37  *   ConnectionClass::Get_Packet -- gets a packet from receive queue			*
     38  *   ConnectionClass::Service -- main polling routine; services packets		*
     39  *   ConnectionClass::Service_Send_Queue -- services the send queue			*
     40  *   ConnectionClass::Service_Receive_Queue -- services receive queue		*
     41  *   ConnectionClass::Time -- gets current time										*
     42  *   ConnectionClass::Command_Name -- returns name for a packet command		*
     43  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     44 
     45 
     46 
     47 #include	"function.h"
     48 #include <stdio.h>
     49 //#include <mem.h>
     50 #include <sys\timeb.h>
     51 #include "connect.h"
     52 
     53 //#include "WolDebug.h"
     54 
     55 /*
     56 ********************************* Globals ***********************************
     57 */
     58 char *ConnectionClass::Commands[PACKET_COUNT] = {
     59 	"ADATA",
     60 	"NDATA",
     61 	"ACK"
     62 };
     63 
     64 
     65 /***************************************************************************
     66  * ConnectionClass::ConnectionClass -- class constructor                   *
     67  *                                                                         *
     68  * INPUT:                                                                  *
     69  *		numsend			desired # of entries for the send queue					*
     70  *		numreceive		desired # of entries for the receive queue				*
     71  *		maxlen			max length of an application packet							*
     72  *		magicnum			the packet "magic number" for this connection			*
     73  *		retry_delta		the time to wait between sends								*
     74  *		max_retries		the max # of retries allowed for a packet					*
     75  *							(-1 means retry forever, based on this parameter)		*
     76  *		timeout			the max amount of time before we give up on a packet	*
     77  *							(-1 means retry forever, based on this parameter)		*
     78  *		extralen			max size of app-specific extra bytes (optional)			*
     79  *                                                                         *
     80  * OUTPUT:                                                                 *
     81  *		none.																						*
     82  *                                                                         *
     83  * WARNINGS:                                                               *
     84  *		none.																						*
     85  *                                                                         *
     86  * HISTORY:                                                                *
     87  *   12/20/1994 BR : Created.                                              *
     88  *=========================================================================*/
     89 ConnectionClass::ConnectionClass (int numsend, int numreceive,
     90 	int maxlen, unsigned short magicnum, unsigned long retry_delta,
     91 	unsigned long max_retries, unsigned long timeout, int extralen)
     92 {
     93 	/*------------------------------------------------------------------------
     94 	Compute our maximum packet length
     95 	------------------------------------------------------------------------*/
     96 	MaxPacketLen = maxlen + sizeof(CommHeaderType);
     97 
     98 	/*------------------------------------------------------------------------
     99 	Assign the magic number
    100 	------------------------------------------------------------------------*/
    101 	MagicNum = magicnum;
    102 
    103 	/*------------------------------------------------------------------------
    104 	Initialize the retry time.  This is the time that t2 - t1 must be greater
    105 	than before a retry will occur.
    106 	------------------------------------------------------------------------*/
    107 	RetryDelta = retry_delta;
    108 
    109 	/*------------------------------------------------------------------------
    110 	Set the maximum allowable retries.
    111 	------------------------------------------------------------------------*/
    112 	MaxRetries = max_retries;
    113 
    114 	/*------------------------------------------------------------------------
    115 	Set the timeout for this connection.
    116 	------------------------------------------------------------------------*/
    117 	Timeout = timeout;
    118 
    119 	/*------------------------------------------------------------------------
    120 	Allocate the packet staging buffer.  This will be used to
    121 	------------------------------------------------------------------------*/
    122 	PacketBuf = new char[ MaxPacketLen ];
    123 
    124 	/*------------------------------------------------------------------------
    125 	Allocate the packet Queue.  This will store incoming packets (placed there
    126 	by Receive_Packet), and outgoing packets (placed there by Send_Packet).
    127 	It can optionally store "extra" bytes, which are stored along with each
    128 	packet, but aren't transmitted as part of the packet.  If 'extralen'
    129 	is 0, the CommBufferClass ignores this parameter.
    130 	------------------------------------------------------------------------*/
    131 	Queue = new CommBufferClass (numsend, numreceive, MaxPacketLen, extralen);
    132 
    133 }	/* end of ConnectionClass */
    134 
    135 
    136 /***************************************************************************
    137  * ConnectionClass::~ConnectionClass -- class destructor                   *
    138  *                                                                         *
    139  * INPUT:                                                                  *
    140  *		none.																						*
    141  *                                                                         *
    142  * OUTPUT:                                                                 *
    143  *		none.																						*
    144  *                                                                         *
    145  * WARNINGS:                                                               *
    146  *		none.																						*
    147  *                                                                         *
    148  * HISTORY:                                                                *
    149  *   12/20/1994 BR : Created.                                              *
    150  *=========================================================================*/
    151 ConnectionClass::~ConnectionClass ()
    152 {
    153 	/*------------------------------------------------------------------------
    154 	Free memory.
    155 	------------------------------------------------------------------------*/
    156 	delete [] PacketBuf;
    157 	delete Queue;
    158 
    159 }	/* end of ~ConnectionClass */
    160 
    161 
    162 /***************************************************************************
    163  * ConnectionClass::Init -- Initializes connection queue to empty				*
    164  *                                                                         *
    165  * INPUT:                                                                  *
    166  *		none.																						*
    167  *                                                                         *
    168  * OUTPUT:                                                                 *
    169  *		none.																						*
    170  *                                                                         *
    171  * WARNINGS:                                                               *
    172  *		none.																						*
    173  *                                                                         *
    174  * HISTORY:                                                                *
    175  *   12/20/1994 BR : Created.                                              *
    176  *=========================================================================*/
    177 void ConnectionClass::Init (void)
    178 {
    179 	NumRecNoAck = 0;
    180 	NumRecAck = 0;
    181 	NumSendNoAck = 0;
    182 	NumSendAck = 0;
    183 
    184 	LastSeqID = 0xffffffff;
    185 	LastReadID = 0xffffffff;
    186 
    187 	Queue->Init();
    188 
    189 }	/* end of Init */
    190 
    191 
    192 /***************************************************************************
    193  * ConnectionClass::Send_Packet -- adds a packet to the send queue			*
    194  *                                                                         *
    195  * This routine prefixes the given buffer with a CommHeaderType and			*
    196  * queues the resulting packet into the Send Queue.  (It's actually the		*
    197  * Service() routine that handles the hardware-dependent Send of the data).*
    198  * The packet's MagicNumber, Code, and PacketID are set here.					*
    199  *                                                                         *
    200  * INPUT:                                                                  *
    201  *		buf			buffer to send															*
    202  *		buflen		length of buffer														*
    203  *		ack_req		1 = ACK is required for this packet; 0 = isn't				*
    204  *                                                                         *
    205  * OUTPUT:                                                                 *
    206  *		1 = packet was queue'd OK, 0 = wasn't											*
    207  *                                                                         *
    208  * WARNINGS:                                                               *
    209  *		none.																						*
    210  *                                                                         *
    211  * HISTORY:                                                                *
    212  *   12/20/1994 BR : Created.                                              *
    213  *=========================================================================*/
    214 int ConnectionClass::Send_Packet (void * buf, int buflen, int ack_req)
    215 {
    216 	/*------------------------------------------------------------------------
    217 	Set the magic # for the packet
    218 	------------------------------------------------------------------------*/
    219 	((CommHeaderType *)PacketBuf)->MagicNumber = MagicNum;
    220 
    221 	/*------------------------------------------------------------------------
    222 	Set the packet Code: DATA_ACK if it requires an ACK, NOACK if it doesn't
    223 	Set the packet ID to the appropriate counter value.
    224 	------------------------------------------------------------------------*/
    225 	if (ack_req) {
    226 		((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_ACK;
    227 		((CommHeaderType *)PacketBuf)->PacketID = NumSendAck;
    228 	}
    229 	else {
    230 		((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_NOACK;
    231 		((CommHeaderType *)PacketBuf)->PacketID = NumSendNoAck;
    232 	}
    233 
    234 	/*------------------------------------------------------------------------
    235 	Now build the packet
    236 	------------------------------------------------------------------------*/
    237 	memcpy(PacketBuf + sizeof(CommHeaderType), buf, buflen);
    238 
    239 	/*------------------------------------------------------------------------
    240 	Add it to the queue; don't add any extra data with it.
    241 	------------------------------------------------------------------------*/
    242 	if (Queue->Queue_Send(PacketBuf,buflen + sizeof(CommHeaderType), NULL, 0)) {
    243 		if (ack_req) {
    244 			NumSendAck++;
    245 		}
    246 		else {
    247 			NumSendNoAck++;
    248 		}
    249 		return(1);
    250 	}
    251 	else {
    252 		return(0);
    253 	}
    254 
    255 }	/* end of Send_Packet */
    256 
    257 
    258 /***************************************************************************
    259  * ConnectionClass::Receive_Packet -- adds packet to receive queue			*
    260  *                                                                         *
    261  * INPUT:                                                                  *
    262  *		buf		buffer to process (already includes CommHeaderType)			*
    263  *		buflen	length of buffer to process											*
    264  *                                                                         *
    265  * OUTPUT:                                                                 *
    266  *		1 = packet was processed OK, 0 = error											*
    267  *                                                                         *
    268  * WARNINGS:                                                               *
    269  *		none.																						*
    270  *                                                                         *
    271  * HISTORY:                                                                *
    272  *   12/20/1994 BR : Created.                                              *
    273  *=========================================================================*/
    274 int ConnectionClass::Receive_Packet (void * buf, int buflen)
    275 {
    276 	CommHeaderType *packet;								// ptr to packet header
    277 	SendQueueType *send_entry;							// ptr to send entry header
    278 	ReceiveQueueType *rec_entry;						// ptr to recv entry header
    279 	CommHeaderType *entry_data;						// ptr to queue entry data
    280 	CommHeaderType ackpacket;							// ACK packet to send
    281 	int i;
    282 	int save_packet = 1;									// 0 = this is a resend
    283 	int found;
    284 
    285 	/*------------------------------------------------------------------------
    286 	Check the magic #
    287 	------------------------------------------------------------------------*/
    288 	packet = (CommHeaderType *)buf;
    289 	if (packet->MagicNumber != MagicNum) {
    290 		return(0);
    291 	}
    292 
    293 	/*------------------------------------------------------------------------
    294 	Handle an incoming ACK
    295 	------------------------------------------------------------------------*/
    296 	if (packet->Code == PACKET_ACK) {
    297 
    298 		for (i = 0; i < Queue->Num_Send(); i++) {
    299 			/*..................................................................
    300 			Get queue entry ptr
    301 			..................................................................*/
    302 			send_entry = Queue->Get_Send(i);
    303 
    304 			/*..................................................................
    305 			If ptr is valid, get ptr to its data
    306 			..................................................................*/
    307 			if (send_entry != NULL) {
    308 				entry_data = (CommHeaderType *)send_entry->Buffer;
    309 
    310 				/*...............................................................
    311 				If ACK is for this entry, mark it
    312 				...............................................................*/
    313 				if (packet->PacketID==entry_data->PacketID &&
    314 					entry_data->Code == PACKET_DATA_ACK) {
    315 					send_entry->IsACK = 1;
    316 					break;
    317 				}
    318 			}
    319 		}
    320 
    321 		return(1);
    322 	}
    323 
    324 	/*------------------------------------------------------------------------
    325 	Handle an incoming PACKET_DATA_NOACK packet
    326 	------------------------------------------------------------------------*/
    327 	else if (packet->Code == PACKET_DATA_NOACK) {
    328 		/*.....................................................................
    329 		If there's only one slot left, don't tie up the queue with this packet
    330 		.....................................................................*/
    331 		if (Queue->Max_Receive() - Queue->Num_Receive() <= 1) {
    332 			return(0);
    333 		}
    334 
    335 		/*.....................................................................
    336 		Error if we can't queue the packet
    337 		.....................................................................*/
    338 		if (!Queue->Queue_Receive (buf, buflen, NULL, 0)) {
    339 			return(0);
    340 		}
    341 
    342 		NumRecNoAck++;
    343 
    344 		return(1);
    345 	}
    346 
    347 	/*------------------------------------------------------------------------
    348 	Handle an incoming PACKET_DATA_ACK packet
    349 	------------------------------------------------------------------------*/
    350 	else if (packet->Code == PACKET_DATA_ACK) {
    351 		/*.....................................................................
    352 		If this is a packet requires an ACK, and it's ID is older than our
    353 		"oldest" ID, we know it's a resend; send an ACK, but don't queue it
    354 		.....................................................................*/
    355 		if (packet->PacketID <= LastSeqID && LastSeqID != 0xffffffff) {
    356 			save_packet = 0;
    357 		}
    358 
    359 		/*.....................................................................
    360 		Otherwise, scan the queue for this entry; if it's found, it's a
    361 		resend, so don't save it.
    362 		.....................................................................*/
    363 		else {
    364 			save_packet = 1;
    365 			for (i = 0; i < Queue->Num_Receive(); i++) {
    366 				rec_entry = Queue->Get_Receive(i);
    367 
    368 				if (rec_entry) {
    369 
    370 					entry_data = (CommHeaderType *)rec_entry->Buffer;
    371 
    372 					/*...........................................................
    373 					Packet is found; it's a resend
    374 					...........................................................*/
    375 					if (entry_data->Code == PACKET_DATA_ACK &&
    376 						entry_data->PacketID == packet->PacketID) {
    377 						save_packet = 0;
    378 						break;
    379 					}
    380 				}
    381 			}
    382 		}	/* end of scan for resend */
    383 
    384 		/*.....................................................................
    385 		Queue the packet & update our LastSeqID value.
    386 		.....................................................................*/
    387 		if (save_packet) {
    388 			/*..................................................................
    389 			If there's only one slot left, make sure we only put a packet in it
    390 			if this packet will let us increment our LastSeqID; otherwise, we'll
    391 			get stuck, forever unable to increment LastSeqID.
    392 			..................................................................*/
    393 			if (Queue->Max_Receive() - Queue->Num_Receive() <= 1) {
    394 				if (packet->PacketID != (LastSeqID + 1) ) {
    395 					return(0);
    396 				}
    397 			}
    398 
    399 			/*..................................................................
    400 			If we can't queue the packet, return; don't send an ACK.
    401 			..................................................................*/
    402 			if (!Queue->Queue_Receive (buf, buflen, NULL, 0)) {
    403 				return(0);
    404 			}
    405 
    406 			NumRecAck++;
    407 
    408 			/*..................................................................
    409 			Update our LastSeqID value if we can.  Anything less than LastSeqID
    410 			we'll know is a resend.
    411 			..................................................................*/
    412 			if (packet->PacketID == (LastSeqID + 1)) {
    413 				LastSeqID = packet->PacketID;
    414 				/*...............................................................
    415 				Now that we have a new 'LastSeqID', search our Queue to see if
    416 				the next ID is there; if so, keep checking for the next one;
    417 				break only when the next one isn't found.  This forces
    418 				LastSeqID to be the largest possible value.
    419 				...............................................................*/
    420 				do {
    421 					found = 0;
    422 					for (i = 0; i < Queue->Num_Receive(); i++) {
    423 
    424 						rec_entry = Queue->Get_Receive(i);
    425 
    426 						if (rec_entry) {
    427 							entry_data = (CommHeaderType *)rec_entry->Buffer;
    428 
    429 							/*......................................................
    430 							Entry is found
    431 							......................................................*/
    432 							if (entry_data->Code == PACKET_DATA_ACK &&
    433 								entry_data->PacketID == (LastSeqID + 1)) {
    434 
    435 								LastSeqID = entry_data->PacketID;
    436 								found = 1;
    437 								break;
    438 							}
    439 						}
    440 					}
    441 				} while (found);
    442 			}
    443 		}	/* end of save packet */
    444 
    445 		/*.....................................................................
    446 		Send an ACK, regardless of whether this was a resend or not.
    447 		.....................................................................*/
    448 		ackpacket.MagicNumber = Magic_Num();
    449 		ackpacket.Code = PACKET_ACK;
    450 		ackpacket.PacketID = packet->PacketID;
    451 		Send ((char *)&ackpacket, sizeof(CommHeaderType), NULL, 0);
    452 
    453 		return(1);
    454 	}
    455 
    456 	return(0);
    457 
    458 }	/* end of Receive_Packet */
    459 
    460 
    461 /***************************************************************************
    462  * ConnectionClass::Get_Packet -- gets a packet from receive queue			*
    463  *                                                                         *
    464  * INPUT:                                                                  *
    465  *		buf		location to store buffer												*
    466  *		buflen	filled in with length of 'buf'										*
    467  *                                                                         *
    468  * OUTPUT:                                                                 *
    469  *		1 = packet was read, 0 = wasn't													*
    470  *                                                                         *
    471  * WARNINGS:                                                               *
    472  *		none.																						*
    473  *                                                                         *
    474  * HISTORY:                                                                *
    475  *   12/20/1994 BR : Created.                                              *
    476  *=========================================================================*/
    477 int ConnectionClass::Get_Packet (void * buf, int *buflen)
    478 {
    479 	ReceiveQueueType *rec_entry;					// ptr to receive entry header
    480 	int packetlen;										// size of received packet
    481 	CommHeaderType *entry_data;
    482 	int i;
    483 
    484 	/*------------------------------------------------------------------------
    485 	Ensure that we read the packets in order.  LastReadID is the ID of the
    486 	last PACKET_DATA_ACK packet we read.
    487 	------------------------------------------------------------------------*/
    488 	for (i = 0; i < Queue->Num_Receive(); i++) {
    489 
    490 		rec_entry = Queue->Get_Receive(i);
    491 
    492 		/*.....................................................................
    493 		Only read this entry if it hasn't been yet
    494 		.....................................................................*/
    495 		if (rec_entry && rec_entry->IsRead==0) {
    496 
    497 			entry_data = (CommHeaderType *)rec_entry->Buffer;
    498 
    499 			/*..................................................................
    500 			If this is a DATA_ACK packet, its ID must be one greater than
    501 			the last one we read.
    502 			..................................................................*/
    503 			if ( (entry_data->Code == PACKET_DATA_ACK) &&
    504 				(entry_data->PacketID == (LastReadID + 1))) {
    505 
    506 				LastReadID = entry_data->PacketID;
    507 				rec_entry->IsRead = 1;
    508 
    509 				packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
    510 				if (packetlen > 0) {
    511 					memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType),
    512 						packetlen);
    513 				}
    514 				(*buflen) = packetlen;
    515 				return(1);
    516 			}
    517 			/*..................................................................
    518 			If this is a DATA_NOACK packet, who cares what the ID is?
    519 			..................................................................*/
    520 			else if (entry_data->Code == PACKET_DATA_NOACK) {
    521 				rec_entry->IsRead = 1;
    522 
    523 				packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
    524 				if (packetlen > 0) {
    525 					memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType),
    526 						packetlen);
    527 				}
    528 				(*buflen) = packetlen;
    529 				return(1);
    530 			}
    531 		}
    532 	}
    533 
    534 	return(0);
    535 
    536 }	/* end of Get_Packet */
    537 
    538 
    539 /***************************************************************************
    540  * ConnectionClass::Service -- main polling routine; services packets		*
    541  *                                                                         *
    542  * INPUT:                                                                  *
    543  *		none.																						*
    544  *                                                                         *
    545  * OUTPUT:                                                                 *
    546  *		1 = OK, 0 = error (connection is broken!)										*
    547  *                                                                         *
    548  * WARNINGS:                                                               *
    549  *		none.																						*
    550  *                                                                         *
    551  * HISTORY:                                                                *
    552  *   12/20/1994 BR : Created.                                              *
    553  *=========================================================================*/
    554 int ConnectionClass::Service (void)
    555 {
    556 	/*------------------------------------------------------------------------
    557 	Service the Send Queue:  This [re]sends packets in the Send Queue which
    558 	haven't been ACK'd yet, and if their retry timeout has expired, and
    559 	updates the FirstTime, LastTime & SendCount values in the Queue entry.
    560 	Entries that have been ACK'd should be removed.
    561 
    562 	Service the Receive Queue:  This sends ACKs for packets that haven't
    563 	been ACK'd yet.  Entries that the app has read, and have been ACK'd,
    564 	should be removed.
    565 	------------------------------------------------------------------------*/
    566 	if ( Service_Send_Queue() && Service_Receive_Queue() ) {
    567 		return(1);
    568 	}
    569 	else {
    570 		return(0);
    571 	}
    572 
    573 }	/* end of Service */
    574 
    575 
    576 /***************************************************************************
    577  * ConnectionClass::Service_Send_Queue -- services the send queue				*
    578  *                                                                         *
    579  * INPUT:                                                                  *
    580  *		none.																						*
    581  *                                                                         *
    582  * OUTPUT:                                                                 *
    583  *		1 = OK, 0 = error																		*
    584  *                                                                         *
    585  * WARNINGS:                                                               *
    586  *		none.																						*
    587  *                                                                         *
    588  * HISTORY:                                                                *
    589  *   12/20/1994 BR : Created.                                              *
    590  *=========================================================================*/
    591 int ConnectionClass::Service_Send_Queue (void)
    592 {
    593 	int i;
    594 	int num_entries;
    595 	SendQueueType *send_entry;						// ptr to send queue entry
    596 	CommHeaderType *packet_hdr;					// packet header
    597 	unsigned long curtime;							// current time
    598 	int bad_conn = 0;
    599 
    600 	/*------------------------------------------------------------------------
    601 	Remove any ACK'd packets from the queue
    602 	------------------------------------------------------------------------*/
    603 	for (i = 0; i < Queue->Num_Send(); i++) {
    604 		/*.....................................................................
    605 		Get this queue entry
    606 		.....................................................................*/
    607 		send_entry = Queue->Get_Send(i);
    608 
    609 		/*.....................................................................
    610 		If ACK has been received, unqueue it
    611 		.....................................................................*/
    612 		if (send_entry->IsACK) {
    613 
    614 			/*..................................................................
    615 			Update this queue's response time
    616 			..................................................................*/
    617 			packet_hdr = (CommHeaderType *)send_entry->Buffer;
    618 			if (packet_hdr->Code == PACKET_DATA_ACK) {
    619 				Queue->Add_Delay(Time() - send_entry->FirstTime);
    620 			}
    621 
    622 			/*..................................................................
    623 			Unqueue the packet
    624 			..................................................................*/
    625 			Queue->UnQueue_Send(NULL,NULL,i,NULL,NULL);
    626 			i--;
    627 		}
    628 	}
    629 
    630 	/*------------------------------------------------------------------------
    631 	Loop through all entries in the Send queue.  [Re]Send any entries that
    632 	need it.
    633 	------------------------------------------------------------------------*/
    634 	num_entries = Queue->Num_Send();
    635 
    636 	for (i = 0; i < num_entries; i++) {
    637 		send_entry = Queue->Get_Send(i);
    638 
    639 		if (send_entry->IsACK) {
    640 			continue;
    641 		}
    642 
    643 		/*.....................................................................
    644 		Only send the message if time has elapsed.  (The message's Time
    645 		fields are init'd to 0 when a message is queue'd or unqueue'd, so the
    646 		first time through, the delta time will appear large.)
    647 		.....................................................................*/
    648 		curtime = Time();
    649 		if (curtime - send_entry->LastTime > RetryDelta) {
    650 
    651 			/*..................................................................
    652 			Send the message
    653 			..................................................................*/
    654 			Send (send_entry->Buffer, send_entry->BufLen, send_entry->ExtraBuffer,
    655 				send_entry->ExtraLen);
    656 
    657 			/*..................................................................
    658 			Fill in Time fields
    659 			..................................................................*/
    660 			send_entry->LastTime = curtime;
    661 			if (send_entry->SendCount==0) {
    662 				send_entry->FirstTime = curtime;
    663 
    664 				/*...............................................................
    665 				If this is the 1st time we're sending this packet, and it doesn't
    666 				require an ACK, mark it as ACK'd; then, the next time through,
    667 				it will just be removed from the queue.
    668 				...............................................................*/
    669 				packet_hdr = (CommHeaderType *)send_entry->Buffer;
    670 				if (packet_hdr->Code == PACKET_DATA_NOACK) {
    671 					send_entry->IsACK = 1;
    672 				}
    673 			}
    674 
    675 			/*..................................................................
    676 			Update SendCount
    677 			..................................................................*/
    678 			send_entry->SendCount++;
    679 
    680 			/*..................................................................
    681 			Perform error detection, based on either MaxRetries or Timeout
    682 			..................................................................*/
    683 			if (MaxRetries != -1 && send_entry->SendCount > MaxRetries) {
    684 				bad_conn = 1;
    685 			}
    686 
    687 			if (Timeout != -1 &&
    688 				(send_entry->LastTime - send_entry->FirstTime) > Timeout) {
    689 				bad_conn = 1;
    690 			}
    691 		}
    692 	}
    693 
    694 	/*------------------------------------------------------------------------
    695 	If the connection is going bad, return an error
    696 	------------------------------------------------------------------------*/
    697 	if (bad_conn) {
    698 		return(0);
    699 	}
    700 	else {
    701 		return(1);
    702 	}
    703 
    704 }	/* end of Service_Send_Queue */
    705 
    706 
    707 /***************************************************************************
    708  * ConnectionClass::Service_Receive_Queue -- services receive queue			*
    709  *                                                                         *
    710  * INPUT:                                                                  *
    711  *		none.																						*
    712  *                                                                         *
    713  * OUTPUT:                                                                 *
    714  *		1 = OK, 0 = error																		*
    715  *                                                                         *
    716  * WARNINGS:                                                               *
    717  *		none.																						*
    718  *                                                                         *
    719  * HISTORY:                                                                *
    720  *   12/20/1994 BR : Created.                                              *
    721  *=========================================================================*/
    722 int ConnectionClass::Service_Receive_Queue (void)
    723 {
    724 	ReceiveQueueType *rec_entry;					// ptr to receive entry header
    725 	CommHeaderType *packet_hdr;					// packet header
    726 	int i;
    727 
    728 	/*------------------------------------------------------------------------
    729 	Remove all dead packets.
    730 	PACKET_DATA_NOACK: if it's been read, throw it away.
    731 	PACKET_DATA_ACK: if it's been read, and its ID is older than LastSeqID,
    732 	throw it away.
    733 	------------------------------------------------------------------------*/
    734 	for (i = 0; i < Queue->Num_Receive(); i++) {
    735 		rec_entry = Queue->Get_Receive(i);
    736 
    737 		if (rec_entry->IsRead) {
    738 			packet_hdr = (CommHeaderType *)(rec_entry->Buffer);
    739 
    740 			if (packet_hdr->Code == PACKET_DATA_NOACK) {
    741 				Queue->UnQueue_Receive(NULL,NULL,i,NULL,NULL);
    742 				i--;
    743 
    744 			}
    745 			else if (packet_hdr->PacketID < LastSeqID) {
    746 				Queue->UnQueue_Receive(NULL,NULL,i,NULL,NULL);
    747 				i--;
    748 			}
    749 		}
    750 	}
    751 
    752 	return(1);
    753 
    754 }	/* end of Service_Receive_Queue */
    755 
    756 
    757 /***************************************************************************
    758  * ConnectionClass::Time -- gets current time										*
    759  *                                                                         *
    760  * INPUT:                                                                  *
    761  *                                                                         *
    762  * OUTPUT:                                                                 *
    763  *		none.																						*
    764  *                                                                         *
    765  * WARNINGS:                                                               *
    766  *		none.																						*
    767  *                                                                         *
    768  * HISTORY:                                                                *
    769  *   12/20/1994 BR : Created.                                              *
    770  *=========================================================================*/
    771 unsigned long ConnectionClass::Time (void)
    772 {
    773 	static struct timeb mytime;			// DOS time
    774 	unsigned long msec;
    775 
    776 #ifdef WWLIB32_H
    777 
    778 	/*------------------------------------------------------------------------
    779 	If the Westwood timer system has been activated, use TickCount's value
    780 	------------------------------------------------------------------------*/
    781 	if (TimerSystemOn) {
    782 		return(TickCount);				// Westwood Library time
    783 	}
    784 	/*------------------------------------------------------------------------
    785 	Otherwise, use the DOS timer
    786 	------------------------------------------------------------------------*/
    787 	else {
    788 		ftime(&mytime);
    789 		msec = (unsigned long)mytime.time * 1000L + (unsigned long)mytime.millitm;
    790 		return((msec / 100) * 6);
    791 	}
    792 
    793 #else
    794 
    795 	/*------------------------------------------------------------------------
    796 	If the Westwood library isn't being used, use the DOS timer.
    797 	------------------------------------------------------------------------*/
    798 	ftime(&mytime);
    799 	msec = (unsigned long)mytime.time * 1000L + (unsigned long)mytime.millitm;
    800 	return((msec / 100) * 6);
    801 
    802 #endif
    803 
    804 }	/* end of Time */
    805 
    806 
    807 /***************************************************************************
    808  * ConnectionClass::Command_Name -- returns name for given packet command  *
    809  *                                                                         *
    810  * INPUT:                                                                  *
    811  *		command		packet Command value to get name for							*
    812  *                                                                         *
    813  * OUTPUT:                                                                 *
    814  *		ptr to command name, NULL if invalid											*
    815  *                                                                         *
    816  * WARNINGS:                                                               *
    817  *		none.																						*
    818  *                                                                         *
    819  * HISTORY:                                                                *
    820  *   05/31/1995 BRR : Created.                                             *
    821  *=========================================================================*/
    822 char *ConnectionClass::Command_Name(int command)
    823 {
    824 	if (command >= 0 && command < PACKET_COUNT) {
    825 		return(Commands[command]);
    826 	}
    827 	else {
    828 		return(NULL);
    829 	}
    830 
    831 }	/* end of Command_Name */
    832 
    833 /************************** end of connect.cpp *****************************/
    834 
    835