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