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