WSPIPX.CPP 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * $Archive:: /Sun/WSPIPX.cpp $*
  25. * *
  26. * $Author:: Joe_b $*
  27. * *
  28. * $Modtime:: 8/20/97 10:54a $*
  29. * *
  30. * $Revision:: 6 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * *
  35. * IPXInterfaceClass::IPXInterfaceClass -- Class constructor *
  36. * IPXInterfaceClass::Get_Network_Card_Address -- Get the ID of the installed net card *
  37. * IPXInterfaceClass::Open_Socket -- Opens an IPX socket for reading & writing *
  38. * IPXInterfaceClass::Message_Handler -- Handler for windows messages relating to IPX *
  39. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  40. #include "function.h"
  41. #include "wspipx.h"
  42. #include "ipxaddr.h"
  43. #include <assert.h>
  44. #include <stdio.h>
  45. /***********************************************************************************************
  46. * IPXInterfaceClass::IPXInterfaceClass -- Class constructor *
  47. * *
  48. * *
  49. * *
  50. * INPUT: Nothing *
  51. * *
  52. * OUTPUT: Nothing *
  53. * *
  54. * WARNINGS: None *
  55. * *
  56. * HISTORY: *
  57. * 8/4/97 11:41AM ST : Created *
  58. *=============================================================================================*/
  59. IPXInterfaceClass::IPXInterfaceClass (void) : WinsockInterfaceClass()
  60. {
  61. /*
  62. ** Set the net and node addressed to their default values.
  63. */
  64. memset ( BroadcastNet, 0xff, sizeof (BroadcastNet) );
  65. memset ( BroadcastNode, 0xff, sizeof (BroadcastNode) );
  66. memset ( MyNode, 0xff, sizeof (MyNode) );
  67. }
  68. /***********************************************************************************************
  69. * IPXInterfaceClass::Get_Network_Card_Address -- Get the ID of the installed net card *
  70. * *
  71. * *
  72. * *
  73. * INPUT: card number to retrieve ID for *
  74. * ptr to addr to return ID in *
  75. * *
  76. * OUTPUT: Nothing *
  77. * *
  78. * WARNINGS: None *
  79. * *
  80. * HISTORY: *
  81. * 8/1/97 3:04PM ST : Created *
  82. *=============================================================================================*/
  83. bool IPXInterfaceClass::Get_Network_Card_Address (int card_number, SOCKADDR_IPX *addr)
  84. {
  85. int cbOpt;
  86. int cbAddr = sizeof( SOCKADDR_IPX );
  87. SOCKET s;
  88. SOCKADDR_IPX Addr;
  89. IPX_ADDRESS_DATA IpxData;
  90. /*
  91. ** Create a temporary IPX socket.
  92. */
  93. s = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
  94. if ( s == SOCKET_ERROR ) {
  95. assert ( s != SOCKET_ERROR );
  96. return (false);
  97. }
  98. /*
  99. ** Socket must be bound prior to calling IPX_MAX_ADAPTER_NUM
  100. */
  101. memset( &Addr, 0, sizeof( Addr ));
  102. Addr.sa_family = AF_IPX;
  103. int err = bind( s, (SOCKADDR*) &Addr, cbAddr);
  104. if ( err == SOCKET_ERROR ) {
  105. assert ( err != SOCKET_ERROR );
  106. closesocket (s);
  107. return (false);
  108. }
  109. memset( &IpxData, 0, sizeof(IpxData));
  110. /*
  111. ** Specify which adapter to check.
  112. */
  113. IpxData.adapternum = card_number;
  114. cbOpt = sizeof( IpxData );
  115. /*
  116. ** Get information for the current adapter.
  117. */
  118. err = getsockopt( s, NSPROTO_IPX, IPX_ADDRESS, (char*) &IpxData, &cbOpt );
  119. if ( err == SOCKET_ERROR ) {
  120. assert ( err != SOCKET_ERROR );
  121. closesocket (s);
  122. return (false);
  123. }
  124. /*
  125. ** IpxData contains the address for the current adapter.
  126. ** The network number will be needed later for broadcasts as the net number ff,ff,ff,ff
  127. ** doesn't work under NT.
  128. **
  129. ** Note: Due to a bug in Win95s implementation of Winsock, only the netnum & nodenum
  130. ** values are correctly returned. NT returns all expected values. ST - 7/31/97 0:57AM
  131. */
  132. memcpy (addr->sa_netnum, IpxData.netnum, sizeof (addr->sa_netnum));
  133. memcpy (BroadcastNet, IpxData.netnum, sizeof (addr->sa_netnum));
  134. memcpy (addr->sa_nodenum, IpxData.nodenum, sizeof (addr->sa_nodenum));
  135. closesocket (s);
  136. return (true);
  137. }
  138. /***********************************************************************************************
  139. * IPXInterfaceClass::Open_Socket -- Opens an IPX socket for reading & writing *
  140. * *
  141. * *
  142. * *
  143. * INPUT: SOCKET number to open. This is usually VIRGIN_SOCKET *
  144. * *
  145. * OUTPUT: true if socket was opened without error *
  146. * *
  147. * WARNINGS: None *
  148. * *
  149. * HISTORY: *
  150. * 8/4/97 5:54PM ST : Created *
  151. *=============================================================================================*/
  152. bool IPXInterfaceClass::Open_Socket( SOCKET socketnum )
  153. {
  154. SOCKADDR_IPX addr;
  155. bool delay = true;
  156. int err;
  157. /*
  158. ** If Winsock is not initialised then do it now.
  159. */
  160. if ( !WinsockInitialised ) {
  161. if ( !Init()) return ( false );;
  162. }
  163. IPXSocketNumber = socketnum;
  164. /*
  165. ** Set up the addr structure for the IPX socket
  166. */
  167. addr.sa_family = AF_IPX;
  168. memset (addr.sa_netnum, 0, sizeof (addr.sa_netnum));
  169. memset (addr.sa_nodenum, -1, sizeof (addr.sa_nodenum));
  170. addr.sa_socket = htons ( socketnum );
  171. /*
  172. ** Create the socket.
  173. */
  174. Socket = socket (AF_NS, SOCK_DGRAM, NSPROTO_IPX);
  175. if (Socket == INVALID_SOCKET) {
  176. char out[128];
  177. sprintf (out, "TS: Failed to create IPX socket - error code %d.\n", GetLastError() );
  178. OutputDebugString (out);
  179. assert ( Socket != INVALID_SOCKET );
  180. closesocket(Socket);
  181. return ( false );
  182. }
  183. /*
  184. ** Get the network card address. This is needed so we can bind the socket to the net card.
  185. */
  186. if ( !Get_Network_Card_Address (0, &addr)){
  187. closesocket ( Socket );
  188. return ( false );
  189. }
  190. /*
  191. ** Bind the IPX socket to the network card.
  192. */
  193. if (bind ( Socket, (const struct sockaddr *) &addr, 16) == SOCKET_ERROR ){
  194. char out[128];
  195. sprintf (out, "TS: IPX socket bind failed with error code %d.\n", GetLastError() );
  196. OutputDebugString (out);
  197. assert ( false );
  198. closesocket(Socket);
  199. return ( false );;
  200. }
  201. /*
  202. ** Set the various options for this IPX socket
  203. */
  204. unsigned long optval = true;
  205. int packet_type = 4;
  206. /*
  207. ** The SO_BROADCAST option allows broadcasting on this socket. This shouldn't be needed
  208. ** except for the bug in the Win95 implementation of Winsock which causes broadcasts to
  209. ** fail if it isn't set.
  210. */
  211. if ( setsockopt ( Socket, SOL_SOCKET, SO_BROADCAST, (char*)&optval, sizeof(optval) ) == SOCKET_ERROR ) {
  212. char out[128];
  213. sprintf (out, "TS: Failed to set IPX socket option SO_BROADCAST - error code %d.\n", GetLastError() );
  214. OutputDebugString (out);
  215. assert ( false );
  216. }
  217. /*
  218. ** Set the value in the packet type field for outgoing packets.
  219. */
  220. err = setsockopt ( Socket, NSPROTO_IPX, IPX_PTYPE, (char*)&packet_type, sizeof(packet_type));
  221. if ( err == INVALID_SOCKET ) {
  222. char out[128];
  223. sprintf (out, "TS: Failed to set IPX protocol option IPX_PTYPE - error code %d.\n", GetLastError() );
  224. OutputDebugString (out);
  225. assert ( err != INVALID_SOCKET );
  226. }
  227. /*
  228. ** Ignore all incoming packets not of this type.
  229. */
  230. err = setsockopt ( Socket, NSPROTO_IPX, IPX_FILTERPTYPE, (char*)&packet_type, sizeof(packet_type));
  231. if ( err == INVALID_SOCKET ) {
  232. char out[128];
  233. sprintf (out, "TS: Failed to set IPX protocol option IPX_FILTERTYPE - error code %d.\n", GetLastError() );
  234. OutputDebugString (out);
  235. assert ( err != INVALID_SOCKET );
  236. }
  237. /*
  238. ** Set the the base class socket options for buffer sizes.
  239. */
  240. WinsockInterfaceClass::Set_Socket_Options();
  241. /*
  242. ** Woohoo!
  243. */
  244. return ( true );
  245. }
  246. /***********************************************************************************************
  247. * IPXInterfaceClass::Message_Handler -- Handler for windows messages relating to IPX *
  248. * *
  249. * *
  250. * *
  251. * INPUT: Usual windoze message handler stuff *
  252. * *
  253. * OUTPUT: 0 if message was handled *
  254. * *
  255. * WARNINGS: None *
  256. * *
  257. * HISTORY: *
  258. * 8/4/97 5:55PM ST : Created *
  259. *=============================================================================================*/
  260. long IPXInterfaceClass::Message_Handler(HWND , UINT message, UINT , LONG lParam)
  261. {
  262. int addr_len; // Length of address structure
  263. int rc; // Result code
  264. SOCKADDR_IPX addr; // Winsock IPX addressing structure
  265. WinsockBufferType *packet; // Ptr to packet
  266. NetNumType netnum;
  267. NetNodeType nodenum;
  268. /*
  269. ** We only handle IPX events.
  270. */
  271. if ( message != WM_IPXASYNCEVENT ) return ( 1 );
  272. switch ( WSAGETSELECTEVENT(lParam) ) {
  273. /*
  274. ** Read event. Winsock has data it would like to give us.
  275. */
  276. case FD_READ:
  277. /*
  278. ** Clear any outstanding errors on the socket.
  279. */
  280. rc = WSAGETSELECTERROR(lParam);
  281. if (rc != 0) {
  282. Clear_Socket_Error (Socket);
  283. return(0);
  284. }
  285. /*
  286. ** Call the Winsock recvfrom function to get the outstanding packet.
  287. */
  288. addr_len = sizeof(addr);
  289. rc = recvfrom ( Socket, (char*) ReceiveBuffer, sizeof (ReceiveBuffer), 0, (LPSOCKADDR)&addr, &addr_len );
  290. if (rc == SOCKET_ERROR) {
  291. if (WSAGetLastError() != WSAEWOULDBLOCK) {
  292. Clear_Socket_Error (Socket);
  293. }
  294. return(0);
  295. }
  296. /*
  297. ** rc is the number of bytes received from Winsock
  298. */
  299. if ( rc ) {
  300. /*
  301. ** Make a copy of the address that this packet came from.
  302. */
  303. memcpy ( netnum, addr.sa_netnum, sizeof (netnum) );
  304. memcpy ( nodenum, addr.sa_nodenum, sizeof (nodenum) );
  305. /*
  306. ** If this packet was from me then ignore it.
  307. */
  308. if ( !memcmp (netnum, BroadcastNet, sizeof (BroadcastNet)) && !memcmp(nodenum, MyNode, sizeof (MyNode)) ) {
  309. return (0);
  310. }
  311. /*
  312. ** Create a new buffer and store this packet in it.
  313. */
  314. packet = new WinsockBufferType;
  315. packet->BufferLen = rc;
  316. memcpy ( packet->Buffer, ReceiveBuffer, rc );
  317. IPXAddressClass *paddress = (IPXAddressClass*) (&packet->Address[0]);
  318. paddress->Set_Address ( netnum, nodenum );
  319. InBuffers.Add ( packet );
  320. }
  321. return(0);
  322. /*
  323. ** Write event. We send ourselves this event when we have more data to send. This
  324. ** event will also occur automatically when a packet has finished being sent.
  325. */
  326. case FD_WRITE:
  327. /*
  328. ** Clear any outstanding erros on the socket.
  329. */
  330. rc = WSAGETSELECTERROR(lParam);
  331. if (rc != 0) {
  332. Clear_Socket_Error ( Socket );
  333. return(0);
  334. }
  335. /*
  336. ** If there are no packets waiting to be sent then bail.
  337. */
  338. while ( OutBuffers.Count() != 0 ) {
  339. int packetnum = 0;
  340. /*
  341. ** Get a pointer to the packet.
  342. */
  343. packet = OutBuffers [ packetnum ];
  344. /*
  345. ** Set up the address structure of the outgoing packet
  346. */
  347. addr.sa_family = AF_IPX;
  348. addr.sa_socket = htons ( IPXSocketNumber );
  349. /*
  350. ** Set up the address as either a broadcast address or the given address
  351. */
  352. if ( packet->IsBroadcast ) {
  353. memcpy ( addr.sa_netnum, BroadcastNet, sizeof (BroadcastNet) );
  354. memcpy ( addr.sa_nodenum, BroadcastNode, sizeof (BroadcastNode) );
  355. }else{
  356. IPXAddressClass *paddress = (IPXAddressClass*) (&packet->Address[0]);
  357. paddress->Get_Address ( netnum, nodenum );
  358. memcpy ( addr.sa_netnum, netnum, sizeof (netnum) );
  359. memcpy ( addr.sa_nodenum, nodenum, sizeof (nodenum) );
  360. }
  361. /*
  362. ** Send it.
  363. ** If we get a WSAWOULDBLOCK error it means that Winsock is unable to accept the packet
  364. ** at this time. In this case, we clear the socket error and just exit. Winsock will
  365. ** send us another WRITE message when it is ready to receive more data.
  366. */
  367. rc = sendto ( Socket, (const char*) packet->Buffer, packet->BufferLen, 0, (LPSOCKADDR)&addr, sizeof (addr) );
  368. if (rc == SOCKET_ERROR){
  369. if (WSAGetLastError() != WSAEWOULDBLOCK) {
  370. Clear_Socket_Error (Socket);
  371. break;
  372. }
  373. }
  374. /*
  375. ** Delete the sent packet.
  376. */
  377. OutBuffers.Delete ( packetnum );
  378. delete packet;
  379. }
  380. return(0);
  381. }
  382. return (0);
  383. }