IPXGCONN.CPP 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  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: /CounterStrike/IPXGCONN.CPP 3 10/13/97 2:20p Steve_t $ */
  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 : IPXGCONN.CPP *
  22. * *
  23. * Programmer : Bill Randolph *
  24. * *
  25. * Start Date : December 20, 1994 *
  26. * *
  27. * Last Update : July 6, 1995 [BRR] *
  28. *-------------------------------------------------------------------------*
  29. * Functions: *
  30. * IPXGlobalConnClass::IPXGlobalConnClass -- class constructor *
  31. * IPXGlobalConnClass::~IPXGlobalConnClass -- class destructor *
  32. * IPXGlobalConnClass::Send_Packet -- adds a packet to the send queue *
  33. * IPXGlobalConnClass::Receive_Packet -- adds packet to the receive queue*
  34. * IPXGlobalConnClass::Get_Packet -- gets a packet from the receive queue*
  35. * IPXGlobalConnClass::Send -- sends a packet *
  36. * IPXGlobalConnClass::Service_Receive_Queue -- services receive queue *
  37. * IPXGlobalConnClass::Set_Bridge -- Sets up connection to cross a bridge*
  38. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  39. #include "function.h"
  40. #include <stdio.h>
  41. //#include <mem.h>
  42. #include "ipxgconn.h"
  43. /***************************************************************************
  44. * IPXGlobalConnClass::IPXGlobalConnClass -- class constructor *
  45. * *
  46. * This routine chains to the parent constructor, but it adjusts the size *
  47. * of the packet by the added bytes in the GlobalHeaderType structure. *
  48. * This forces the parent classes to allocate the proper sized PacketBuf *
  49. * for outgoing packets, and to set MaxPacketLen to the proper value. *
  50. * *
  51. * INPUT: *
  52. * numsend desired # of entries for the send queue *
  53. * numreceive desired # of entries for the receive queue *
  54. * maxlen max length of an application packet *
  55. * product_id unique ID for this product *
  56. * *
  57. * OUTPUT: *
  58. * none. *
  59. * *
  60. * WARNINGS: *
  61. * none. *
  62. * *
  63. * HISTORY: *
  64. * 12/20/1994 BR : Created. *
  65. *=========================================================================*/
  66. IPXGlobalConnClass::IPXGlobalConnClass (int numsend, int numreceive,
  67. int maxlen, unsigned short product_id) :
  68. IPXConnClass (numsend, numreceive,
  69. maxlen + sizeof(GlobalHeaderType) - sizeof(CommHeaderType),
  70. GLOBAL_MAGICNUM, // magic number for this connection
  71. NULL, // IPX Address (none)
  72. 0, // Connection ID
  73. "", // Connection Name
  74. sizeof (IPXAddressClass)) // extra storage for the sender's address
  75. {
  76. int i;
  77. ProductID = product_id;
  78. IsBridge = 0;
  79. for (i = 0; i < 4; i++) {
  80. LastPacketID[i] = 0xffffffff;
  81. }
  82. LastRXIndex = 0;
  83. } /* end of IPXGlobalConnClass */
  84. /***************************************************************************
  85. * IPXGlobalConnClass::Send_Packet -- adds a packet to the send queue *
  86. * *
  87. * This routine prefixes the given buffer with a GlobalHeaderType and *
  88. * queues the resulting packet into the Send Queue. The packet's *
  89. * MagicNumber, Code, PacketID, destination Address and ProductID are set *
  90. * here. *
  91. * *
  92. * INPUT: *
  93. * buf buffer to send *
  94. * buflen length of buffer *
  95. * address address to send the packet to (NULL = Broadcast) *
  96. * ack_req 1 = ACK is required for this packet; 0 = isn't *
  97. * *
  98. * OUTPUT: *
  99. * 1 = OK, 0 = error *
  100. * *
  101. * WARNINGS: *
  102. * none. *
  103. * *
  104. * HISTORY: *
  105. * 12/20/1994 BR : Created. *
  106. *=========================================================================*/
  107. int IPXGlobalConnClass::Send_Packet (void * buf, int buflen,
  108. IPXAddressClass *address, int ack_req)
  109. {
  110. IPXAddressClass dest_addr;
  111. /*------------------------------------------------------------------------
  112. Store the packet's Magic Number
  113. ------------------------------------------------------------------------*/
  114. ((GlobalHeaderType *)PacketBuf)->Header.MagicNumber = MagicNum;
  115. /*------------------------------------------------------------------------
  116. If this is a ACK-required packet, sent to a specific system, mark it as
  117. ACK-required; otherwise, mark as no-ACK-required.
  118. ------------------------------------------------------------------------*/
  119. if (ack_req && address != NULL) {
  120. ((GlobalHeaderType *)PacketBuf)->Header.Code = PACKET_DATA_ACK;
  121. }
  122. else {
  123. ((GlobalHeaderType *)PacketBuf)->Header.Code = PACKET_DATA_NOACK;
  124. }
  125. /*------------------------------------------------------------------------
  126. Fill in the packet ID. This will have very limited meaning; it only
  127. allows us to determine if an ACK packet we receive later goes with this
  128. packet; it doesn't let us detect re-sends of other systems' packets.
  129. ------------------------------------------------------------------------*/
  130. ((GlobalHeaderType *)PacketBuf)->Header.PacketID = Queue->Send_Total();
  131. /*------------------------------------------------------------------------
  132. Set the product ID for this packet.
  133. ------------------------------------------------------------------------*/
  134. ((GlobalHeaderType *)PacketBuf)->ProductID = ProductID;
  135. /*------------------------------------------------------------------------
  136. Set this packet's destination address. If no address is specified, use
  137. a Broadcast address (which IPXAddressClass's default constructor creates).
  138. ------------------------------------------------------------------------*/
  139. if (address != NULL) {
  140. dest_addr = (*address);
  141. }
  142. /*------------------------------------------------------------------------
  143. Copy the application's data
  144. ------------------------------------------------------------------------*/
  145. memcpy(PacketBuf + sizeof(GlobalHeaderType), buf, buflen);
  146. /*------------------------------------------------------------------------
  147. Queue it, along with the destination address
  148. ------------------------------------------------------------------------*/
  149. return(Queue->Queue_Send(PacketBuf,buflen + sizeof(GlobalHeaderType),
  150. &dest_addr, sizeof (IPXAddressClass)));
  151. } /* end of Send_Packet */
  152. /***************************************************************************
  153. * IPXGlobalConnClass::Receive_Packet -- adds packet to the receive queue *
  154. * *
  155. * INPUT: *
  156. * buf buffer to process (already includes GlobalHeaderType) *
  157. * buflen length of buffer to process *
  158. * address the address of the sender (the IPX Manager class must *
  159. * extract this from the IPX Header of the received packet.) *
  160. * *
  161. * OUTPUT: *
  162. * 1 = OK, 0 = error *
  163. * *
  164. * WARNINGS: *
  165. * none. *
  166. * *
  167. * HISTORY: *
  168. * 12/20/1994 BR : Created. *
  169. *=========================================================================*/
  170. int IPXGlobalConnClass::Receive_Packet (void * buf, int buflen,
  171. IPXAddressClass *address)
  172. {
  173. GlobalHeaderType *packet; // ptr to this packet
  174. SendQueueType *send_entry; // ptr to send entry header
  175. GlobalHeaderType *entry_data; // ptr to queue entry data
  176. GlobalHeaderType ackpacket; // ACK packet to send
  177. int i;
  178. int resend;
  179. /*------------------------------------------------------------------------
  180. Check the magic #
  181. ------------------------------------------------------------------------*/
  182. packet = (GlobalHeaderType *)buf;
  183. if (packet->Header.MagicNumber!=MagicNum) {
  184. return(0);
  185. }
  186. /*------------------------------------------------------------------------
  187. Process the packet based on its Code
  188. ------------------------------------------------------------------------*/
  189. switch (packet->Header.Code) {
  190. //.....................................................................
  191. // DATA_ACK: Check for a resend by comparing the source address &
  192. // ID of this packet with our last 4 received packets.
  193. // Send an ACK for the packet, regardless of whether it's a resend
  194. // or not.
  195. //.....................................................................
  196. case PACKET_DATA_ACK:
  197. {
  198. //..................................................................
  199. // Check for a resend
  200. //..................................................................
  201. resend = 0;
  202. for (i = 0; i < 4; i++) {
  203. if ((unsigned int)i >= Queue->Receive_Total()) {
  204. break;
  205. }
  206. if ((*address)==LastAddress[i] &&
  207. packet->Header.PacketID==LastPacketID[i]) {
  208. resend = 1;
  209. break;
  210. }
  211. }
  212. bool send_ack = true;
  213. //..................................................................
  214. // If it's not a resend, queue it; then, record the sender's address
  215. // & the packet ID for future resend detection.
  216. //..................................................................
  217. if (!resend) {
  218. if (Queue->Queue_Receive (buf, buflen, address, sizeof(IPXAddressClass))) {
  219. LastAddress[LastRXIndex] = (*address);
  220. LastPacketID[LastRXIndex] = packet->Header.PacketID;
  221. LastRXIndex++;
  222. if (LastRXIndex >= 4) {
  223. LastRXIndex = 0;
  224. }
  225. }else{
  226. //..................................................................
  227. // Don't send an ack if we didn't have room to store the packet.
  228. //..................................................................
  229. send_ack = false;
  230. }
  231. }
  232. //..................................................................
  233. // Send an ACK for this packet
  234. //..................................................................
  235. if (send_ack) {
  236. ackpacket.Header.MagicNumber = MagicNum;
  237. ackpacket.Header.Code = PACKET_ACK;
  238. ackpacket.Header.PacketID = packet->Header.PacketID;
  239. ackpacket.ProductID = ProductID;
  240. Send ((char *)&ackpacket, sizeof(GlobalHeaderType),
  241. address, sizeof(IPXAddressClass));
  242. }
  243. break;
  244. }
  245. /*.....................................................................
  246. DATA_NOACK: Queue this message, along with the sender's address.
  247. Don't bother checking for a Re-Send, since the other system will only
  248. send this packet once.
  249. .....................................................................*/
  250. case PACKET_DATA_NOACK:
  251. Queue->Queue_Receive (buf, buflen, address, sizeof(IPXAddressClass));
  252. break;
  253. /*.....................................................................
  254. ACK: If this ACK is for any of my packets, mark that packet as
  255. acknowledged, then throw this packet away. Otherwise, ignore the ACK
  256. (if we re-sent before we received the other system's first ACK, this
  257. ACK will be a leftover)
  258. .....................................................................*/
  259. case PACKET_ACK:
  260. for (i = 0; i < Queue->Num_Send(); i++) {
  261. /*...............................................................
  262. Get queue entry ptr
  263. ...............................................................*/
  264. send_entry = Queue->Get_Send(i);
  265. /*...............................................................
  266. If ptr is valid, get ptr to its data
  267. ...............................................................*/
  268. entry_data = (GlobalHeaderType *)(send_entry->Buffer);
  269. /*...............................................................
  270. If ACK is for this entry, mark it
  271. ...............................................................*/
  272. if (packet->Header.PacketID==entry_data->Header.PacketID &&
  273. entry_data->Header.Code == PACKET_DATA_ACK) {
  274. send_entry->IsACK = 1;
  275. break;
  276. }
  277. }
  278. break;
  279. /*.....................................................................
  280. Default: ignore the packet
  281. .....................................................................*/
  282. default:
  283. break;
  284. }
  285. return(1);
  286. } /* end of Receive_Packet */
  287. /***************************************************************************
  288. * IPXGlobalConnClass::Get_Packet -- gets a packet from the receive queue *
  289. * *
  290. * INPUT: *
  291. * buf location to store buffer *
  292. * buflen filled in with length of 'buf' *
  293. * address filled in with sender's address *
  294. * product_id filled in with sender's ProductID *
  295. * *
  296. * OUTPUT: *
  297. * 1 = OK, 0 = error *
  298. * *
  299. * WARNINGS: *
  300. * none. *
  301. * *
  302. * HISTORY: *
  303. * 12/20/1994 BR : Created. *
  304. *=========================================================================*/
  305. int IPXGlobalConnClass::Get_Packet (void * buf, int *buflen,
  306. IPXAddressClass *address, unsigned short *product_id)
  307. {
  308. ReceiveQueueType *rec_entry; // ptr to receive entry header
  309. GlobalHeaderType *packet;
  310. int packetlen; // size of received packet
  311. /*------------------------------------------------------------------------
  312. Return if nothing to do
  313. ------------------------------------------------------------------------*/
  314. if (Queue->Num_Receive() == 0) {
  315. return(0);
  316. }
  317. /*------------------------------------------------------------------------
  318. Get ptr to the next available entry
  319. ------------------------------------------------------------------------*/
  320. rec_entry = Queue->Get_Receive(0);
  321. /*------------------------------------------------------------------------
  322. Read it if it's un-read
  323. ------------------------------------------------------------------------*/
  324. if (rec_entry!=NULL && rec_entry->IsRead==0) {
  325. /*.....................................................................
  326. Mark as read
  327. .....................................................................*/
  328. rec_entry->IsRead = 1;
  329. /*.....................................................................
  330. Copy data packet
  331. .....................................................................*/
  332. packet = (GlobalHeaderType *)(rec_entry->Buffer);
  333. packetlen = rec_entry->BufLen - sizeof(GlobalHeaderType);
  334. if (packetlen > 0) {
  335. memcpy(buf, rec_entry->Buffer + sizeof(GlobalHeaderType), packetlen);
  336. }
  337. (*buflen) = packetlen;
  338. (*product_id) = packet->ProductID;
  339. (*address) = (*((IPXAddressClass *)(rec_entry->ExtraBuffer)));
  340. return(1);
  341. }
  342. return(0);
  343. } /* end of Get_Packet */
  344. /***************************************************************************
  345. * IPXGlobalConnClass::Send -- sends a packet *
  346. * *
  347. * This routine gets invoked by NonSequencedConn, when it's processing *
  348. * the Send & Receive Queues. The buffer provided will already have the *
  349. * GlobalHeaderType header embedded in it. *
  350. * *
  351. * INPUT: *
  352. * buf buffer to send *
  353. * buflen length of buffer *
  354. * extrabuf extra buffer to send *
  355. * extralen length of extra buffer *
  356. * *
  357. * OUTPUT: *
  358. * 1 = OK, 0 = error *
  359. * *
  360. * WARNINGS: *
  361. * none. *
  362. * *
  363. * HISTORY: *
  364. * 12/20/1994 BR : Created. *
  365. *=========================================================================*/
  366. int IPXGlobalConnClass::Send(char *buf, int buflen, void *extrabuf, int )
  367. {
  368. IPXAddressClass *addr;
  369. int rc;
  370. /*------------------------------------------------------------------------
  371. Extract the packet's embedded IPX address
  372. ------------------------------------------------------------------------*/
  373. addr = (IPXAddressClass *)extrabuf;
  374. /*------------------------------------------------------------------------
  375. If it's a broadcast address, broadcast it
  376. ------------------------------------------------------------------------*/
  377. if (addr->Is_Broadcast()) {
  378. return(Broadcast (buf, buflen));
  379. }
  380. /*------------------------------------------------------------------------
  381. Otherwise, send it
  382. ------------------------------------------------------------------------*/
  383. else {
  384. if (IsBridge && !memcmp (addr, BridgeNet, 4)) {
  385. rc = Send_To (buf, buflen, addr, BridgeNode);
  386. }
  387. else {
  388. rc = Send_To (buf, buflen, addr, NULL);
  389. }
  390. return (rc);
  391. }
  392. } /* end of Send */
  393. /***************************************************************************
  394. * IPXGlobalConnClass::Service_Receive_Queue -- services the receive queue *
  395. * *
  396. * This routine is necessary because the regular ConnectionClass checks *
  397. * for sequential packet ID's before removing them from the receive queue; *
  398. * this class cannot do that. *
  399. * *
  400. * INPUT: *
  401. * none. *
  402. * *
  403. * OUTPUT: *
  404. * 1 = OK, 0 = error *
  405. * *
  406. * WARNINGS: *
  407. * none. *
  408. * *
  409. * HISTORY: *
  410. * 12/20/1994 BR : Created. *
  411. *=========================================================================*/
  412. int IPXGlobalConnClass::Service_Receive_Queue (void)
  413. {
  414. int i;
  415. ReceiveQueueType *rec_entry; // ptr to receive entry header
  416. //------------------------------------------------------------------------
  417. // Remove all dead packets: If a packet's been read, throw it away.
  418. //------------------------------------------------------------------------
  419. for (i = 0; i < Queue->Num_Receive(); i++) {
  420. rec_entry = Queue->Get_Receive(i);
  421. if (rec_entry->IsRead) {
  422. Queue->UnQueue_Receive(NULL,NULL,i,NULL,NULL);
  423. i--;
  424. }
  425. }
  426. return (1);
  427. } /* end of Service_Receive_Queue */
  428. /***************************************************************************
  429. * Set_Bridge -- Sets up connection to cross a bridge *
  430. * *
  431. * This routine is designed to prevent the connection from having to *
  432. * call Get_Local_Target, except the minimum number of times, since that *
  433. * routine is buggy & goes away for long periods sometimes. *
  434. * *
  435. * INPUT: *
  436. * bridge network number of the destination bridge *
  437. * *
  438. * OUTPUT: *
  439. * none *
  440. * *
  441. * WARNINGS: *
  442. * none *
  443. * *
  444. * HISTORY: *
  445. * 07/06/1995 BRR : Created. *
  446. *=========================================================================*/
  447. void IPXGlobalConnClass::Set_Bridge(NetNumType bridge)
  448. {
  449. #ifdef WINSOCK_IPX
  450. if (Configured) {
  451. bridge = bridge;
  452. IsBridge = 0;
  453. }
  454. #else //WINSOCK_IPX
  455. if (Configured) {
  456. memcpy (BridgeNet, bridge, 4);
  457. memset (BridgeNode, 0xff, 6);
  458. if (IPX_Get_Local_Target (BridgeNet, BridgeNode, Socket, BridgeNode)==0) {
  459. IsBridge = 1;
  460. }
  461. else {
  462. IsBridge = 0;
  463. }
  464. }
  465. #endif //WINSOCK_IPX
  466. } /* end of Set_Bridge */
  467. /************************** end of ipxgconn.cpp ****************************/