SEQCONN.CPP 24 KB

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