Files
2026-03-02 22:04:18 +03:00

817 lines
24 KiB
C++
Executable File

#include "UDPForwarder.h"
#if _RAKNET_SUPPORT_UDPForwarder==1
#include "GetTime.h"
#include "MTUSize.h"
#include "SocketLayer.h"
#include "WSAStartupSingleton.h"
#include "RakSleep.h"
#include "DS_OrderedList.h"
#include "LinuxStrings.h"
#include "SocketDefines.h"
#include "VitaIncludes.h"
using namespace RakNet;
static const unsigned short DEFAULT_MAX_FORWARD_ENTRIES=64;
#ifdef UDP_FORWARDER_EXECUTE_THREADED
namespace RakNet
{
RAK_THREAD_DECLARATION(UpdateUDPForwarder);
}
#endif
int UDPForwarder::SrcAndDestForwardEntryComp( const UDPForwarder::SrcAndDest &inputKey, UDPForwarder::ForwardEntry * const &cls )
{
if (inputKey.source < cls->srcAndDest.source)
return -1;
if (inputKey.source > cls->srcAndDest.source)
return 1;
if (inputKey.dest < cls->srcAndDest.dest)
return -1;
if (inputKey.dest > cls->srcAndDest.dest)
return 1;
return 0;
}
/*
bool operator<( const DataStructures::MLKeyRef<UDPForwarder::SrcAndDest> &inputKey, const UDPForwarder::ForwardEntry *cls )
{
return inputKey.Get().source < cls->srcAndDest.source ||
(inputKey.Get().source == cls->srcAndDest.source && inputKey.Get().dest < cls->srcAndDest.dest);
}
bool operator>( const DataStructures::MLKeyRef<UDPForwarder::SrcAndDest> &inputKey, const UDPForwarder::ForwardEntry *cls )
{
return inputKey.Get().source > cls->srcAndDest.source ||
(inputKey.Get().source == cls->srcAndDest.source && inputKey.Get().dest > cls->srcAndDest.dest);
}
bool operator==( const DataStructures::MLKeyRef<UDPForwarder::SrcAndDest> &inputKey, const UDPForwarder::ForwardEntry *cls )
{
return inputKey.Get().source == cls->srcAndDest.source && inputKey.Get().dest == cls->srcAndDest.dest;
}
*/
UDPForwarder::ForwardEntry::ForwardEntry() {socket=INVALID_SOCKET; timeLastDatagramForwarded=RakNet::GetTimeMS(); updatedSourcePort=false; updatedDestPort=false;}
UDPForwarder::ForwardEntry::~ForwardEntry() {
if (socket!=INVALID_SOCKET)
closesocket__(socket);
}
UDPForwarder::UDPForwarder()
{
#ifdef _WIN32
WSAStartupSingleton::AddRef();
#endif
maxForwardEntries=DEFAULT_MAX_FORWARD_ENTRIES;
isRunning=false;
threadRunning=false;
}
UDPForwarder::~UDPForwarder()
{
Shutdown();
#ifdef _WIN32
WSAStartupSingleton::Deref();
#endif
}
void UDPForwarder::Startup(void)
{
if (isRunning==true)
return;
isRunning=true;
threadRunning=false;
#ifdef UDP_FORWARDER_EXECUTE_THREADED
int errorCode;
errorCode = RakNet::RakThread::Create(UpdateUDPForwarder, this);
if ( errorCode != 0 )
{
RakAssert(0);
return;
}
while (threadRunning==false)
RakSleep(30);
#endif
}
void UDPForwarder::Shutdown(void)
{
if (isRunning==false)
return;
isRunning=false;
#ifdef UDP_FORWARDER_EXECUTE_THREADED
while (threadRunning==true)
RakSleep(30);
#endif
unsigned int j;
for (j=0; j < forwardList.Size(); j++)
RakNet::OP_DELETE(forwardList[j],_FILE_AND_LINE_);
forwardList.Clear(false, _FILE_AND_LINE_);
}
void UDPForwarder::Update(void)
{
#ifndef UDP_FORWARDER_EXECUTE_THREADED
#if RAKNET_SUPPORT_IPV6!=1
UpdateThreaded_Old();
#else
UpdateThreaded();
#endif
#endif
}
void UDPForwarder::UpdateThreaded_Old(void)
{
fd_set readFD;
//fd_set exceptionFD;
FD_ZERO(&readFD);
// FD_ZERO(&exceptionFD);
int selectResult;
timeval tv;
tv.tv_sec=0;
tv.tv_usec=0;
RakNet::TimeMS curTime = RakNet::GetTimeMS();
SOCKET largestDescriptor=0;
unsigned int i;
// Remove unused entries
i=0;
while (i < forwardList.Size())
{
if (curTime > forwardList[i]->timeLastDatagramForwarded && // Account for timestamp wrap
curTime > forwardList[i]->timeLastDatagramForwarded+forwardList[i]->timeoutOnNoDataMS)
{
RakNet::OP_DELETE(forwardList[i],_FILE_AND_LINE_);
forwardList.RemoveAtIndex(i);
}
else
i++;
}
if (forwardList.Size()==0)
return;
for (i=0; i < forwardList.Size(); i++)
{
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
FD_SET(forwardList[i]->socket, &readFD);
// FD_SET(forwardList[i]->readSocket, &exceptionFD);
if (forwardList[i]->socket > largestDescriptor)
largestDescriptor = forwardList[i]->socket;
}
selectResult=(int) select__((int) largestDescriptor+1, &readFD, 0, 0, &tv);
char data[ MAXIMUM_MTU_SIZE ];
sockaddr_in sa;
socklen_t len2;
if (selectResult > 0)
{
DataStructures::Queue<ForwardEntry*> entriesToRead;
ForwardEntry *forwardEntry;
for (i=0; i < forwardList.Size(); i++)
{
forwardEntry = forwardList[i];
// I do this because I'm updating the forwardList, and don't want to lose FD_ISSET as the list is no longer in order
if (FD_ISSET(forwardEntry->socket, &readFD))
entriesToRead.Push(forwardEntry,_FILE_AND_LINE_);
}
while (entriesToRead.IsEmpty()==false)
{
forwardEntry=entriesToRead.Pop();
const int flag=0;
int receivedDataLen, len=0;
unsigned short portnum=0;
len2 = sizeof( sa );
sa.sin_family = AF_INET;
receivedDataLen = recvfrom__( forwardEntry->socket, data, MAXIMUM_MTU_SIZE, flag, ( sockaddr* ) & sa, ( socklen_t* ) & len2 );
if (receivedDataLen<0)
{
#if defined(_WIN32) && defined(_DEBUG)
DWORD dwIOError = WSAGetLastError();
if (dwIOError!=WSAECONNRESET && dwIOError!=WSAEINTR && dwIOError!=WSAETIMEDOUT)
{
LPVOID messageBuffer;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwIOError, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
( LPTSTR ) & messageBuffer, 0, NULL );
// something has gone wrong here...
RAKNET_DEBUG_PRINTF( "recvfrom failed:Error code - %d\n%s", dwIOError, messageBuffer );
//Free the buffer.
LocalFree( messageBuffer );
}
#endif
continue;
}
portnum = ntohs( sa.sin_port );
if (forwardEntry->srcAndDest.source.address.addr4.sin_addr.s_addr==sa.sin_addr.s_addr && forwardEntry->updatedSourcePort==false && forwardEntry->srcAndDest.dest.GetPort()!=portnum)
{
forwardEntry->updatedSourcePort=true;
if (forwardEntry->srcAndDest.source.GetPort()!=portnum)
{
unsigned int index;
SrcAndDest srcAndDest(forwardEntry->srcAndDest.dest, forwardEntry->srcAndDest.source);
bool objectExists;
index = forwardList.GetIndexFromKey(srcAndDest, &objectExists);
if (objectExists)
{
forwardList.RemoveAtIndex(index);
}
forwardEntry->srcAndDest.source.SetPort(portnum);
forwardList.Insert(forwardEntry->srcAndDest,forwardEntry,true,_FILE_AND_LINE_);
}
}
if (forwardEntry->srcAndDest.source.address.addr4.sin_addr.s_addr==sa.sin_addr.s_addr && forwardEntry->srcAndDest.source.GetPort()==portnum)
{
// Forward to dest
len=0;
sockaddr_in saOut;
saOut.sin_port = forwardEntry->srcAndDest.dest.GetPortNetworkOrder(); // User port
saOut.sin_addr.s_addr = forwardEntry->srcAndDest.dest.address.addr4.sin_addr.s_addr;
saOut.sin_family = AF_INET;
do
{
len = sendto__( forwardEntry->socket, data, receivedDataLen, 0, ( const sockaddr* ) & saOut, sizeof( saOut ) );
}
while ( len == 0 );
// printf("1. Forwarding after %i ms\n", curTime-forwardEntry->timeLastDatagramForwarded);
forwardEntry->timeLastDatagramForwarded=curTime;
}
if (forwardEntry->srcAndDest.dest.address.addr4.sin_addr.s_addr==sa.sin_addr.s_addr && forwardEntry->updatedDestPort==false && forwardEntry->srcAndDest.source.GetPort()!=portnum)
{
forwardEntry->updatedDestPort=true;
if (forwardEntry->srcAndDest.dest.GetPort()!=portnum)
{
unsigned int index;
SrcAndDest srcAndDest(forwardEntry->srcAndDest.source, forwardEntry->srcAndDest.dest);
bool objectExists;
index = forwardList.GetIndexFromKey(srcAndDest, &objectExists);
if (objectExists)
{
forwardList.RemoveAtIndex(index);
}
forwardEntry->srcAndDest.dest.SetPort(portnum);
forwardList.Insert(forwardEntry->srcAndDest,forwardEntry,true,_FILE_AND_LINE_);
}
}
if (forwardEntry->srcAndDest.dest.address.addr4.sin_addr.s_addr==sa.sin_addr.s_addr && forwardEntry->srcAndDest.dest.GetPort()==portnum)
{
// Forward to source
len=0;
sockaddr_in saOut;
saOut.sin_port = forwardEntry->srcAndDest.source.GetPortNetworkOrder(); // User port
saOut.sin_addr.s_addr = forwardEntry->srcAndDest.source.address.addr4.sin_addr.s_addr;
saOut.sin_family = AF_INET;
do
{
len = sendto__( forwardEntry->socket, data, receivedDataLen, 0, ( const sockaddr* ) & saOut, sizeof( saOut ) );
}
while ( len == 0 );
// printf("2. Forwarding after %i ms\n", curTime-forwardEntry->timeLastDatagramForwarded);
forwardEntry->timeLastDatagramForwarded=curTime;
}
}
}
}
#if RAKNET_SUPPORT_IPV6==1
void UDPForwarder::UpdateThreaded(void)
{
fd_set readFD;
//fd_set exceptionFD;
FD_ZERO(&readFD);
// FD_ZERO(&exceptionFD);
timeval tv;
int selectResult;
tv.tv_sec=0;
tv.tv_usec=0;
RakNet::TimeMS curTime = RakNet::GetTimeMS();
SOCKET largestDescriptor=0;
unsigned int i;
// Remove unused entries
i=0;
while (i < forwardList.Size())
{
if (curTime > forwardList[i]->timeLastDatagramForwarded && // Account for timestamp wrap
curTime > forwardList[i]->timeLastDatagramForwarded+forwardList[i]->timeoutOnNoDataMS)
{
RakNet::OP_DELETE(forwardList[i],_FILE_AND_LINE_);
forwardList.RemoveAtIndex(i);
}
else
i++;
}
if (forwardList.Size()==0)
return;
for (i=0; i < forwardList.Size(); i++)
{
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
FD_SET(forwardList[i]->socket, &readFD);
// FD_SET(forwardList[i]->readSocket, &exceptionFD);
if (forwardList[i]->socket > largestDescriptor)
largestDescriptor = forwardList[i]->socket;
}
selectResult=(int) select__((int) largestDescriptor+1, &readFD, 0, 0, &tv);
char data[ MAXIMUM_MTU_SIZE ];
sockaddr_storage their_addr;
sockaddr* sockAddrPtr;
socklen_t sockLen;
socklen_t* socketlenPtr=(socklen_t*) &sockLen;
sockaddr_in *sockAddrIn;
sockaddr_in6 *sockAddrIn6;
SystemAddress receivedAddr;
sockLen=sizeof(their_addr);
sockAddrPtr=(sockaddr*) &their_addr;
if (selectResult > 0)
{
DataStructures::Queue<ForwardEntry*> entriesToRead;
ForwardEntry *forwardEntry;
for (i=0; i < forwardList.Size(); i++)
{
forwardEntry = forwardList[i];
// I do this because I'm updating the forwardList, and don't want to lose FD_ISSET as the list is no longer in order
if (FD_ISSET(forwardEntry->socket, &readFD))
entriesToRead.Push(forwardEntry,_FILE_AND_LINE_);
}
while (entriesToRead.IsEmpty()==false)
{
forwardEntry=entriesToRead.Pop();
const int flag=0;
int receivedDataLen, len=0;
receivedDataLen = recvfrom__( forwardEntry->socket, data, MAXIMUM_MTU_SIZE, flag, sockAddrPtr, socketlenPtr );
if (receivedDataLen<0)
{
#if defined(_WIN32) && defined(_DEBUG)
DWORD dwIOError = WSAGetLastError();
if (dwIOError!=WSAECONNRESET && dwIOError!=WSAEINTR && dwIOError!=WSAETIMEDOUT)
{
LPVOID messageBuffer;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwIOError, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
( LPTSTR ) & messageBuffer, 0, NULL );
// something has gone wrong here...
RAKNET_DEBUG_PRINTF( "recvfrom failed:Error code - %d\n%s", dwIOError, messageBuffer );
//Free the buffer.
LocalFree( messageBuffer );
}
#endif
continue;
}
if (their_addr.ss_family==AF_INET)
{
sockAddrIn=(sockaddr_in *)&their_addr;
sockAddrIn6=0;
memcpy(&receivedAddr.address.addr4,sockAddrIn,sizeof(sockaddr_in));
// receivedAddr.address.addr4.sin_port=ntohs( sockAddrIn->sin_port );
}
else
{
sockAddrIn=0;
sockAddrIn6=(sockaddr_in6 *)&their_addr;
memcpy(&receivedAddr.address.addr6,sockAddrIn6,sizeof(sockaddr_in6));
// receivedAddr.address.addr6.sin6_port=ntohs( sockAddrIn6->sin6_port );
}
if (forwardEntry->srcAndDest.source.EqualsExcludingPort(receivedAddr) && forwardEntry->updatedSourcePort==false && forwardEntry->srcAndDest.dest.GetPort()!=receivedAddr.GetPort())
{
forwardEntry->updatedSourcePort=true;
if (forwardEntry->srcAndDest.source.GetPort()!=receivedAddr.GetPort())
{
unsigned int index;
SrcAndDest srcAndDest(forwardEntry->srcAndDest.dest, forwardEntry->srcAndDest.source);
bool objectExists;
index=forwardList.GetIndexFromKey(srcAndDest, &objectExists);
forwardList.RemoveAtIndex(index);
forwardEntry->srcAndDest.source.SetPort(receivedAddr.GetPort());
forwardList.Push(forwardEntry,forwardEntry->srcAndDest,_FILE_AND_LINE_);
}
}
if (forwardEntry->srcAndDest.source.EqualsExcludingPort(receivedAddr) && forwardEntry->srcAndDest.source.GetPort()==receivedAddr.GetPort())
{
// Forward to dest
len=0;
if (forwardEntry->srcAndDest.dest.address.addr4.sin_family==AF_INET)
{
do
{
len = sendto__( forwardEntry->socket, data, receivedDataLen, 0, ( const sockaddr* ) & forwardEntry->srcAndDest.dest.address.addr4, sizeof( sockaddr_in ) );
}
while ( len == 0 );
}
else
{
do
{
len = sendto__( forwardEntry->socket, data, receivedDataLen, 0, ( const sockaddr* ) & forwardEntry->srcAndDest.dest.address.addr6, sizeof( sockaddr_in ) );
}
while ( len == 0 );
}
// printf("1. Forwarding after %i ms\n", curTime-forwardEntry->timeLastDatagramForwarded);
forwardEntry->timeLastDatagramForwarded=curTime;
}
if (forwardEntry->srcAndDest.dest.EqualsExcludingPort(receivedAddr) && forwardEntry->updatedDestPort==false && forwardEntry->srcAndDest.source.GetPort()!=receivedAddr.GetPort())
{
forwardEntry->updatedDestPort=true;
if (forwardEntry->srcAndDest.dest.GetPort()!=receivedAddr.GetPort())
{
unsigned int index;
SrcAndDest srcAndDest(forwardEntry->srcAndDest.source, forwardEntry->srcAndDest.dest);
index=forwardList.GetIndexOf(srcAndDest);
forwardList.RemoveAtIndex(index);
forwardEntry->srcAndDest.dest.SetPort(receivedAddr.GetPort());
forwardList.Push(forwardEntry,forwardEntry->srcAndDest,_FILE_AND_LINE_);
}
}
if (forwardEntry->srcAndDest.dest.EqualsExcludingPort(receivedAddr) && forwardEntry->srcAndDest.dest.GetPort()==receivedAddr.GetPort())
{
// Forward to source
len=0;
if (forwardEntry->srcAndDest.source.address.addr4.sin_family==AF_INET)
{
do
{
len = sendto__( forwardEntry->socket, data, receivedDataLen, 0, ( const sockaddr* ) & forwardEntry->srcAndDest.source.address.addr4, sizeof( sockaddr_in ) );
}
while ( len == 0 );
}
else
{
do
{
len = sendto__( forwardEntry->socket, data, receivedDataLen, 0, ( const sockaddr* ) & forwardEntry->srcAndDest.source.address.addr6, sizeof( sockaddr_in ) );
}
while ( len == 0 );
}
// printf("2. Forwarding after %i ms\n", curTime-forwardEntry->timeLastDatagramForwarded);
forwardEntry->timeLastDatagramForwarded=curTime;
}
}
}
}
#endif // #if RAKNET_SUPPORT_IPV6!=1
void UDPForwarder::SetMaxForwardEntries(unsigned short maxEntries)
{
RakAssert(maxEntries>0 && maxEntries<65535/2);
maxForwardEntries=maxEntries;
}
int UDPForwarder::GetMaxForwardEntries(void) const
{
return maxForwardEntries;
}
int UDPForwarder::GetUsedForwardEntries(void) const
{
return (int) forwardList.Size();
}
UDPForwarderResult UDPForwarder::AddForwardingEntry(SrcAndDest srcAndDest, RakNet::TimeMS timeoutOnNoDataMS, unsigned short *port, const char *forceHostAddress, short socketFamily)
{
(void) socketFamily;
unsigned int insertionIndex;
bool objectExists;
insertionIndex = forwardList.GetIndexFromKey(srcAndDest, &objectExists);
if (objectExists==false)
{
#if RAKNET_SUPPORT_IPV6!=1
int sock_opt;
sockaddr_in listenerSocketAddress;
listenerSocketAddress.sin_port = 0;
ForwardEntry *fe = RakNet::OP_NEW<UDPForwarder::ForwardEntry>(_FILE_AND_LINE_);
fe->srcAndDest=srcAndDest;
fe->timeoutOnNoDataMS=timeoutOnNoDataMS;
fe->socket = socket__( AF_INET, SOCK_DGRAM, 0 );
//printf("Made socket %i\n", fe->readSocket);
// This doubles the max throughput rate
sock_opt=1024*256;
setsockopt__(fe->socket, SOL_SOCKET, SO_RCVBUF, ( char * ) & sock_opt, sizeof ( sock_opt ) );
// Immediate hard close. Don't linger the readSocket, or recreating the readSocket quickly on Vista fails.
sock_opt=0;
setsockopt__(fe->socket, SOL_SOCKET, SO_LINGER, ( char * ) & sock_opt, sizeof ( sock_opt ) );
listenerSocketAddress.sin_family = AF_INET;
if (forceHostAddress && forceHostAddress[0])
{
listenerSocketAddress.sin_addr.s_addr = inet_addr__( forceHostAddress );
}
else
{
listenerSocketAddress.sin_addr.s_addr = INADDR_ANY;
}
int ret = bind__( fe->socket, ( struct sockaddr * ) & listenerSocketAddress, sizeof( listenerSocketAddress ) );
if (ret==-1)
{
RakNet::OP_DELETE(fe,_FILE_AND_LINE_);
return UDPFORWARDER_BIND_FAILED;
}
#else
ForwardEntry *fe = RakNet::OP_NEW<UDPForwarder::ForwardEntry>(_FILE_AND_LINE_);
fe->srcAndDest=srcAndDest;
fe->timeoutOnNoDataMS=timeoutOnNoDataMS;
fe->socket=INVALID_SOCKET;
struct addrinfo hints;
memset(&hints, 0, sizeof (addrinfo)); // make sure the struct is empty
hints.ai_family = socketFamily;
hints.ai_socktype = SOCK_DGRAM; // UDP sockets
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
struct addrinfo *servinfo=0, *aip; // will point to the results
RakAssert(forceHostAddress==0 || forceHostAddress[0]!=0);
if (_stricmp(forceHostAddress,"UNASSIGNED_SYSTEM_ADDRESS")==0)
{
getaddrinfo(0, "0", &hints, &servinfo);
}
else
{
getaddrinfo(forceHostAddress, "0", &hints, &servinfo);
}
for (aip = servinfo; aip != NULL; aip = aip->ai_next)
{
// Open socket. The address type depends on what
// getaddrinfo() gave us.
fe->socket = socket__(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
if (fe->socket != INVALID_SOCKET)
{
int ret = bind__( fe->socket, aip->ai_addr, (int) aip->ai_addrlen );
if (ret>=0)
{
break;
}
else
{
closesocket__(fe->socket);
fe->socket=INVALID_SOCKET;
}
}
}
if (fe->socket==INVALID_SOCKET)
return UDPFORWARDER_BIND_FAILED;
//printf("Made socket %i\n", fe->readSocket);
// This doubles the max throughput rate
int sock_opt;
sock_opt=1024*256;
setsockopt__(fe->socket, SOL_SOCKET, SO_RCVBUF, ( char * ) & sock_opt, sizeof ( sock_opt ) );
// Immediate hard close. Don't linger the readSocket, or recreating the readSocket quickly on Vista fails.
sock_opt=0;
setsockopt__(fe->socket, SOL_SOCKET, SO_LINGER, ( char * ) & sock_opt, sizeof ( sock_opt ) );
#endif // #if RAKNET_SUPPORT_IPV6!=1
// unsigned int oldSize = forwardList.Size();
forwardList.InsertAtIndex(fe,insertionIndex,_FILE_AND_LINE_);
// RakAssert(forwardList.GetIndexOf(fe->srcAndDest)!=(unsigned int) -1);
*port = SocketLayer::GetLocalPort ( fe->socket );
return UDPFORWARDER_SUCCESS;
}
return UDPFORWARDER_FORWARDING_ALREADY_EXISTS;
}
UDPForwarderResult UDPForwarder::StartForwarding(SystemAddress source, SystemAddress destination, RakNet::TimeMS timeoutOnNoDataMS, const char *forceHostAddress, unsigned short socketFamily,
unsigned short *forwardingPort, SOCKET *forwardingSocket)
{
// Invalid parameters?
if (timeoutOnNoDataMS == 0 || timeoutOnNoDataMS > UDP_FORWARDER_MAXIMUM_TIMEOUT || source==UNASSIGNED_SYSTEM_ADDRESS || destination==UNASSIGNED_SYSTEM_ADDRESS)
return UDPFORWARDER_INVALID_PARAMETERS;
#ifdef UDP_FORWARDER_EXECUTE_THREADED
ThreadOperation threadOperation;
threadOperation.source=source;
threadOperation.destination=destination;
threadOperation.timeoutOnNoDataMS=timeoutOnNoDataMS;
threadOperation.forceHostAddress=forceHostAddress;
threadOperation.socketFamily=socketFamily;
threadOperation.operation=ThreadOperation::TO_START_FORWARDING;
threadOperationIncomingMutex.Lock();
threadOperationIncomingQueue.Push(threadOperation, _FILE_AND_LINE_ );
threadOperationIncomingMutex.Unlock();
while (1)
{
RakSleep(0);
threadOperationOutgoingMutex.Lock();
if (threadOperationOutgoingQueue.Size()!=0)
{
threadOperation=threadOperationOutgoingQueue.Pop();
threadOperationOutgoingMutex.Unlock();
if (forwardingPort)
*forwardingPort=threadOperation.forwardingPort;
if (forwardingSocket)
*forwardingSocket=threadOperation.forwardingSocket;
return threadOperation.result;
}
threadOperationOutgoingMutex.Unlock();
}
#else
return StartForwardingThreaded(source, destination, timeoutOnNoDataMS, forceHostAddress, socketFamily, srcToDestPort, destToSourcePort, srcToDestSocket, destToSourceSocket);
#endif
}
UDPForwarderResult UDPForwarder::StartForwardingThreaded(SystemAddress source, SystemAddress destination, RakNet::TimeMS timeoutOnNoDataMS, const char *forceHostAddress, unsigned short socketFamily,
unsigned short *forwardingPort, SOCKET *forwardingSocket)
{
SrcAndDest srcAndDest(source, destination);
UDPForwarderResult result = AddForwardingEntry(srcAndDest, timeoutOnNoDataMS, forwardingPort, forceHostAddress, socketFamily);
if (result!=UDPFORWARDER_SUCCESS)
return result;
if (*forwardingSocket)
{
unsigned int idx;
bool objectExists;
idx = forwardList.GetIndexFromKey(srcAndDest, &objectExists);
RakAssert(objectExists);
*forwardingSocket=forwardList[idx]->socket;
}
return UDPFORWARDER_SUCCESS;
}
void UDPForwarder::StopForwarding(SystemAddress source, SystemAddress destination)
{
#ifdef UDP_FORWARDER_EXECUTE_THREADED
ThreadOperation threadOperation;
threadOperation.source=source;
threadOperation.destination=destination;
threadOperation.operation=ThreadOperation::TO_STOP_FORWARDING;
threadOperationIncomingMutex.Lock();
threadOperationIncomingQueue.Push(threadOperation, _FILE_AND_LINE_ );
threadOperationIncomingMutex.Unlock();
#else
StopForwardingThreaded(source, destination);
#endif
}
void UDPForwarder::StopForwardingThreaded(SystemAddress source, SystemAddress destination)
{
SrcAndDest srcAndDest(destination,source);
bool objectExists;
unsigned int idx = forwardList.GetIndexFromKey(srcAndDest, &objectExists);
if (objectExists)
{
RakNet::OP_DELETE(forwardList[idx],_FILE_AND_LINE_);
forwardList.RemoveAtIndex(idx);
}
}
namespace RakNet {
#ifdef UDP_FORWARDER_EXECUTE_THREADED
RAK_THREAD_DECLARATION(UpdateUDPForwarder)
{
UDPForwarder * udpForwarder = ( UDPForwarder * ) arguments;
udpForwarder->threadRunning=true;
UDPForwarder::ThreadOperation threadOperation;
while (udpForwarder->isRunning)
{
udpForwarder->threadOperationIncomingMutex.Lock();
while (udpForwarder->threadOperationIncomingQueue.Size())
{
threadOperation=udpForwarder->threadOperationIncomingQueue.Pop();
udpForwarder->threadOperationIncomingMutex.Unlock();
if (threadOperation.operation==UDPForwarder::ThreadOperation::TO_START_FORWARDING)
{
threadOperation.result=udpForwarder->StartForwardingThreaded(threadOperation.source, threadOperation.destination, threadOperation.timeoutOnNoDataMS,
threadOperation.forceHostAddress, threadOperation.socketFamily, &threadOperation.forwardingPort, &threadOperation.forwardingSocket);
udpForwarder->threadOperationOutgoingMutex.Lock();
udpForwarder->threadOperationOutgoingQueue.Push(threadOperation, _FILE_AND_LINE_ );
udpForwarder->threadOperationOutgoingMutex.Unlock();
}
else
{
udpForwarder->StopForwardingThreaded(threadOperation.source, threadOperation.destination);
}
udpForwarder->threadOperationIncomingMutex.Lock();
}
udpForwarder->threadOperationIncomingMutex.Unlock();
#if RAKNET_SUPPORT_IPV6!=1
udpForwarder->UpdateThreaded_Old();
#else
udpForwarder->UpdateThreaded();
#endif
// 12/1/2010 Do not change from 0
// See http://www.jenkinssoftware.com/forum/index.php?topic=4033.0;topicseen
// Avoid 100% reported CPU usage
RakSleep(0);
}
udpForwarder->threadRunning=false;
return 0;
}
} // namespace RakNet
#endif
#endif // #if _RAKNET_SUPPORT_FileOperations==1