SEQCONN.CPP 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. /*
  2. ** Command & Conquer Red Alert(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: F:\projects\c&c\vcs\code\seqconn.cpv 1.10 01 Mar 1996 18:29:54 JOE_BOSTIC $ */
  19. /***************************************************************************
  20. ** 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 **
  21. ***************************************************************************
  22. * *
  23. * Project Name : Command & Conquer *
  24. * *
  25. * File Name : SEQCONN.CPP *
  26. * *
  27. * Programmer : Bill Randolph *
  28. * *
  29. * Start Date : December 20, 1994 *
  30. * *
  31. * Last Update : April 9, 1995 [BRR] *
  32. * *
  33. *-------------------------------------------------------------------------*
  34. * Functions: *
  35. * SequencedConnClass::SequencedConnClass -- class constructor *
  36. * SequencedConnClass::~SequencedConnClass -- class destructor *
  37. * SequencedConnClass::Init -- Initializes connection queue to empty *
  38. * SequencedConnClass::Send_Packet -- adds a packet to the send queue *
  39. * SequencedConnClass::Receive_Packet -- adds packet to receive queue *
  40. * SequencedConnClass::Get_Packet -- gets a packet from receive queue *
  41. * SequencedConnClass::Service_Send_Queue -- services the send queue *
  42. * SequencedConnClass::Service_Receive_Queue -- services recieve queue *
  43. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  44. #include "function.h"
  45. #include "WolDebug.h"
  46. /***************************************************************************
  47. * SequencedConnClass::SequencedConnClass -- 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. SequencedConnClass::SequencedConnClass (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. NumRecNoAck = 0;
  75. NumRecAck = 0;
  76. NumSendNoAck = 0;
  77. NumSendAck = 0;
  78. /*------------------------------------------------------------------------
  79. Allocate the packet Queue. This will store incoming packets (which will
  80. be placed there by the Connection Manager), and outgoing packets (which
  81. are placed there by this class when it "sends" a packet).
  82. ------------------------------------------------------------------------*/
  83. Queue = new CommQueueClass (numsend, numreceive, MaxPacketLen);
  84. } /* end of SequencedConnClass */
  85. /***************************************************************************
  86. * SequencedConnClass::~SequencedConnClass -- class destructor *
  87. * *
  88. * INPUT: *
  89. * none. *
  90. * *
  91. * OUTPUT: *
  92. * none. *
  93. * *
  94. * WARNINGS: *
  95. * none. *
  96. * *
  97. * HISTORY: *
  98. * 12/20/1994 BR : Created. *
  99. *=========================================================================*/
  100. SequencedConnClass::~SequencedConnClass ()
  101. {
  102. delete Queue;
  103. }
  104. /***************************************************************************
  105. * SequencedConnClass::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 SequencedConnClass::Init (void)
  120. {
  121. Queue->Init();
  122. } /* end of Init */
  123. /***************************************************************************
  124. * SequencedConnClass::Send_Packet -- adds a packet to the send queue *
  125. * *
  126. * This routine prefixes the given buffer with a CommHeaderType and *
  127. * queues the resulting packet into the Send Queue. (It's actually the *
  128. * Service() routine that handles the hardware-dependent Send of the data).*
  129. * The packet's MagicNumber, Code, and PacketID are set here. *
  130. * *
  131. * INPUT: *
  132. * buf buffer to send *
  133. * buflen length of buffer *
  134. * ack_req true = ACK is required for this packet; false = isn't *
  135. * *
  136. * OUTPUT: *
  137. * 1 = packet was queue'd OK, 0 = wasn't *
  138. * *
  139. * WARNINGS: *
  140. * none. *
  141. * *
  142. * HISTORY: *
  143. * 12/20/1994 BR : Created. *
  144. *=========================================================================*/
  145. int SequencedConnClass::Send_Packet (void * buf, int buflen, int ack_req)
  146. {
  147. /*........................................................................
  148. Set the magic # for the packet
  149. ........................................................................*/
  150. ((CommHeaderType *)PacketBuf)->MagicNumber = MagicNum;
  151. /*........................................................................
  152. Set the packet Code: DATA_ACK if it requires an ACK, NOACK if it doesn't
  153. Set the packet ID to the appropriate counter value.
  154. ........................................................................*/
  155. if (ack_req) {
  156. ((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_ACK;
  157. ((CommHeaderType *)PacketBuf)->PacketID = NumSendAck;
  158. } else {
  159. ((CommHeaderType *)PacketBuf)->Code = PACKET_DATA_NOACK;
  160. ((CommHeaderType *)PacketBuf)->PacketID = NumSendNoAck;
  161. }
  162. /*........................................................................
  163. Now build the packet
  164. ........................................................................*/
  165. memcpy(PacketBuf + sizeof(CommHeaderType), buf, buflen);
  166. /*........................................................................
  167. Add it to the queue.
  168. ........................................................................*/
  169. if (Queue->Queue_Send(PacketBuf,buflen + sizeof(CommHeaderType))) {
  170. if (ack_req) {
  171. NumSendAck++;
  172. } else {
  173. NumSendNoAck++;
  174. }
  175. return(true);
  176. } else {
  177. return(false);
  178. }
  179. }
  180. /***************************************************************************
  181. * SequencedConnClass::Receive_Packet -- adds packet to the receive queue *
  182. * *
  183. * INPUT: *
  184. * buf buffer to process (already includes CommHeaderType) *
  185. * buflen length of buffer to process *
  186. * *
  187. * OUTPUT: *
  188. * 1 = packet was processed OK, 0 = error *
  189. * *
  190. * WARNINGS: *
  191. * none. *
  192. * *
  193. * HISTORY: *
  194. * 12/20/1994 BR : Created. *
  195. *=========================================================================*/
  196. int SequencedConnClass::Receive_Packet (void * buf, int buflen)
  197. {
  198. CommHeaderType *packet; // ptr to this packet
  199. SendQueueType *send_entry; // ptr to send entry header
  200. ReceiveQueueType *rec_entry; // ptr to receive entry header
  201. CommHeaderType *entry_data; // ptr to queue entry data
  202. int save_packet = 1; // 0 = this is a resend, or
  203. // out-of-order packet
  204. /*
  205. --------------------------- Check the magic # ----------------------------
  206. */
  207. packet = (CommHeaderType *)buf;
  208. if (packet->MagicNumber!=MagicNum)
  209. return(false);
  210. /*------------------------------------------------------------------------
  211. Process the packet based on its Code
  212. ------------------------------------------------------------------------*/
  213. switch (packet->Code) {
  214. /*.....................................................................
  215. DATA: If this is a No-Ack packet, always save it. Otherwise, only
  216. save it if it's received in the proper sequence.
  217. .....................................................................*/
  218. case PACKET_DATA_ACK:
  219. case PACKET_DATA_NOACK:
  220. if (packet->Code == PACKET_DATA_NOACK) {
  221. #ifdef DEBUG_SEQ
  222. printf("PACKET_DATA_NOACK received (%d)\n",packet->PacketID);
  223. #endif
  224. save_packet = 1;
  225. } else {
  226. #ifdef DEBUG_SEQ
  227. printf("PACKET_DATA_ACK received (%d)\n",packet->PacketID);
  228. #endif
  229. if ((packet->PacketID == NumRecAck)) {
  230. save_packet = 1;
  231. } else {
  232. save_packet = 0;
  233. /*...............................................................
  234. If this is a resend of our next-available received message, it
  235. means the other app didn't get our ACK, so mark it as
  236. non-acknowledged to tell Service_Receive_Queue to send an ACK.
  237. ...............................................................*/
  238. rec_entry = Queue->Next_Receive();
  239. if (rec_entry) {
  240. entry_data = (CommHeaderType *)rec_entry->Buffer;
  241. if (entry_data->PacketID==packet->PacketID &&
  242. entry_data->Code == PACKET_DATA_ACK) {
  243. rec_entry->IsACK = 0;
  244. #ifdef DEBUG_SEQ
  245. printf("(Resend)\n");
  246. #endif
  247. }
  248. }
  249. }
  250. }
  251. /*
  252. ...................... queue this packet ........................
  253. */
  254. if (save_packet) {
  255. if (!Queue->Queue_Receive(buf, buflen)) {
  256. return(false);
  257. }
  258. if (packet->Code == PACKET_DATA_ACK) {
  259. NumRecAck++;
  260. } else {
  261. NumRecNoAck++;
  262. }
  263. }
  264. break;
  265. /*.....................................................................
  266. ACK: If this ACK is for the latest-sent packet, mark that packet as
  267. acknowledged, then throw this packet away. Otherwise, ignore the ACK
  268. (if we re-sent before we received the other system's first ACK, this
  269. ACK will be a leftover)
  270. .....................................................................*/
  271. case PACKET_ACK:
  272. #ifdef DEBUG_SEQ
  273. printf("ACK received (%d)\n",packet->PacketID);
  274. #endif
  275. /*
  276. ....................... Get queue entry ptr ........................
  277. */
  278. send_entry = Queue->Next_Send();
  279. /*
  280. ............... If ptr is valid, get ptr to its data ...............
  281. */
  282. if (send_entry!=NULL) {
  283. entry_data = (CommHeaderType *)send_entry->Buffer;
  284. /*
  285. .............. If ACK is for this entry, mark it ................
  286. */
  287. if (packet->PacketID==entry_data->PacketID &&
  288. entry_data->Code == PACKET_DATA_ACK) {
  289. send_entry->IsACK = 1;
  290. }
  291. }
  292. break;
  293. /*.....................................................................
  294. Default: ignore the packet
  295. .....................................................................*/
  296. default:
  297. break;
  298. } /* end of switch */
  299. return(true);
  300. }
  301. /***************************************************************************
  302. * SequencedConnClass::Get_Packet -- gets a packet from the receive queue *
  303. * *
  304. * INPUT: *
  305. * buf location to store buffer *
  306. * buflen filled in with length of 'buf' *
  307. * *
  308. * OUTPUT: *
  309. * 1 = packet was read, 0 = wasn't *
  310. * *
  311. * WARNINGS: *
  312. * none. *
  313. * *
  314. * HISTORY: *
  315. * 12/20/1994 BR : Created. *
  316. *=========================================================================*/
  317. int SequencedConnClass::Get_Packet (void * buf, int *buflen)
  318. {
  319. ReceiveQueueType *rec_entry; // ptr to receive entry header
  320. int packetlen; // size of received packet
  321. /*
  322. ------------------ Get ptr to the next available entry -------------------
  323. */
  324. rec_entry = Queue->Next_Receive();
  325. /*
  326. ------------------------ Read it if it's un-read -------------------------
  327. */
  328. if (rec_entry!=NULL && rec_entry->IsRead==0) {
  329. /*
  330. ........................... Mark as read ..............................
  331. */
  332. rec_entry->IsRead = 1;
  333. /*
  334. .......................... Copy data packet ...........................
  335. */
  336. packetlen = rec_entry->BufLen - sizeof(CommHeaderType);
  337. if (packetlen > 0) {
  338. memcpy(buf, rec_entry->Buffer + sizeof(CommHeaderType), packetlen);
  339. }
  340. (*buflen) = packetlen;
  341. return(true);
  342. }
  343. return(false);
  344. }
  345. /***************************************************************************
  346. * SequencedConnClass::Service_Send_Queue -- services the send queue *
  347. * *
  348. * INPUT: *
  349. * none. *
  350. * *
  351. * OUTPUT: *
  352. * 1 = OK, 0 = error *
  353. * *
  354. * WARNINGS: *
  355. * none. *
  356. * *
  357. * HISTORY: *
  358. * 12/20/1994 BR : Created. *
  359. *=========================================================================*/
  360. int SequencedConnClass::Service_Send_Queue (void)
  361. {
  362. SendQueueType *send_entry; // ptr to send queue entry
  363. CommHeaderType *packet_hdr; // packet header
  364. unsigned long curtime; // current time
  365. /*------------------------------------------------------------------------
  366. - If the next packet is ACK'd remove it from the queue
  367. - If the next packet isn't ACK'd, [re-]send it
  368. ------------------------------------------------------------------------*/
  369. /*
  370. ......................... Get ptr to data to send ........................
  371. */
  372. send_entry = Queue->Next_Send();
  373. if (send_entry==NULL)
  374. return(true);
  375. /*
  376. ------------------ If ACK has been received, unqueue it ------------------
  377. */
  378. if (send_entry->IsACK) {
  379. /*
  380. .................. Update this queue's response time ..................
  381. */
  382. packet_hdr = (CommHeaderType *)send_entry->Buffer;
  383. if (packet_hdr->Code == PACKET_DATA_ACK) {
  384. Queue->Add_Delay(Time() - send_entry->FirstTime);
  385. }
  386. /*
  387. ......................... unqueue the packet ..........................
  388. */
  389. #ifdef DEBUG_SEQ
  390. printf(">>>Unqueueing Receive packet #%d<<<\n",packet_hdr->PacketID);
  391. #endif
  392. Queue->UnQueue_Send(NULL,NULL);
  393. } else {
  394. /*
  395. ----------------- ACK not received yet, [re-]send packet -----------------
  396. */
  397. /*.....................................................................
  398. Only send the message if time has elapsed. (The message's Time
  399. fields are init'd to 0 when a message is queue'd or unqueue'd, so the
  400. first time through, the delta time will appear large.)
  401. .....................................................................*/
  402. curtime = Time();
  403. if (curtime - send_entry->LastTime > RetryDelta) {
  404. /*
  405. ......................... Send the message .........................
  406. */
  407. Send (send_entry->Buffer, send_entry->BufLen);
  408. /*
  409. ....................... Fill in Time fields ........................
  410. */
  411. send_entry->LastTime = curtime;
  412. if (send_entry->SendCount==0) {
  413. send_entry->FirstTime = curtime;
  414. /*...............................................................
  415. If this is the 1st time we're sending this packet, and it doesn't
  416. require an ACK, mark it as ACK'd; then, the next time through,
  417. it will just be removed from the queue.
  418. ...............................................................*/
  419. packet_hdr = (CommHeaderType *)send_entry->Buffer;
  420. if (packet_hdr->Code == PACKET_DATA_NOACK)
  421. send_entry->IsACK = 1;
  422. }
  423. #ifdef DEBUG_SEQ
  424. packet_hdr = (CommHeaderType *)send_entry->Buffer;
  425. if (packet_hdr->Code == PACKET_DATA_NOACK) {
  426. printf("Sending PACKET_DATA_NOACK (%d)\n",packet_hdr->PacketID);
  427. } else {
  428. printf("Sending PACKET_DATA_ACK (%d)\n",packet_hdr->PacketID);
  429. }
  430. #endif
  431. /*
  432. ......................... Update SendCount .........................
  433. */
  434. send_entry->SendCount++;
  435. /*..................................................................
  436. Perform error detection, based on either MaxRetries or Timeout
  437. ..................................................................*/
  438. if (MaxRetries != -1 && send_entry->SendCount > MaxRetries)
  439. return(false);
  440. if (Timeout != -1 && send_entry->LastTime -
  441. send_entry->FirstTime > Timeout)
  442. return(false);
  443. }
  444. }
  445. return(true);
  446. }
  447. /***************************************************************************
  448. * SequencedConnClass::Service_Receive_Queue -- services the recieve queue *
  449. * *
  450. * INPUT: *
  451. * none. *
  452. * *
  453. * OUTPUT: *
  454. * 1 = OK, 0 = error *
  455. * *
  456. * WARNINGS: *
  457. * none. *
  458. * *
  459. * HISTORY: *
  460. * 12/20/1994 BR : Created. *
  461. *=========================================================================*/
  462. int SequencedConnClass::Service_Receive_Queue (void)
  463. {
  464. CommHeaderType ackpacket; // ACK packet to send
  465. ReceiveQueueType *rec_entry; // ptr to receive entry header
  466. CommHeaderType *packet_hdr; // packet header
  467. /*------------------------------------------------------------------------
  468. Get a pointer to the next received entry
  469. ------------------------------------------------------------------------*/
  470. rec_entry = Queue->Next_Receive();
  471. if (rec_entry==NULL)
  472. return(true);
  473. /*------------------------------------------------------------------------
  474. If this packet doesn't require an ACK, mark it as ACK'd.
  475. ------------------------------------------------------------------------*/
  476. packet_hdr = (CommHeaderType *)(rec_entry->Buffer);
  477. if (packet_hdr->Code==PACKET_DATA_NOACK)
  478. rec_entry->IsACK = 1;
  479. /*------------------------------------------------------------------------
  480. If this packet hasn't been ACK'd, send an ACK:
  481. - Fill in the MagicNum & the Code
  482. - Set the PacketID to the same ID that the sending system used, so the
  483. sending system knows which packet the ACK is for
  484. ------------------------------------------------------------------------*/
  485. if (rec_entry->IsACK==0) {
  486. #ifdef DEBUG_SEQ
  487. printf("Sending ACK (%d)\n",packet_hdr->PacketID);
  488. #endif
  489. ackpacket.MagicNumber = MagicNum;
  490. ackpacket.Code = PACKET_ACK;
  491. ackpacket.PacketID = packet_hdr->PacketID;
  492. Send((char *)&ackpacket, sizeof(CommHeaderType));
  493. rec_entry->IsACK = 1;
  494. }
  495. /*------------------------------------------------------------------------
  496. If this packet has been read by the application, and has been ACK'd, and
  497. there is another packet in the queue behind this one, it means the other
  498. system got the ACK we sent for this packet; remove this packet from the
  499. queue.
  500. ------------------------------------------------------------------------*/
  501. if (rec_entry!=NULL && rec_entry->IsRead && rec_entry->IsACK &&
  502. Queue->Num_Receive() > 1) {
  503. #ifdef DEBUG_SEQ
  504. printf(">>>Unqueueing Send packet #%d<<<\n",packet_hdr->PacketID);
  505. #endif
  506. Queue->UnQueue_Receive(NULL,NULL);
  507. }
  508. return(true);
  509. }