IPXGCONN.CPP 24 KB

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