WSPIPX.CPP 17 KB

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