/* * Original work: Copyright (c) 2014, Oculus VR, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * RakNet License.txt file in the licenses directory of this source tree. An additional grant * of patent rights can be found in the RakNet Patents.txt file in the same directory. * * * Modified work: Copyright (c) 2016-2020, SLikeSoft UG (haftungsbeschränkt) * * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style * license found in the license.txt file in the root directory of this source tree. */ #include "slikenet/UDPForwarder.h" #if _RAKNET_SUPPORT_UDPForwarder==1 #include "slikenet/GetTime.h" #include "slikenet/MTUSize.h" #include "slikenet/SocketLayer.h" #include "slikenet/WSAStartupSingleton.h" #include "slikenet/sleep.h" #include "slikenet/DS_OrderedList.h" #include "slikenet/LinuxStrings.h" #include "slikenet/SocketDefines.h" #include "slikenet/VitaIncludes.h" #include "errno.h" #ifdef _WIN32 #include #else #ifndef _T #define _T(x) (x) #endif #include // used for getaddrinfo() #include // used for getaddrinfo() #include // used for getaddrinfo() #endif #ifndef INVALID_SOCKET #define INVALID_SOCKET -1 #endif using namespace SLNet; static const unsigned short DEFAULT_MAX_FORWARD_ENTRIES=64; namespace SLNet { RAK_THREAD_DECLARATION(UpdateUDPForwarderGlobal); } UDPForwarder::ForwardEntry::ForwardEntry() { socket=INVALID_SOCKET; timeLastDatagramForwarded= SLNet::GetTimeMS(); addr1Confirmed=UNASSIGNED_SYSTEM_ADDRESS; addr2Confirmed=UNASSIGNED_SYSTEM_ADDRESS; } UDPForwarder::ForwardEntry::~ForwardEntry() { if (socket!=INVALID_SOCKET) closesocket__(socket); } UDPForwarder::UDPForwarder() { #ifdef _WIN32 WSAStartupSingleton::AddRef(); #endif maxForwardEntries=DEFAULT_MAX_FORWARD_ENTRIES; nextInputId=0; startForwardingInput.SetPageSize(sizeof(StartForwardingInputStruct)*16); stopForwardingCommands.SetPageSize(sizeof(StopForwardingStruct)*16); } UDPForwarder::~UDPForwarder() { Shutdown(); #ifdef _WIN32 WSAStartupSingleton::Deref(); #endif } void UDPForwarder::Startup(void) { if (isRunning.GetValue()>0) return; isRunning.Increment(); int errorCode; errorCode = SLNet::RakThread::Create(UpdateUDPForwarderGlobal, this); if ( errorCode != 0 ) { RakAssert(0); return; } while (threadRunning.GetValue()==0) RakSleep(30); } void UDPForwarder::Shutdown(void) { if (isRunning.GetValue()==0) return; isRunning.Decrement(); while (threadRunning.GetValue()>0) RakSleep(30); unsigned int j; for (j=0; j < forwardListNotUpdated.Size(); j++) SLNet::OP_DELETE(forwardListNotUpdated[j],_FILE_AND_LINE_); forwardListNotUpdated.Clear(false, _FILE_AND_LINE_); } 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) forwardListNotUpdated.Size(); } UDPForwarderResult UDPForwarder::StartForwarding(SystemAddress source, SystemAddress destination, SLNet::TimeMS timeoutOnNoDataMS, const char *forceHostAddress, unsigned short socketFamily, unsigned short *forwardingPort, __UDPSOCKET__ *forwardingSocket) { // Invalid parameters? if (timeoutOnNoDataMS == 0 || timeoutOnNoDataMS > UDP_FORWARDER_MAXIMUM_TIMEOUT || source==UNASSIGNED_SYSTEM_ADDRESS || destination==UNASSIGNED_SYSTEM_ADDRESS) return UDPFORWARDER_INVALID_PARAMETERS; if (isRunning.GetValue()==0) return UDPFORWARDER_NOT_RUNNING; (void) socketFamily; unsigned int inputId = nextInputId++; StartForwardingInputStruct *sfis; sfis = startForwardingInput.Allocate(_FILE_AND_LINE_); sfis->source=source; sfis->destination=destination; sfis->timeoutOnNoDataMS=timeoutOnNoDataMS; RakAssert(timeoutOnNoDataMS!=0); if (forceHostAddress && forceHostAddress[0]) sfis->forceHostAddress=forceHostAddress; sfis->socketFamily=socketFamily; sfis->inputId=inputId; startForwardingInput.Push(sfis); for(;;) { RakSleep(0); startForwardingOutputMutex.Lock(); for (unsigned int i=0; i < startForwardingOutput.Size(); i++) { if (startForwardingOutput[i].inputId==inputId) { if (startForwardingOutput[i].result==UDPFORWARDER_SUCCESS) { if (forwardingPort) *forwardingPort = startForwardingOutput[i].forwardingPort; if (forwardingSocket) *forwardingSocket = startForwardingOutput[i].forwardingSocket; } UDPForwarderResult res = startForwardingOutput[i].result; startForwardingOutput.RemoveAtIndex(i); startForwardingOutputMutex.Unlock(); return res; } } startForwardingOutputMutex.Unlock(); } } void UDPForwarder::StopForwarding(SystemAddress source, SystemAddress destination) { StopForwardingStruct *sfs; sfs = stopForwardingCommands.Allocate(_FILE_AND_LINE_); sfs->destination=destination; sfs->source=source; stopForwardingCommands.Push(sfs); } void UDPForwarder::RecvFrom(SLNet::TimeMS curTime, ForwardEntry *forwardEntry) { #ifndef __native_client__ char data[ MAXIMUM_MTU_SIZE ]; #if RAKNET_SUPPORT_IPV6==1 sockaddr_storage their_addr; memset(&their_addr,0,sizeof(their_addr)); sockaddr* sockAddrPtr; socklen_t sockLen; socklen_t* socketlenPtr=(socklen_t*) &sockLen; sockaddr_in *sockAddrIn; sockaddr_in6 *sockAddrIn6; sockLen=sizeof(their_addr); sockAddrPtr=(sockaddr*) &their_addr; #else sockaddr_in sockAddrIn; memset(&sockAddrIn,0,sizeof(sockaddr_in)); socklen_t len2; len2 = sizeof( sockAddrIn ); sockAddrIn.sin_family = AF_INET; #endif #if defined(__GNUC__) #if defined(MSG_DONTWAIT) const int flag=MSG_DONTWAIT; #else const int flag=0x40; #endif #else const int flag=0; #endif int receivedDataLen, len=0; //unsigned short portnum=0; #if RAKNET_SUPPORT_IPV6==1 receivedDataLen = recvfrom__( forwardEntry->socket, data, MAXIMUM_MTU_SIZE, flag, sockAddrPtr, socketlenPtr ); #else receivedDataLen = recvfrom__( forwardEntry->socket, data, MAXIMUM_MTU_SIZE, flag, ( sockaddr* ) & sockAddrIn, ( socklen_t* ) & len2 ); #endif if (receivedDataLen<0) { #if defined(_WIN32) && defined(_DEBUG) && !defined(WINDOWS_PHONE_8) && !defined(WINDOWS_STORE_RT) DWORD dwIOError = WSAGetLastError(); if (dwIOError!=WSAECONNRESET && dwIOError!=WSAEINTR && dwIOError!=WSAETIMEDOUT && dwIOError!=WSAEWOULDBLOCK) { LPTSTR messageBuffer; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, dwIOError, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language ( LPTSTR ) & messageBuffer, 0, nullptr); // something has gone wrong here... RAKNET_DEBUG_TPRINTF( _T("recvfrom failed:Error code - %lu\n%s"), dwIOError, messageBuffer ); //Free the buffer. LocalFree( messageBuffer ); } #else if (errno!=EAGAIN && errno!=0 #if defined(__GNUC__) && errno!=EWOULDBLOCK #endif ) { printf("errno=%i\n", errno); } #endif } if (receivedDataLen<=0) return; SystemAddress receivedAddr; #if RAKNET_SUPPORT_IPV6==1 if (their_addr.ss_family==AF_INET) { sockAddrIn=(sockaddr_in *)&their_addr; sockAddrIn6=0; memcpy(&receivedAddr.address.addr4,sockAddrIn,sizeof(sockaddr_in)); } else { sockAddrIn=0; sockAddrIn6=(sockaddr_in6 *)&their_addr; memcpy(&receivedAddr.address.addr6,sockAddrIn6,sizeof(sockaddr_in6)); } #else memcpy(&receivedAddr.address.addr4,&sockAddrIn,sizeof(sockaddr_in)); #endif //portnum=receivedAddr.GetPort(); SystemAddress forwardTarget; bool confirmed1 = forwardEntry->addr1Confirmed!=UNASSIGNED_SYSTEM_ADDRESS; bool confirmed2 = forwardEntry->addr2Confirmed!=UNASSIGNED_SYSTEM_ADDRESS; bool matchConfirmed1 = confirmed1 && forwardEntry->addr1Confirmed==receivedAddr; bool matchConfirmed2 = confirmed2 && forwardEntry->addr2Confirmed==receivedAddr; bool matchUnconfirmed1 = forwardEntry->addr1Unconfirmed.EqualsExcludingPort(receivedAddr); bool matchUnconfirmed2 = forwardEntry->addr2Unconfirmed.EqualsExcludingPort(receivedAddr); if (matchConfirmed1==true || (matchConfirmed2==false && confirmed1==false && matchUnconfirmed1==true)) { // Forward to addr2 if (forwardEntry->addr1Confirmed==UNASSIGNED_SYSTEM_ADDRESS) { forwardEntry->addr1Confirmed=receivedAddr; } if (forwardEntry->addr2Confirmed!=UNASSIGNED_SYSTEM_ADDRESS) forwardTarget=forwardEntry->addr2Confirmed; else forwardTarget=forwardEntry->addr2Unconfirmed; } else if (matchConfirmed2==true || (confirmed2==false && matchUnconfirmed2==true)) { // Forward to addr1 if (forwardEntry->addr2Confirmed==UNASSIGNED_SYSTEM_ADDRESS) { forwardEntry->addr2Confirmed=receivedAddr; } if (forwardEntry->addr1Confirmed!=UNASSIGNED_SYSTEM_ADDRESS) forwardTarget=forwardEntry->addr1Confirmed; else forwardTarget=forwardEntry->addr1Unconfirmed; } else { return; } // Forward to dest len=0; // sockaddr_in saOut; // saOut.sin_port = forwardTarget.GetPortNetworkOrder(); // User port // saOut.sin_addr.s_addr = forwardTarget.address.addr4.sin_addr.s_addr; // saOut.sin_family = AF_INET; do { #if RAKNET_SUPPORT_IPV6==1 if (forwardTarget.address.addr4.sin_family==AF_INET) { do { len = sendto__( forwardEntry->socket, data, receivedDataLen, 0, ( const sockaddr* ) & forwardTarget.address.addr4, sizeof( sockaddr_in ) ); } while ( len == 0 ); } else { do { len = sendto__( forwardEntry->socket, data, receivedDataLen, 0, ( const sockaddr* ) & forwardTarget.address.addr6, sizeof( sockaddr_in6 ) ); } while ( len == 0 ); } #else do { len = sendto__( forwardEntry->socket, data, receivedDataLen, 0, ( const sockaddr* ) & forwardTarget.address.addr4, sizeof( sockaddr_in ) ); } while ( len == 0 ); #endif } while ( len == 0 ); forwardEntry->timeLastDatagramForwarded=curTime; #endif // __native_client__ } void UDPForwarder::UpdateUDPForwarder(void) { /* #if !defined(SN_TARGET_PSP2) timeval tv; tv.tv_sec=0; tv.tv_usec=0; #endif */ SLNet::TimeMS curTime = SLNet::GetTimeMS(); StartForwardingInputStruct *sfis; StartForwardingOutputStruct sfos; sfos.forwardingSocket=INVALID_SOCKET; sfos.forwardingPort=0; sfos.inputId=0; sfos.result=UDPFORWARDER_RESULT_COUNT; for(;;) { sfis = startForwardingInput.Pop(); if (sfis==0) break; if (GetUsedForwardEntries()>maxForwardEntries) { sfos.result=UDPFORWARDER_NO_SOCKETS; } else { sfos.result=UDPFORWARDER_RESULT_COUNT; for (unsigned int i=0; i < forwardListNotUpdated.Size(); i++) { if ( (forwardListNotUpdated[i]->addr1Unconfirmed==sfis->source && forwardListNotUpdated[i]->addr2Unconfirmed==sfis->destination) || (forwardListNotUpdated[i]->addr1Unconfirmed==sfis->destination && forwardListNotUpdated[i]->addr2Unconfirmed==sfis->source) ) { ForwardEntry *fe = forwardListNotUpdated[i]; sfos.forwardingPort = SocketLayer::GetLocalPort ( fe->socket ); sfos.forwardingSocket=fe->socket; sfos.result=UDPFORWARDER_FORWARDING_ALREADY_EXISTS; break; } } if (sfos.result==UDPFORWARDER_RESULT_COUNT) { int sock_opt; sockaddr_in listenerSocketAddress; listenerSocketAddress.sin_port = 0; ForwardEntry *fe = SLNet::OP_NEW(_FILE_AND_LINE_); fe->addr1Unconfirmed=sfis->source; fe->addr2Unconfirmed=sfis->destination; fe->timeoutOnNoDataMS=sfis->timeoutOnNoDataMS; #if RAKNET_SUPPORT_IPV6!=1 fe->socket = socket__( AF_INET, SOCK_DGRAM, 0 ); listenerSocketAddress.sin_family = AF_INET; if (sfis->forceHostAddress.IsEmpty()==false) { inet_pton(AF_INET, sfis->forceHostAddress.C_String(), &listenerSocketAddress.sin_addr.s_addr); } else { listenerSocketAddress.sin_addr.s_addr = INADDR_ANY; } int ret = bind__( fe->socket, ( struct sockaddr * ) & listenerSocketAddress, sizeof( listenerSocketAddress ) ); if (ret==-1) { SLNet::OP_DELETE(fe,_FILE_AND_LINE_); sfos.result=UDPFORWARDER_BIND_FAILED; } else { sfos.result=UDPFORWARDER_SUCCESS; } #else // RAKNET_SUPPORT_IPV6==1 struct addrinfo hints; memset(&hints, 0, sizeof (addrinfo)); // make sure the struct is empty hints.ai_family = sfis->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 if (sfis->forceHostAddress.IsEmpty() || sfis->forceHostAddress=="UNASSIGNED_SYSTEM_ADDRESS") getaddrinfo(0, "0", &hints, &servinfo); else getaddrinfo(sfis->forceHostAddress.C_String(), "0", &hints, &servinfo); for (aip = servinfo; aip != nullptr; 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) sfos.result=UDPFORWARDER_BIND_FAILED; else sfos.result=UDPFORWARDER_SUCCESS; #endif // RAKNET_SUPPORT_IPV6==1 if (sfos.result==UDPFORWARDER_SUCCESS) { sfos.forwardingPort = SocketLayer::GetLocalPort ( fe->socket ); sfos.forwardingSocket=fe->socket; sock_opt=1024*256; setsockopt__(fe->socket, SOL_SOCKET, SO_RCVBUF, ( char * ) & sock_opt, sizeof ( sock_opt ) ); sock_opt=0; setsockopt__(fe->socket, SOL_SOCKET, SO_LINGER, ( char * ) & sock_opt, sizeof ( sock_opt ) ); #ifdef _WIN32 unsigned long nonblocking = 1; ioctlsocket__( fe->socket, FIONBIO, &nonblocking ); #else fcntl( fe->socket, F_SETFL, O_NONBLOCK ); #endif forwardListNotUpdated.Insert(fe,_FILE_AND_LINE_); } } } // Push result sfos.inputId=sfis->inputId; startForwardingOutputMutex.Lock(); startForwardingOutput.Push(sfos,_FILE_AND_LINE_); startForwardingOutputMutex.Unlock(); startForwardingInput.Deallocate(sfis, _FILE_AND_LINE_); } StopForwardingStruct *sfs; for(;;) { sfs = stopForwardingCommands.Pop(); if (sfs==0) break; ForwardEntry *fe; for (unsigned int i=0; i < forwardListNotUpdated.Size(); i++) { if ( (forwardListNotUpdated[i]->addr1Unconfirmed==sfs->source && forwardListNotUpdated[i]->addr2Unconfirmed==sfs->destination) || (forwardListNotUpdated[i]->addr1Unconfirmed==sfs->destination && forwardListNotUpdated[i]->addr2Unconfirmed==sfs->source) ) { fe = forwardListNotUpdated[i]; forwardListNotUpdated.RemoveAtIndexFast(i); SLNet::OP_DELETE(fe, _FILE_AND_LINE_); break; } } stopForwardingCommands.Deallocate(sfs, _FILE_AND_LINE_); } unsigned int i; i=0; while (i < forwardListNotUpdated.Size()) { if (curTime > forwardListNotUpdated[i]->timeLastDatagramForwarded && // Account for timestamp wrap curTime > forwardListNotUpdated[i]->timeLastDatagramForwarded+forwardListNotUpdated[i]->timeoutOnNoDataMS) { SLNet::OP_DELETE(forwardListNotUpdated[i],_FILE_AND_LINE_); forwardListNotUpdated.RemoveAtIndex(i); } else i++; } ForwardEntry *forwardEntry; for (i=0; i < forwardListNotUpdated.Size(); i++) { forwardEntry = forwardListNotUpdated[i]; RecvFrom(curTime, forwardEntry); } } namespace SLNet { RAK_THREAD_DECLARATION(UpdateUDPForwarderGlobal) { UDPForwarder * udpForwarder = ( UDPForwarder * ) arguments; udpForwarder->threadRunning.Increment(); while (udpForwarder->isRunning.GetValue()>0) { udpForwarder->UpdateUDPForwarder(); // 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 if (udpForwarder->forwardListNotUpdated.Size()==0) RakSleep(30); else RakSleep(0); } udpForwarder->threadRunning.Decrement(); return 0; } } // namespace SLNet #endif // #if _RAKNET_SUPPORT_FileOperations==1