WSPUDP.CPP 18 KB

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