| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688 |
- //
- // Copyright 2020 Electronic Arts Inc.
- //
- // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
- // software: you can redistribute it and/or modify it under the terms of
- // the GNU General Public License as published by the Free Software Foundation,
- // either version 3 of the License, or (at your option) any later version.
- // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
- // in the hope that it will be useful, but with permitted additional restrictions
- // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
- // distributed with this program. You should have received a copy of the
- // GNU General Public License along with permitted additional restrictions
- // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
- /* $Header: F:\projects\c&c\vcs\code\noseqcon.cpv 1.10 01 Mar 1996 18:08:30 JOE_BOSTIC $ */
- /***************************************************************************
- ** 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 **
- ***************************************************************************
- * *
- * Project Name : Command & Conquer *
- * *
- * File Name : SEQCONN.CPP *
- * *
- * Programmer : Bill Randolph *
- * *
- * Start Date : December 20, 1994 *
- * *
- * Last Update : April 9, 1995 [BRR] *
- * *
- *-------------------------------------------------------------------------*
- * Functions: *
- * NonSequencedConnClass::NonSequencedConnClass -- class constructor *
- * NonSequencedConnClass::~NonSequencedConnClass -- class destructor *
- * NonSequencedConnClass::Init -- Initializes connection queue to empty *
- * NonSequencedConnClass::Send_Packet -- adds a packet to the send queue *
- * NonSequencedConnClass::Receive_Packet -- adds packet to receive queue *
- * NonSequencedConnClass::Get_Packet -- gets a packet from receive queue *
- * NonSequencedConnClass::Service_Send_Queue -- services the send queue *
- * NonSequencedConnClass::Service_Receive_Queue -- services recieve queue*
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "function.h"
- #include "NOSEQCON.H"
- /***************************************************************************
- * NonSequencedConnClass::NonSequencedConnClass -- class constructor *
- * *
- * INPUT: *
- * numsend desired # of entries for the send queue *
- * numreceive desired # of entries for the recieve queue *
- * maxlen max length of an application packet *
- * magicnum the packet "magic number" for this connection *
- * retry_delta the time to wait between sends *
- * max_retries the max # of retries allowed for a packet *
- * (-1 means retry forever, based on this parameter) *
- * timeout the max amount of time before we give up on a packet *
- * (-1 means retry forever, based on this parameter) *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/20/1994 BR : Created. *
- *=========================================================================*/
- NonSequencedConnClass::NonSequencedConnClass (int numsend, int numreceive,
- int maxlen, unsigned short magicnum, unsigned long retry_delta,
- unsigned long max_retries, unsigned long timeout) :
- ConnectionClass (maxlen, magicnum, retry_delta, max_retries, timeout)
- {
- /*------------------------------------------------------------------------
- Allocate the packet Queue. This will store incoming packets (which will
- be placed there by the Connection Manager), and outgoing packets (which
- are placed there by this class when it "sends" a packet).
- ------------------------------------------------------------------------*/
- Queue = new CommBufferClass (numsend, numreceive, MaxPacketLen);
- }
- /***************************************************************************
- * NonSequencedConnClass::~NonSequencedConnClass -- class destructor *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/20/1994 BR : Created. *
- *=========================================================================*/
- NonSequencedConnClass::~NonSequencedConnClass ()
- {
- delete Queue;
- }
- /***************************************************************************
- * NonSequencedConnClass::Init -- Initializes connection queue to empty *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/20/1994 BR : Created. *
- *=========================================================================*/
- void NonSequencedConnClass::Init (void)
- {
- NumRecNoAck = 0;
- NumRecAck = 0;
- NumSendNoAck = 0;
- NumSendAck = 0;
- LastSeqID = 0xffffffff;
- LastReadID = 0xffffffff;
- Queue->Init();
- }
- /***************************************************************************
- * NonSequencedConnClass::Send_Packet -- adds a packet to the send queue *
- * *
- * This routine prefixes the given buffer with a CommHeaderType and *
- * queues the resulting packet into the Send Queue. (It's actually the *
- * Service() routine that handles the hardware-dependent Send of the data).*
- * The packet's MagicNumber, Code, and PacketID are set here. *
- * *
- * INPUT: *
- * buf buffer to send *
- * buflen length of buffer *
- * ack_req true = ACK is required for this packet; false = isn't *
- * *
- * OUTPUT: *
- * 1 = packet was queue'd OK, 0 = wasn't *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/20/1994 BR : Created. *
- *=========================================================================*/
- int NonSequencedConnClass::Send_Packet (void * buf, int buflen, int ack_req)
- {
- /*........................................................................
- Set the magic # for the packet
- ........................................................................*/
- ((CommHeaderType *)PacketBuf)->MagicNumber = MagicNum;
- /*........................................................................
- Set the packet Code: DATA_ACK if it requires an ACK, NOACK if it doesn't
- Set the packet ID to the appropriate counter value.
- ........................................................................*/
- if (ack_req) {
- ((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_ACK;
- ((CommHeaderType *)PacketBuf)->PacketID = NumSendAck;
- } else {
- ((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_NOACK;
- ((CommHeaderType *)PacketBuf)->PacketID = NumSendNoAck;
- }
- /*........................................................................
- Now build the packet
- ........................................................................*/
- memcpy(PacketBuf + sizeof(CommHeaderType), buf, buflen);
- /*........................................................................
- Add it to the queue.
- ........................................................................*/
- if (Queue->Queue_Send(PacketBuf,buflen + sizeof(CommHeaderType))) {
- if (ack_req) {
- // Smart_Printf( "Packet ack Queued ID %d \n", ((CommHeaderType *)PacketBuf)->PacketID );
- NumSendAck++;
- } else {
- // Smart_Printf( "Packet noack Queued ID %d \n", ((CommHeaderType *)PacketBuf)->PacketID );
- NumSendNoAck++;
- }
- return(true);
- } else {
- // Smart_Printf( "Packet not Queued ID %d \n", ((CommHeaderType *)PacketBuf)->PacketID );
- return(false);
- }
- }
- /***************************************************************************
- * NonSequencedConnClass::Receive_Packet -- adds packet to the receive queue *
- * *
- * INPUT: *
- * buf buffer to process (already includes CommHeaderType) *
- * buflen length of buffer to process *
- * *
- * OUTPUT: *
- * 1 = packet was processed OK, 0 = error *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/20/1994 BR : Created. *
- *=========================================================================*/
- int NonSequencedConnClass::Receive_Packet (void * buf, int buflen)
- {
- CommHeaderType *packet; // ptr to packet header
- SendQueueType *send_entry; // ptr to send entry header
- ReceiveQueueType *rec_entry; // ptr to recv entry header
- CommHeaderType *entry_data; // ptr to queue entry data
- CommHeaderType ackpacket; // ACK packet to send
- int i;
- int save_packet = 1; // 0 = this is a resend
- int found;
- /*
- --------------------------- Check the magic # ----------------------------
- */
- packet = (CommHeaderType *)buf;
- if (packet->MagicNumber != MagicNum) {
- // Smart_Printf( "Bad Magic Number\n" );
- return(false);
- }
- /*------------------------------------------------------------------------
- Handle an incoming ACK
- ------------------------------------------------------------------------*/
- if (packet->Code == PACKET_ACK) {
- for (i = 0; i < Queue->Num_Send(); i++) {
- /*
- ....................... Get queue entry ptr ........................
- */
- send_entry = Queue->Get_Send(i);
- /*
- ............... If ptr is valid, get ptr to its data ...............
- */
- if (send_entry != NULL) {
- entry_data = (CommHeaderType *)send_entry->Buffer;
- /*
- .............. If ACK is for this entry, mark it ................
- */
- if (packet->PacketID==entry_data->PacketID &&
- entry_data->Code == PACKET_DATA_ACK) {
- // Smart_Printf( "Received ACK for %d \n", packet->PacketID );
- send_entry->IsACK = 1;
- break;
- }
- }
- }
- //{
- // if (i == Queue->Num_Send() ) {
- // Smart_Printf( "Received bad ACK for %d \n", packet->PacketID );
- // }
- //}
- return(true);
- }
- /*------------------------------------------------------------------------
- Handle an incoming PACKET_DATA_NOACK packet
- ------------------------------------------------------------------------*/
- else if (packet->Code == PACKET_DATA_NOACK) {
- /*---------------------------------------------------------------------
- If there's only one slot left, don't tie up the queue with this packet
- ---------------------------------------------------------------------*/
- if (Queue->Max_Receive() - Queue->Num_Receive() <= 1) {
- // Smart_Printf( "Only one slot left don't tie up with DATA NOACK packet %d \n", packet->PacketID );
- return(false);
- }
- /*---------------------------------------------------------------------
- Error if we can't queue the packet
- ---------------------------------------------------------------------*/
- if (!Queue->Queue_Receive (buf, buflen)) {
- // Smart_Printf( "Can't Queue the packet %d \n", packet->PacketID );
- return(false);
- }
- // Smart_Printf( "Queued DATA NOACK for %d \n", packet->PacketID );
- NumRecNoAck++;
- return(true);
- }
- /*------------------------------------------------------------------------
- Handle an incoming PACKET_DATA_ACK packet
- ------------------------------------------------------------------------*/
- else if (packet->Code == PACKET_DATA_ACK) {
- // Smart_Printf( "Looking at ID %d, LastSeqID=%d \n", packet->PacketID, LastSeqID );
- /*....................................................................
- If this is a packet requires an ACK, and it's ID is older than our
- "oldest" ID, we know it's a resend; send an ACK, but don't queue it
- ....................................................................*/
- if (packet->PacketID <= LastSeqID && LastSeqID != 0xffffffff) {
- // Smart_Printf( "Older than oldest\n" );
- save_packet = 0;
- }
- /*....................................................................
- Otherwise, scan the queue for this entry; if it's found, it's a
- resend, so don't save it.
- ....................................................................*/
- else {
- save_packet = 1;
- for (i = 0; i < Queue->Num_Receive(); i++) {
- rec_entry = Queue->Get_Receive(i);
- if (rec_entry) {
- entry_data = (CommHeaderType *)rec_entry->Buffer;
- /*...........................................................
- Packet is found; it's a resend
- ...........................................................*/
- if (entry_data->Code == PACKET_DATA_ACK &&
- entry_data->PacketID == packet->PacketID) {
- // Smart_Printf( "It's a resend\n" );
- save_packet = 0;
- break;
- }
- }
- }
- } /* end of scan for resend */
- /*---------------------------------------------------------------------
- Queue the packet & update our LastSeqID value.
- ---------------------------------------------------------------------*/
- if (save_packet) {
- /*------------------------------------------------------------------
- If there's only one slot left, make sure we only put a packet in it if
- this packet will let us increment our LastSeqID; otherwise, we'll get
- stuck, forever unable to increment LastSeqID.
- ------------------------------------------------------------------*/
- if (Queue->Max_Receive() - Queue->Num_Receive() <= 1) {
- if (packet->PacketID != (LastSeqID + 1) ) {
- // Smart_Printf( "One slot left not what we looking for max=%d,num=%d \n",
- // Queue->Max_Receive(), Queue->Num_Receive() );
- return(0);
- }
- }
- /*------------------------------------------------------------------
- If we can't queue the packet, return; don't send an ACK.
- ------------------------------------------------------------------*/
- if (!Queue->Queue_Receive (buf, buflen)) {
- // Smart_Printf( "unable to queue packet\n" );
- return(0);
- }
- NumRecAck++;
- /*------------------------------------------------------------------
- Update our LastSeqID value if we can. Anything less than LastSeqID
- we'll know is a resend.
- ------------------------------------------------------------------*/
- if (packet->PacketID == (LastSeqID + 1)) {
- LastSeqID = packet->PacketID;
- /*............................................................
- Now that we have a new 'LastSeqID', search our Queue to see if
- the next ID is there; if so, keep checking for the next one;
- break only when the next one isn't found. This forces
- LastSeqID to be the largest possible value.
- ............................................................*/
- do {
- found = 0;
- for (i = 0; i < Queue->Num_Receive(); i++) {
- rec_entry = Queue->Get_Receive(i);
- if (rec_entry) {
- entry_data = (CommHeaderType *)rec_entry->Buffer;
- /*......................................................
- Entry is found
- ......................................................*/
- if (entry_data->Code == PACKET_DATA_ACK &&
- entry_data->PacketID == (LastSeqID + 1)) {
- LastSeqID = entry_data->PacketID;
- found = 1;
- break;
- }
- }
- }
- } while (found);
- }
- } /* end of save packet */
- /*---------------------------------------------------------------------
- Send an ACK, regardless of whether this was a resend or not.
- ---------------------------------------------------------------------*/
- ackpacket.MagicNumber = Magic_Num();
- ackpacket.Code = PACKET_ACK;
- ackpacket.PacketID = packet->PacketID;
- // Smart_Printf( "Sending ACK for %d \n", packet->PacketID );
- Send ((char *)&ackpacket, sizeof(CommHeaderType));
- return(true);
- } else {
- // Smart_Printf( "invalid packet type %d \n", packet->Code );
- }
- return(false);
- }
- /***************************************************************************
- * NonSequencedConnClass::Get_Packet -- gets a packet from receive queue *
- * *
- * INPUT: *
- * buf location to store buffer *
- * buflen filled in with length of 'buf' *
- * *
- * OUTPUT: *
- * 1 = packet was read, 0 = wasn't *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/20/1994 BR : Created. *
- *=========================================================================*/
- int NonSequencedConnClass::Get_Packet (void * buf, int *buflen)
- {
- ReceiveQueueType *rec_entry; // ptr to receive entry header
- int packetlen; // size of received packet
- CommHeaderType *entry_data;
- int i;
- /*------------------------------------------------------------------------
- Ensure that we read the packets in order. LastReadID is the ID of the
- last PACKET_DATA_ACK packet we read.
- ------------------------------------------------------------------------*/
- for (i = 0; i < Queue->Num_Receive(); i++) {
- rec_entry = Queue->Get_Receive(i);
- /*.....................................................................
- Only read this entry if it hasn't been yet
- .....................................................................*/
- if (rec_entry && rec_entry->IsRead==0) {
- entry_data = (CommHeaderType *)rec_entry->Buffer;
- /*..................................................................
- If this is a DATA_ACK packet, its ID must be one greater than
- the last one we read.
- ..................................................................*/
- if ( (entry_data->Code == PACKET_DATA_ACK) &&
- (entry_data->PacketID == (LastReadID + 1))) {
- LastReadID = entry_data->PacketID;
- rec_entry->IsRead = 1;
- packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
- if (packetlen > 0) {
- memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType), packetlen);
- }
- (*buflen) = packetlen;
- return(true);
- }
- /*..................................................................
- If this is a DATA_NOACK packet, who cares what the ID is?
- ..................................................................*/
- else if (entry_data->Code == PACKET_DATA_NOACK) {
- rec_entry->IsRead = 1;
- packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
- if (packetlen > 0) {
- memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType), packetlen);
- }
- (*buflen) = packetlen;
- return(true);
- }
- }
- }
- return(false);
- }
- /***************************************************************************
- * NonSequencedConnClass::Service_Send_Queue -- services the send queue *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * 1 = OK, 0 = error *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/20/1994 BR : Created. *
- *=========================================================================*/
- int NonSequencedConnClass::Service_Send_Queue (void)
- {
- int i;
- int num_entries;
- SendQueueType *send_entry; // ptr to send queue entry
- CommHeaderType *packet_hdr; // packet header
- unsigned long curtime; // current time
- int bad_conn = 0;
- /*------------------------------------------------------------------------
- Remove any ACK'd packets from the queue
- ------------------------------------------------------------------------*/
- for (i = 0; i < Queue->Num_Send(); i++) {
- /*
- ------------------------- Get this queue entry ------------------------
- */
- send_entry = Queue->Get_Send(i);
- /*
- ---------------- If ACK has been received, unqueue it -----------------
- */
- if (send_entry->IsACK) {
- /*
- ................ Update this queue's response time .................
- */
- packet_hdr = (CommHeaderType *)send_entry->Buffer;
- if (packet_hdr->Code == PACKET_DATA_ACK) {
- Queue->Add_Delay(Time() - send_entry->FirstTime);
- }
- /*
- ....................... unqueue the packet .........................
- */
- Queue->UnQueue_Send(NULL,NULL,i);
- i--;
- }
- }
- /*------------------------------------------------------------------------
- Loop through all entries in the Send queue. [Re]Send any entries that
- need it.
- ------------------------------------------------------------------------*/
- num_entries = Queue->Num_Send();
- for (i = 0; i < num_entries; i++) {
- send_entry = Queue->Get_Send(i);
- if (send_entry->IsACK) {
- continue;
- }
- /*.....................................................................
- Only send the message if time has elapsed. (The message's Time
- fields are init'd to 0 when a message is queue'd or unqueue'd, so the
- first time through, the delta time will appear large.)
- .....................................................................*/
- curtime = Time();
- if (curtime - send_entry->LastTime > RetryDelta) {
- /*
- ......................... Send the message .........................
- */
- #if(0)
- {
- packet_hdr = (CommHeaderType *)send_entry->Buffer;
- if (send_entry->SendCount) {
- if (packet_hdr->Code == PACKET_DATA_NOACK) {
- // Smart_Printf( "Resending DATA NOACK for %d \n", packet_hdr->PacketID );
- } else {
- if (packet_hdr->Code == PACKET_DATA_ACK) {
- // Smart_Printf( "Resending DATA ACK for %d \n", packet_hdr->PacketID );
- }
- }
- } else {
- if (packet_hdr->Code == PACKET_DATA_NOACK) {
- // Smart_Printf( "Sending DATA NOACK for %d \n", packet_hdr->PacketID );
- } else {
- if (packet_hdr->Code == PACKET_DATA_ACK) {
- // Smart_Printf( "Sending DATA ACK for %d \n", packet_hdr->PacketID );
- }
- }
- }
- }
- #endif
- Send (send_entry->Buffer, send_entry->BufLen);
- /*
- ....................... Fill in Time fields ........................
- */
- send_entry->LastTime = curtime;
- if (send_entry->SendCount==0) {
- send_entry->FirstTime = curtime;
- /*...............................................................
- If this is the 1st time we're sending this packet, and it doesn't
- require an ACK, mark it as ACK'd; then, the next time through,
- it will just be removed from the queue.
- ...............................................................*/
- packet_hdr = (CommHeaderType *)send_entry->Buffer;
- if (packet_hdr->Code == PACKET_DATA_NOACK) {
- send_entry->IsACK = 1;
- }
- }
- /*
- ......................... Update SendCount .........................
- */
- send_entry->SendCount++;
- /*..................................................................
- Perform error detection, based on either MaxRetries or Timeout
- ..................................................................*/
- if (MaxRetries != -1 && send_entry->SendCount > MaxRetries) {
- // Smart_Printf( "Max Retries!!! %d !!! \n", MaxRetries );
- bad_conn = 1;
- }
- if (Timeout != -1 &&
- (send_entry->LastTime - send_entry->FirstTime) > Timeout) {
- // Smart_Printf( "Timed out!!! Time %d, Timeout %d, buflen %d !!! \n",
- // (send_entry->LastTime - send_entry->FirstTime), Timeout,
- // send_entry->BufLen );
- bad_conn = 1;
- }
- }
- }
- /*------------------------------------------------------------------------
- If the connection is going bad, return an error
- ------------------------------------------------------------------------*/
- if (bad_conn) {
- // Smart_Printf( "Connection going bad!!! \n" );
- return(false);
- } else {
- return(true);
- }
- }
- /***************************************************************************
- * NonSequencedConnClass::Service_Receive_Queue -- services recieve queue *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * 1 = OK, 0 = error *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 12/20/1994 BR : Created. *
- *=========================================================================*/
- int NonSequencedConnClass::Service_Receive_Queue (void)
- {
- ReceiveQueueType *rec_entry; // ptr to receive entry header
- CommHeaderType *packet_hdr; // packet header
- int i;
- /*------------------------------------------------------------------------
- Remove all dead packets.
- PACKET_DATA_NOACK: if it's been read, throw it away.
- PACKET_DATA_ACK: if it's been read, and its ID is older than LastSeqID,
- throw it away.
- ------------------------------------------------------------------------*/
- for (i = 0; i < Queue->Num_Receive(); i++) {
- rec_entry = Queue->Get_Receive(i);
- if (rec_entry->IsRead) {
- packet_hdr = (CommHeaderType *)(rec_entry->Buffer);
- if (packet_hdr->Code == PACKET_DATA_NOACK) {
- Queue->UnQueue_Receive(NULL,NULL,i);
- i--;
- } else {
- if (packet_hdr->PacketID < LastSeqID) {
- Queue->UnQueue_Receive(NULL,NULL,i);
- i--;
- }
- }
- }
- }
- return(true);
- }
|