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