CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

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 }