429 lines
18 KiB
C++
429 lines
18 KiB
C++
//
|
|
// Copyright 2020 Electronic Arts Inc.
|
|
//
|
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
|
|
// software: you can redistribute it and/or modify it under the terms of
|
|
// the GNU General Public License as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
|
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
|
|
// in the hope that it will be useful, but with permitted additional restrictions
|
|
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
|
|
// distributed with this program. You should have received a copy of the
|
|
// GNU General Public License along with permitted additional restrictions
|
|
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
|
|
|
|
/***********************************************************************************************
|
|
*** 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 ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : Command & Conquer *
|
|
* *
|
|
* $Archive:: /Sun/WSPUDP.cpp $*
|
|
* *
|
|
* $Author:: Joe_b $*
|
|
* *
|
|
* $Modtime:: 8/05/97 6:45p $*
|
|
* *
|
|
* $Revision:: 3 $*
|
|
* *
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* *
|
|
* WSProto.CPP WinsockInterfaceClass to provide an interface to Winsock protocols *
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* *
|
|
* Functions: *
|
|
* UDPInterfaceClass::UDPInterfaceClass -- Class constructor. *
|
|
* UDPInterfaceClass::Set_Broadcast_Address -- Sets the address to send broadcast packets to *
|
|
* UDPInterfaceClass::Open_Socket -- Opens a socket for communications via the UDP protocol *
|
|
* TMC::Message_Handler -- Message handler function for Winsock related messages *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include "function.h"
|
|
#include "internet.h"
|
|
#include "WSPUDP.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <svcguid.h>
|
|
|
|
|
|
/***********************************************************************************************
|
|
* UDPInterfaceClass::UDPInterfaceClass -- Class constructor. *
|
|
* *
|
|
* *
|
|
* *
|
|
* INPUT: Nothing *
|
|
* *
|
|
* OUTPUT: Nothing *
|
|
* *
|
|
* WARNINGS: None *
|
|
* *
|
|
* HISTORY: *
|
|
* 8/5/97 12:11PM ST : Created *
|
|
*=============================================================================================*/
|
|
UDPInterfaceClass::UDPInterfaceClass (void) : WinsockInterfaceClass()
|
|
{}
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* UDPIC::~UDPInterfaceClass -- UDPInterface class destructor *
|
|
* *
|
|
* *
|
|
* *
|
|
* INPUT: Nothing *
|
|
* *
|
|
* OUTPUT: Nothing *
|
|
* *
|
|
* WARNINGS: None *
|
|
* *
|
|
* HISTORY: *
|
|
* 10/9/97 12:17PM ST : Created *
|
|
*=============================================================================================*/
|
|
UDPInterfaceClass::~UDPInterfaceClass (void)
|
|
{
|
|
while ( BroadcastAddresses.Count() ) {
|
|
delete BroadcastAddresses[0];
|
|
BroadcastAddresses.Delete(0);
|
|
}
|
|
|
|
while ( LocalAddresses.Count() ) {
|
|
delete LocalAddresses[0];
|
|
LocalAddresses.Delete(0);
|
|
}
|
|
|
|
Close();
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* UDPInterfaceClass::Set_Broadcast_Address -- Sets the address to send broadcast packets to *
|
|
* *
|
|
* *
|
|
* *
|
|
* INPUT: ptr to address in decimal dot format. i.e. xxx.xxx.xxx.xxx *
|
|
* *
|
|
* OUTPUT: Nothing *
|
|
* *
|
|
* WARNINGS: None *
|
|
* *
|
|
* HISTORY: *
|
|
* 8/5/97 12:12PM ST : Created *
|
|
*=============================================================================================*/
|
|
void UDPInterfaceClass::Set_Broadcast_Address (void *address)
|
|
{
|
|
char* ip_addr = (char*) address;
|
|
assert ( strlen (ip_addr) <= strlen ( "xxx.xxx.xxx.xxx" ) );
|
|
|
|
unsigned char *baddr = new unsigned char[4];
|
|
|
|
sscanf ( ip_addr, "%hhu.%hhu.%hhu.%hhu", &baddr[0], &baddr[1], &baddr[2], &baddr[3] );
|
|
BroadcastAddresses.Add (baddr);
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* UDPInterfaceClass::Open_Socket -- Opens a socket for communications via the UDP protocol *
|
|
* *
|
|
* *
|
|
* *
|
|
* INPUT: Socket number to use. Not required for this protocol. *
|
|
* *
|
|
* OUTPUT: True if socket was opened OK *
|
|
* *
|
|
* WARNINGS: None *
|
|
* *
|
|
* HISTORY: *
|
|
* 8/5/97 12:13PM ST : Created *
|
|
*=============================================================================================*/
|
|
bool UDPInterfaceClass::Open_Socket ( SOCKET )
|
|
{
|
|
LINGER ling;
|
|
struct sockaddr_in addr;
|
|
|
|
/*
|
|
** If Winsock is not initialised then do it now.
|
|
*/
|
|
if ( !WinsockInitialised ) {
|
|
if ( !Init()) return ( false );;
|
|
}
|
|
|
|
/*
|
|
** Create our UDP socket
|
|
*/
|
|
Socket = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (Socket == INVALID_SOCKET) {
|
|
return (false);
|
|
}
|
|
|
|
/*
|
|
** Bind our UDP socket to our UDP port number
|
|
*/
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = (unsigned short) htons ( (unsigned short) PlanetWestwoodPortNumber);
|
|
addr.sin_addr.s_addr = htonl (INADDR_ANY);
|
|
|
|
if ( bind (Socket, (LPSOCKADDR)&addr, sizeof(addr) ) == SOCKET_ERROR) {
|
|
Close_Socket ();
|
|
return (false);
|
|
}
|
|
|
|
/*
|
|
** Use gethostbyname to find the name of the local host. We will need this to look up
|
|
** the local ip address.
|
|
*/
|
|
char hostname[128];
|
|
gethostname(hostname, 128);
|
|
WWDebugString (hostname);
|
|
struct hostent *host_info = gethostbyname ( hostname );
|
|
|
|
/*
|
|
** Clear out any old local addresses from the local address list.
|
|
*/
|
|
while ( LocalAddresses.Count() ) {
|
|
delete LocalAddresses[0];
|
|
LocalAddresses.Delete(0);
|
|
}
|
|
|
|
|
|
/*
|
|
** Add all local IP addresses to the list. This list will be used to discard any packets that
|
|
** we send to ourselves.
|
|
*/
|
|
unsigned long **addresses = (unsigned long**) (host_info->h_addr_list);
|
|
|
|
for ( ;; ) {
|
|
if ( !*addresses ) break;
|
|
|
|
unsigned long address = **addresses++;
|
|
//address = ntohl (address);
|
|
|
|
char temp[128];
|
|
sprintf (temp, "RA95: Found local address: %d.%d.%d.%d\n", address & 0xff, (address & 0xff00) >> 8, (address & 0xff0000) >> 16, (address & 0xff000000) >> 24);
|
|
OutputDebugString (temp);
|
|
|
|
unsigned char *a = new unsigned char [4];
|
|
* ((unsigned long*) a) = address;
|
|
LocalAddresses.Add (a);
|
|
}
|
|
|
|
/*
|
|
** Set options for the UDP socket
|
|
*/
|
|
ling.l_onoff = 0; // linger off
|
|
ling.l_linger = 0; // timeout in seconds (ie close now)
|
|
setsockopt (Socket, SOL_SOCKET, SO_LINGER, (LPSTR)&ling, sizeof(ling));
|
|
|
|
WinsockInterfaceClass::Set_Socket_Options();
|
|
|
|
return (true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* UDPIC::Broadcast -- Send data via the Winsock socket *
|
|
* *
|
|
* *
|
|
* *
|
|
* INPUT: ptr to buffer containing data to send *
|
|
* length of data to send *
|
|
* *
|
|
* OUTPUT: Nothing *
|
|
* *
|
|
* WARNINGS: None *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/20/96 3:00PM ST : Created *
|
|
*=============================================================================================*/
|
|
void UDPInterfaceClass::Broadcast (void *buffer, int buffer_len)
|
|
{
|
|
for ( int i=0 ; i<BroadcastAddresses.Count() ; i++ ) {
|
|
|
|
/*
|
|
** Create a temporary holding area for the packet.
|
|
*/
|
|
WinsockBufferType *packet = new WinsockBufferType;
|
|
|
|
/*
|
|
** Copy the packet into the holding buffer.
|
|
*/
|
|
memcpy ( packet->Buffer, buffer, buffer_len );
|
|
packet->BufferLen = buffer_len;
|
|
|
|
/*
|
|
** Indicate that this packet should be broadcast.
|
|
*/
|
|
packet->IsBroadcast = true;
|
|
|
|
/*
|
|
** Set up the send address for this packet.
|
|
*/
|
|
memset (packet->Address, 0, sizeof (packet->Address));
|
|
memcpy (packet->Address+4, BroadcastAddresses[i], 4);
|
|
|
|
/*
|
|
** Add it to our out list.
|
|
*/
|
|
OutBuffers.Add ( packet );
|
|
|
|
/*
|
|
** Send a message to ourselves so that we can initiate a write if Winsock is idle.
|
|
*/
|
|
SendMessage ( MainWindow, Protocol_Event_Message(), 0, (LONG)FD_WRITE );
|
|
|
|
/*
|
|
** Make sure the message loop gets called.
|
|
*/
|
|
Keyboard->Check();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************************************
|
|
* TMC::Message_Handler -- Message handler function for Winsock related messages *
|
|
* *
|
|
* *
|
|
* *
|
|
* INPUT: Windows message handler stuff *
|
|
* *
|
|
* OUTPUT: Nothing *
|
|
* *
|
|
* WARNINGS: None *
|
|
* *
|
|
* HISTORY: *
|
|
* 3/20/96 3:05PM ST : Created *
|
|
*=============================================================================================*/
|
|
long UDPInterfaceClass::Message_Handler(HWND, UINT message, UINT, LONG lParam)
|
|
{
|
|
struct sockaddr_in addr;
|
|
int rc;
|
|
int addr_len;
|
|
WinsockBufferType *packet;
|
|
|
|
/*
|
|
** We only handle UDP events.
|
|
*/
|
|
if ( message != WM_UDPASYNCEVENT ) return (1);
|
|
|
|
/*
|
|
** Handle UDP packet events
|
|
*/
|
|
switch ( WSAGETSELECTEVENT(lParam) ) {
|
|
|
|
/*
|
|
** Read event. Winsock has data it would like to give us.
|
|
*/
|
|
case FD_READ:
|
|
/*
|
|
** Clear any outstanding errors on the socket.
|
|
*/
|
|
rc = WSAGETSELECTERROR(lParam);
|
|
if (rc != 0) {
|
|
Clear_Socket_Error (Socket);
|
|
return (0);;
|
|
}
|
|
|
|
/*
|
|
** Call the Winsock recvfrom function to get the outstanding packet.
|
|
*/
|
|
addr_len = sizeof(addr);
|
|
rc = recvfrom ( Socket, (char*)ReceiveBuffer, sizeof (ReceiveBuffer), 0, (LPSOCKADDR)&addr, &addr_len);
|
|
if (rc == SOCKET_ERROR) {
|
|
Clear_Socket_Error (Socket);
|
|
return (0);;
|
|
}
|
|
|
|
/*
|
|
** rc is the number of bytes received from Winsock
|
|
*/
|
|
if ( rc ) {
|
|
|
|
/*
|
|
** Make sure this packet didn't come from us. If it did then throw it away.
|
|
*/
|
|
for ( int i=0 ; i<LocalAddresses.Count() ; i++ ) {
|
|
if ( ! memcmp (LocalAddresses[i], &addr.sin_addr.s_addr, 4) ) return (0);
|
|
}
|
|
|
|
/*
|
|
** Create a new buffer and store this packet in it.
|
|
*/
|
|
packet = new WinsockBufferType;
|
|
packet->BufferLen = rc;
|
|
memcpy ( packet->Buffer, ReceiveBuffer, rc );
|
|
memset ( packet->Address, 0, sizeof (packet->Address) );
|
|
memcpy ( packet->Address+4, &addr.sin_addr.s_addr, 4 );
|
|
InBuffers.Add (packet);
|
|
}
|
|
return (0);
|
|
|
|
|
|
/*
|
|
** Write event. We send ourselves this event when we have more data to send. This
|
|
** event will also occur automatically when a packet has finished being sent.
|
|
*/
|
|
case FD_WRITE:
|
|
/*
|
|
** Clear any outstanding erros on the socket.
|
|
*/
|
|
rc = WSAGETSELECTERROR(lParam);
|
|
if (rc != 0) {
|
|
Clear_Socket_Error (Socket);
|
|
return (0);;
|
|
}
|
|
|
|
/*
|
|
** If there are no packets waiting to be sent then bail.
|
|
*/
|
|
if ( OutBuffers.Count() == 0 ) return (0);
|
|
int packetnum = 0;
|
|
|
|
/*
|
|
** Get a pointer to the packet.
|
|
*/
|
|
packet = OutBuffers [ packetnum ];
|
|
|
|
/*
|
|
** Set up the address structure of the outgoing packet
|
|
*/
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = (unsigned short) htons ((unsigned short)PlanetWestwoodPortNumber);
|
|
memcpy (&addr.sin_addr.s_addr, packet->Address+4, 4);
|
|
|
|
/*
|
|
** Send it.
|
|
** If we get a WSAWOULDBLOCK error it means that Winsock is unable to accept the packet
|
|
** at this time. In this case, we clear the socket error and just exit. Winsock will
|
|
** send us another WRITE message when it is ready to receive more data.
|
|
*/
|
|
rc = sendto ( Socket, (const char*) packet->Buffer, packet->BufferLen, 0, (LPSOCKADDR)&addr, sizeof (addr) );
|
|
|
|
if (rc == SOCKET_ERROR){
|
|
if (WSAGetLastError() != WSAEWOULDBLOCK) {
|
|
Clear_Socket_Error (Socket);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Delete the sent packet.
|
|
*/
|
|
OutBuffers.Delete ( packetnum );
|
|
delete packet;
|
|
return(0);
|
|
}
|
|
|
|
return (0);
|
|
}
|