WSPUDP.CPP 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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/WSPUDP.cpp $*
  21. * *
  22. * $Author:: Joe_b $*
  23. * *
  24. * $Modtime:: 8/05/97 6:45p $*
  25. * *
  26. * $Revision:: 3 $*
  27. * *
  28. * *
  29. *---------------------------------------------------------------------------------------------*
  30. * *
  31. * WSProto.CPP WinsockInterfaceClass to provide an interface to Winsock protocols *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * *
  35. * Functions: *
  36. * UDPInterfaceClass::UDPInterfaceClass -- Class constructor. *
  37. * UDPInterfaceClass::Set_Broadcast_Address -- Sets the address to send broadcast packets to *
  38. * UDPInterfaceClass::Open_Socket -- Opens a socket for communications via the UDP protocol *
  39. * TMC::Message_Handler -- Message handler function for Winsock related messages *
  40. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  41. #include "function.h"
  42. #include "internet.h"
  43. #include "WSPUDP.h"
  44. #include <assert.h>
  45. #include <stdio.h>
  46. #include <svcguid.h>
  47. /***********************************************************************************************
  48. * UDPInterfaceClass::UDPInterfaceClass -- Class constructor. *
  49. * *
  50. * *
  51. * *
  52. * INPUT: Nothing *
  53. * *
  54. * OUTPUT: Nothing *
  55. * *
  56. * WARNINGS: None *
  57. * *
  58. * HISTORY: *
  59. * 8/5/97 12:11PM ST : Created *
  60. *=============================================================================================*/
  61. UDPInterfaceClass::UDPInterfaceClass (void) : WinsockInterfaceClass()
  62. {}
  63. /***********************************************************************************************
  64. * UDPIC::~UDPInterfaceClass -- UDPInterface class destructor *
  65. * *
  66. * *
  67. * *
  68. * INPUT: Nothing *
  69. * *
  70. * OUTPUT: Nothing *
  71. * *
  72. * WARNINGS: None *
  73. * *
  74. * HISTORY: *
  75. * 10/9/97 12:17PM ST : Created *
  76. *=============================================================================================*/
  77. UDPInterfaceClass::~UDPInterfaceClass (void)
  78. {
  79. while ( BroadcastAddresses.Count() ) {
  80. delete BroadcastAddresses[0];
  81. BroadcastAddresses.Delete(0);
  82. }
  83. while ( LocalAddresses.Count() ) {
  84. delete LocalAddresses[0];
  85. LocalAddresses.Delete(0);
  86. }
  87. Close();
  88. }
  89. /***********************************************************************************************
  90. * UDPInterfaceClass::Set_Broadcast_Address -- Sets the address to send broadcast packets to *
  91. * *
  92. * *
  93. * *
  94. * INPUT: ptr to address in decimal dot format. i.e. xxx.xxx.xxx.xxx *
  95. * *
  96. * OUTPUT: Nothing *
  97. * *
  98. * WARNINGS: None *
  99. * *
  100. * HISTORY: *
  101. * 8/5/97 12:12PM ST : Created *
  102. *=============================================================================================*/
  103. void UDPInterfaceClass::Set_Broadcast_Address (void *address)
  104. {
  105. char* ip_addr = (char*) address;
  106. assert ( strlen (ip_addr) <= strlen ( "xxx.xxx.xxx.xxx" ) );
  107. unsigned char *baddr = new unsigned char[4];
  108. sscanf ( ip_addr, "%hhu.%hhu.%hhu.%hhu", &baddr[0], &baddr[1], &baddr[2], &baddr[3] );
  109. BroadcastAddresses.Add (baddr);
  110. }
  111. /***********************************************************************************************
  112. * UDPInterfaceClass::Open_Socket -- Opens a socket for communications via the UDP protocol *
  113. * *
  114. * *
  115. * *
  116. * INPUT: Socket number to use. Not required for this protocol. *
  117. * *
  118. * OUTPUT: True if socket was opened OK *
  119. * *
  120. * WARNINGS: None *
  121. * *
  122. * HISTORY: *
  123. * 8/5/97 12:13PM ST : Created *
  124. *=============================================================================================*/
  125. bool UDPInterfaceClass::Open_Socket ( SOCKET )
  126. {
  127. LINGER ling;
  128. struct sockaddr_in addr;
  129. /*
  130. ** If Winsock is not initialised then do it now.
  131. */
  132. if ( !WinsockInitialised ) {
  133. if ( !Init()) return ( false );;
  134. }
  135. /*
  136. ** Create our UDP socket
  137. */
  138. Socket = socket(AF_INET, SOCK_DGRAM, 0);
  139. if (Socket == INVALID_SOCKET) {
  140. return (false);
  141. }
  142. /*
  143. ** Bind our UDP socket to our UDP port number
  144. */
  145. addr.sin_family = AF_INET;
  146. addr.sin_port = (unsigned short) htons ( (unsigned short) PlanetWestwoodPortNumber);
  147. addr.sin_addr.s_addr = htonl (INADDR_ANY);
  148. if ( bind (Socket, (LPSOCKADDR)&addr, sizeof(addr) ) == SOCKET_ERROR) {
  149. Close_Socket ();
  150. return (false);
  151. }
  152. /*
  153. ** Use gethostbyname to find the name of the local host. We will need this to look up
  154. ** the local ip address.
  155. */
  156. char hostname[128];
  157. gethostname(hostname, 128);
  158. WWDebugString (hostname);
  159. struct hostent *host_info = gethostbyname ( hostname );
  160. /*
  161. ** Clear out any old local addresses from the local address list.
  162. */
  163. while ( LocalAddresses.Count() ) {
  164. delete LocalAddresses[0];
  165. LocalAddresses.Delete(0);
  166. }
  167. /*
  168. ** Add all local IP addresses to the list. This list will be used to discard any packets that
  169. ** we send to ourselves.
  170. */
  171. unsigned long **addresses = (unsigned long**) (host_info->h_addr_list);
  172. for ( ;; ) {
  173. if ( !*addresses ) break;
  174. unsigned long address = **addresses++;
  175. //address = ntohl (address);
  176. char temp[128];
  177. sprintf (temp, "RA95: Found local address: %d.%d.%d.%d\n", address & 0xff, (address & 0xff00) >> 8, (address & 0xff0000) >> 16, (address & 0xff000000) >> 24);
  178. OutputDebugString (temp);
  179. unsigned char *a = new unsigned char [4];
  180. * ((unsigned long*) a) = address;
  181. LocalAddresses.Add (a);
  182. }
  183. /*
  184. ** Set options for the UDP socket
  185. */
  186. ling.l_onoff = 0; // linger off
  187. ling.l_linger = 0; // timeout in seconds (ie close now)
  188. setsockopt (Socket, SOL_SOCKET, SO_LINGER, (LPSTR)&ling, sizeof(ling));
  189. WinsockInterfaceClass::Set_Socket_Options();
  190. return (true);
  191. }
  192. /***********************************************************************************************
  193. * UDPIC::Broadcast -- Send data via the Winsock socket *
  194. * *
  195. * *
  196. * *
  197. * INPUT: ptr to buffer containing data to send *
  198. * length of data to send *
  199. * *
  200. * OUTPUT: Nothing *
  201. * *
  202. * WARNINGS: None *
  203. * *
  204. * HISTORY: *
  205. * 3/20/96 3:00PM ST : Created *
  206. *=============================================================================================*/
  207. void UDPInterfaceClass::Broadcast (void *buffer, int buffer_len)
  208. {
  209. for ( int i=0 ; i<BroadcastAddresses.Count() ; i++ ) {
  210. /*
  211. ** Create a temporary holding area for the packet.
  212. */
  213. WinsockBufferType *packet = new WinsockBufferType;
  214. /*
  215. ** Copy the packet into the holding buffer.
  216. */
  217. memcpy ( packet->Buffer, buffer, buffer_len );
  218. packet->BufferLen = buffer_len;
  219. /*
  220. ** Indicate that this packet should be broadcast.
  221. */
  222. packet->IsBroadcast = true;
  223. /*
  224. ** Set up the send address for this packet.
  225. */
  226. memset (packet->Address, 0, sizeof (packet->Address));
  227. memcpy (packet->Address+4, BroadcastAddresses[i], 4);
  228. /*
  229. ** Add it to our out list.
  230. */
  231. OutBuffers.Add ( packet );
  232. /*
  233. ** Send a message to ourselves so that we can initiate a write if Winsock is idle.
  234. */
  235. SendMessage ( MainWindow, Protocol_Event_Message(), 0, (LONG)FD_WRITE );
  236. /*
  237. ** Make sure the message loop gets called.
  238. */
  239. Keyboard->Check();
  240. }
  241. }
  242. /***********************************************************************************************
  243. * TMC::Message_Handler -- Message handler function for Winsock related messages *
  244. * *
  245. * *
  246. * *
  247. * INPUT: Windows message handler stuff *
  248. * *
  249. * OUTPUT: Nothing *
  250. * *
  251. * WARNINGS: None *
  252. * *
  253. * HISTORY: *
  254. * 3/20/96 3:05PM ST : Created *
  255. *=============================================================================================*/
  256. long UDPInterfaceClass::Message_Handler(HWND, UINT message, UINT, LONG lParam)
  257. {
  258. struct sockaddr_in addr;
  259. int rc;
  260. int addr_len;
  261. WinsockBufferType *packet;
  262. /*
  263. ** We only handle UDP events.
  264. */
  265. if ( message != WM_UDPASYNCEVENT ) return (1);
  266. /*
  267. ** Handle UDP packet events
  268. */
  269. switch ( WSAGETSELECTEVENT(lParam) ) {
  270. /*
  271. ** Read event. Winsock has data it would like to give us.
  272. */
  273. case FD_READ:
  274. /*
  275. ** Clear any outstanding errors on the socket.
  276. */
  277. rc = WSAGETSELECTERROR(lParam);
  278. if (rc != 0) {
  279. Clear_Socket_Error (Socket);
  280. return (0);;
  281. }
  282. /*
  283. ** Call the Winsock recvfrom function to get the outstanding packet.
  284. */
  285. addr_len = sizeof(addr);
  286. rc = recvfrom ( Socket, (char*)ReceiveBuffer, sizeof (ReceiveBuffer), 0, (LPSOCKADDR)&addr, &addr_len);
  287. if (rc == SOCKET_ERROR) {
  288. Clear_Socket_Error (Socket);
  289. return (0);;
  290. }
  291. /*
  292. ** rc is the number of bytes received from Winsock
  293. */
  294. if ( rc ) {
  295. /*
  296. ** Make sure this packet didn't come from us. If it did then throw it away.
  297. */
  298. for ( int i=0 ; i<LocalAddresses.Count() ; i++ ) {
  299. if ( ! memcmp (LocalAddresses[i], &addr.sin_addr.s_addr, 4) ) return (0);
  300. }
  301. /*
  302. ** Create a new buffer and store this packet in it.
  303. */
  304. packet = new WinsockBufferType;
  305. packet->BufferLen = rc;
  306. memcpy ( packet->Buffer, ReceiveBuffer, rc );
  307. memset ( packet->Address, 0, sizeof (packet->Address) );
  308. memcpy ( packet->Address+4, &addr.sin_addr.s_addr, 4 );
  309. InBuffers.Add (packet);
  310. }
  311. return (0);
  312. /*
  313. ** Write event. We send ourselves this event when we have more data to send. This
  314. ** event will also occur automatically when a packet has finished being sent.
  315. */
  316. case FD_WRITE:
  317. /*
  318. ** Clear any outstanding erros on the socket.
  319. */
  320. rc = WSAGETSELECTERROR(lParam);
  321. if (rc != 0) {
  322. Clear_Socket_Error (Socket);
  323. return (0);;
  324. }
  325. /*
  326. ** If there are no packets waiting to be sent then bail.
  327. */
  328. if ( OutBuffers.Count() == 0 ) return (0);
  329. int packetnum = 0;
  330. /*
  331. ** Get a pointer to the packet.
  332. */
  333. packet = OutBuffers [ packetnum ];
  334. /*
  335. ** Set up the address structure of the outgoing packet
  336. */
  337. addr.sin_family = AF_INET;
  338. addr.sin_port = (unsigned short) htons ((unsigned short)PlanetWestwoodPortNumber);
  339. memcpy (&addr.sin_addr.s_addr, packet->Address+4, 4);
  340. /*
  341. ** Send it.
  342. ** If we get a WSAWOULDBLOCK error it means that Winsock is unable to accept the packet
  343. ** at this time. In this case, we clear the socket error and just exit. Winsock will
  344. ** send us another WRITE message when it is ready to receive more data.
  345. */
  346. rc = sendto ( Socket, (const char*) packet->Buffer, packet->BufferLen, 0, (LPSOCKADDR)&addr, sizeof (addr) );
  347. if (rc == SOCKET_ERROR){
  348. if (WSAGetLastError() != WSAEWOULDBLOCK) {
  349. Clear_Socket_Error (Socket);
  350. return (0);
  351. }
  352. }
  353. /*
  354. ** Delete the sent packet.
  355. */
  356. OutBuffers.Delete ( packetnum );
  357. delete packet;
  358. return(0);
  359. }
  360. return (0);
  361. }