Files
mcpe/thirdparty/raknet/RakNetSocket2_Berkley.cpp
iProgramInCpp 9642818a88 * Initial commit.
:)
2023-07-30 22:22:02 +03:00

555 lines
13 KiB
C++

/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#include "EmptyHeader.h"
#ifdef RAKNET_SOCKET_2_INLINE_FUNCTIONS
#ifndef RAKNETSOCKET2_BERKLEY_CPP
#define RAKNETSOCKET2_BERKLEY_CPP
// Every platform except windows store 8 and native client supports Berkley sockets
#if !defined(WINDOWS_STORE_RT) && !defined(__native_client__)
#include "Itoa.h"
void RNS2_Berkley::SetSocketOptions(void)
{
int r;
// This doubles the max throughput rate
int sock_opt=1024*256;
r = setsockopt__( rns2Socket, SOL_SOCKET, SO_RCVBUF, ( char * ) & sock_opt, sizeof ( sock_opt ) );
RakAssert(r==0);
// Immediate hard close. Don't linger the socket, or recreating the socket quickly on Vista fails.
// Fail with voice and xbox
sock_opt=0;
r = setsockopt__( rns2Socket, SOL_SOCKET, SO_LINGER, ( char * ) & sock_opt, sizeof ( sock_opt ) );
// Do not assert, ignore failure
// This doesn't make much difference: 10% maybe
// Not supported on console 2
sock_opt=1024*16;
r = setsockopt__( rns2Socket, SOL_SOCKET, SO_SNDBUF, ( char * ) & sock_opt, sizeof ( sock_opt ) );
RakAssert(r==0);
}
void RNS2_Berkley::SetNonBlockingSocket(unsigned long nonblocking)
{
#ifdef _WIN32
int res = ioctlsocket__( rns2Socket, FIONBIO, &nonblocking );
RakAssert(res==0);
#else
if (nonblocking)
fcntl( rns2Socket, F_SETFL, O_NONBLOCK );
#endif
}
void RNS2_Berkley::SetBroadcastSocket(int broadcast)
{
setsockopt__( rns2Socket, SOL_SOCKET, SO_BROADCAST, ( char * ) & broadcast, sizeof( broadcast ) );
}
void RNS2_Berkley::SetIPHdrIncl(int ipHdrIncl)
{
setsockopt__( rns2Socket, IPPROTO_IP, IP_HDRINCL, ( char * ) & ipHdrIncl, sizeof( ipHdrIncl ) );
}
void RNS2_Berkley::SetDoNotFragment( int opt )
{
#if defined( IP_DONTFRAGMENT )
#if defined(_WIN32) && !defined(_DEBUG)
// If this assert hit you improperly linked against WSock32.h
RakAssert(IP_DONTFRAGMENT==14);
#endif
setsockopt__( rns2Socket, boundAddress.GetIPPROTO(), IP_DONTFRAGMENT, ( char * ) & opt, sizeof ( opt ) );
#endif
}
void RNS2_Berkley::GetSystemAddressIPV4 ( RNS2Socket rns2Socket, SystemAddress *systemAddressOut )
{
sockaddr_in sa;
memset(&sa,0,sizeof(sockaddr_in));
socklen_t len = sizeof(sa);
//int r =
getsockname__(rns2Socket, (sockaddr*)&sa, &len);
systemAddressOut->SetPortNetworkOrder(sa.sin_port);
systemAddressOut->address.addr4.sin_addr.s_addr=sa.sin_addr.s_addr;
if (systemAddressOut->address.addr4.sin_addr.s_addr == INADDR_ANY)
{
systemAddressOut->address.addr4.sin_addr.s_addr=inet_addr__("127.0.0.1");
}
}
void RNS2_Berkley::GetSystemAddressIPV4And6 ( RNS2Socket rns2Socket, SystemAddress *systemAddressOut )
{
#if RAKNET_SUPPORT_IPV6==1
socklen_t slen;
sockaddr_storage ss;
slen = sizeof(ss);
if ( getsockname__(rns2Socket, (struct sockaddr *)&ss, &slen)!=0)
{
#if defined(_WIN32) && defined(_DEBUG)
DWORD dwIOError = GetLastError();
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( "getsockname failed:Error code - %d\n%s", dwIOError, messageBuffer );
//Free the buffer.
LocalFree( messageBuffer );
#endif
systemAddressOut->FromString(0);
return;
}
if (ss.ss_family==AF_INET)
{
memcpy(&systemAddressOut->address.addr4,(sockaddr_in *)&ss,sizeof(sockaddr_in));
systemAddressOut->debugPort=ntohs(systemAddressOut->address.addr4.sin_port);
uint32_t zero = 0;
if (memcmp(&systemAddressOut->address.addr4.sin_addr.s_addr, &zero, sizeof(zero))==0)
systemAddressOut->SetToLoopback(4);
// systemAddressOut->address.addr4.sin_port=ntohs(systemAddressOut->address.addr4.sin_port);
}
else
{
memcpy(&systemAddressOut->address.addr6,(sockaddr_in6 *)&ss,sizeof(sockaddr_in6));
systemAddressOut->debugPort=ntohs(systemAddressOut->address.addr6.sin6_port);
char zero[16];
memset(zero,0,sizeof(zero));
if (memcmp(&systemAddressOut->address.addr4.sin_addr.s_addr, &zero, sizeof(zero))==0)
systemAddressOut->SetToLoopback(6);
// systemAddressOut->address.addr6.sin6_port=ntohs(systemAddressOut->address.addr6.sin6_port);
}
#else
(void) rns2Socket;
(void) systemAddressOut;
return;
#endif
}
#ifdef _MSC_VER
#pragma warning( disable : 4702 ) // warning C4702: unreachable code
#endif
RNS2BindResult RNS2_Berkley::BindSharedIPV4( RNS2_BerkleyBindParameters *bindParameters, const char *file, unsigned int line ) {
(void) file;
(void) line;
int ret;
memset(&boundAddress.address.addr4,0,sizeof(sockaddr_in));
boundAddress.address.addr4.sin_port = htons( bindParameters->port );
rns2Socket = (int) socket__( bindParameters->addressFamily, bindParameters->type, bindParameters->protocol );
if (rns2Socket == -1)
return BR_FAILED_TO_BIND_SOCKET;
SetSocketOptions();
SetNonBlockingSocket(bindParameters->nonBlockingSocket);
SetBroadcastSocket(bindParameters->setBroadcast);
SetIPHdrIncl(bindParameters->setIPHdrIncl);
// Fill in the rest of the address structure
boundAddress.address.addr4.sin_family = AF_INET;
if (bindParameters->hostAddress && bindParameters->hostAddress[0])
{
boundAddress.address.addr4.sin_addr.s_addr = inet_addr__( bindParameters->hostAddress );
}
else
{
// RAKNET_DEBUG_PRINTF("Binding any on port %i\n", port);
boundAddress.address.addr4.sin_addr.s_addr = INADDR_ANY;
}
// bind our name to the socket
ret = bind__( rns2Socket, ( struct sockaddr * ) &boundAddress.address.addr4, sizeof( boundAddress.address.addr4 ) );
if ( ret <= -1 )
{
#if defined(_WIN32)
closesocket__(rns2Socket);
return BR_FAILED_TO_BIND_SOCKET;
#elif (defined(__GNUC__) || defined(__GCCXML__) ) && !defined(_WIN32)
closesocket__(rns2Socket);
switch (ret)
{
case EBADF:
RAKNET_DEBUG_PRINTF("bind__(): sockfd is not a valid descriptor.\n"); break;
case ENOTSOCK:
RAKNET_DEBUG_PRINTF("bind__(): Argument is a descriptor for a file, not a socket.\n"); break;
case EINVAL:
RAKNET_DEBUG_PRINTF("bind__(): The addrlen is wrong, or the socket was not in the AF_UNIX family.\n"); break;
case EROFS:
RAKNET_DEBUG_PRINTF("bind__(): The socket inode would reside on a read-only file system.\n"); break;
case EFAULT:
RAKNET_DEBUG_PRINTF("bind__(): my_addr points outside the user's accessible address space.\n"); break;
case ENAMETOOLONG:
RAKNET_DEBUG_PRINTF("bind__(): my_addr is too long.\n"); break;
case ENOENT:
RAKNET_DEBUG_PRINTF("bind__(): The file does not exist.\n"); break;
case ENOMEM:
RAKNET_DEBUG_PRINTF("bind__(): Insufficient kernel memory was available.\n"); break;
case ENOTDIR:
RAKNET_DEBUG_PRINTF("bind__(): A component of the path prefix is not a directory.\n"); break;
case EACCES:
// Port reserved on PS4
RAKNET_DEBUG_PRINTF("bind__(): Search permission is denied on a component of the path prefix.\n"); break;
case ELOOP:
RAKNET_DEBUG_PRINTF("bind__(): Too many symbolic links were encountered in resolving my_addr.\n"); break;
default:
RAKNET_DEBUG_PRINTF("Unknown bind__() error %i.\n", ret); break;
}
#endif
return BR_FAILED_TO_BIND_SOCKET;
}
GetSystemAddressIPV4(rns2Socket, &boundAddress );
return BR_SUCCESS;
}
RNS2BindResult RNS2_Berkley::BindSharedIPV4And6( RNS2_BerkleyBindParameters *bindParameters, const char *file, unsigned int line ) {
(void) file;
(void) line;
(void) bindParameters;
#if RAKNET_SUPPORT_IPV6==1
int ret=0;
struct addrinfo hints;
struct addrinfo *servinfo=0, *aip; // will point to the results
PrepareAddrInfoHints2(&hints);
hints.ai_family=bindParameters->addressFamily;
char portStr[32];
Itoa(bindParameters->port,portStr,10);
// On Ubuntu, "" returns "No address associated with hostname" while 0 works.
if (bindParameters->hostAddress &&
(_stricmp(bindParameters->hostAddress,"UNASSIGNED_SYSTEM_ADDRESS")==0 || bindParameters->hostAddress[0]==0))
{
getaddrinfo(0, portStr, &hints, &servinfo);
}
else
{
getaddrinfo(bindParameters->hostAddress, portStr, &hints, &servinfo);
}
// Try all returned addresses until one works
for (aip = servinfo; aip != NULL; aip = aip->ai_next)
{
// Open socket. The address type depends on what
// getaddrinfo() gave us.
rns2Socket = socket__(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
if (rns2Socket == -1)
return BR_FAILED_TO_BIND_SOCKET;
ret = bind__(rns2Socket, aip->ai_addr, (int) aip->ai_addrlen );
if (ret>=0)
{
// Is this valid?
memcpy(&boundAddress.address.addr6, aip->ai_addr, sizeof(boundAddress.address.addr6));
freeaddrinfo(servinfo); // free the linked-list
SetSocketOptions();
SetNonBlockingSocket(bindParameters->nonBlockingSocket);
SetBroadcastSocket(bindParameters->setBroadcast);
SetIPHdrIncl(bindParameters->setIPHdrIncl);
GetSystemAddressIPV4And6( rns2Socket, &boundAddress );
return BR_SUCCESS;
}
else
{
closesocket__(rns2Socket);
}
}
return BR_FAILED_TO_BIND_SOCKET;
#else
return BR_REQUIRES_RAKNET_SUPPORT_IPV6_DEFINE;
#endif
}
void RNS2_Berkley::RecvFromBlockingIPV4And6(RNS2RecvStruct *recvFromStruct)
{
#if RAKNET_SUPPORT_IPV6==1
sockaddr_storage their_addr;
sockaddr* sockAddrPtr;
socklen_t sockLen;
socklen_t* socketlenPtr=(socklen_t*) &sockLen;
memset(&their_addr,0,sizeof(their_addr));
int dataOutSize;
const int flag=0;
{
sockLen=sizeof(their_addr);
sockAddrPtr=(sockaddr*) &their_addr;
}
dataOutSize=MAXIMUM_MTU_SIZE;
recvFromStruct->bytesRead = recvfrom__(rns2Socket, recvFromStruct->data, dataOutSize, flag, sockAddrPtr, socketlenPtr );
#if defined(_WIN32) && defined(_DEBUG) && !defined(WINDOWS_PHONE_8)
if (recvFromStruct->bytesRead==-1)
{
DWORD dwIOError = GetLastError();
if (dwIoError != 10035)
{
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 );
// I see this hit on XP with IPV6 for some reason
RAKNET_DEBUG_PRINTF( "Warning: recvfrom failed:Error code - %d\n%s", dwIOError, messageBuffer );
LocalFree( messageBuffer );
}
}
#endif
if (recvFromStruct->bytesRead<=0)
return;
recvFromStruct->timeRead=RakNet::GetTimeUS();
{
if (their_addr.ss_family==AF_INET)
{
memcpy(&recvFromStruct->systemAddress.address.addr4,(sockaddr_in *)&their_addr,sizeof(sockaddr_in));
recvFromStruct->systemAddress.debugPort=ntohs(recvFromStruct->systemAddress.address.addr4.sin_port);
// systemAddressOut->address.addr4.sin_port=ntohs( systemAddressOut->address.addr4.sin_port );
}
else
{
memcpy(&recvFromStruct->systemAddress.address.addr6,(sockaddr_in6 *)&their_addr,sizeof(sockaddr_in6));
recvFromStruct->systemAddress.debugPort=ntohs(recvFromStruct->systemAddress.address.addr6.sin6_port);
// systemAddressOut->address.addr6.sin6_port=ntohs( systemAddressOut->address.addr6.sin6_port );
}
}
#else
(void) recvFromStruct;
#endif
}
void RNS2_Berkley::RecvFromBlockingIPV4(RNS2RecvStruct *recvFromStruct)
{
sockaddr* sockAddrPtr;
socklen_t sockLen;
socklen_t* socketlenPtr=(socklen_t*) &sockLen;
sockaddr_in sa;
memset(&sa,0,sizeof(sockaddr_in));
const int flag=0;
{
sockLen=sizeof(sa);
sa.sin_family = AF_INET;
sa.sin_port=0;
sockAddrPtr=(sockaddr*) &sa;
}
recvFromStruct->bytesRead = recvfrom__( GetSocket(), recvFromStruct->data, sizeof(recvFromStruct->data), flag, sockAddrPtr, socketlenPtr );
if (recvFromStruct->bytesRead<=0)
{
/*
DWORD dwIOError = WSAGetLastError();
if ( dwIOError == WSAECONNRESET )
{
#if defined(_DEBUG)
RAKNET_DEBUG_PRINTF( "A previous send operation resulted in an ICMP Port Unreachable message.\n" );
#endif
}
else if ( dwIOError != WSAEWOULDBLOCK && dwIOError != WSAEADDRNOTAVAIL)
{
#if defined(_WIN32) && !defined(_XBOX) && !defined(_XBOX_720_COMPILE_AS_WINDOWS) && !defined(X360) && defined(_DEBUG) && !defined(_XBOX_720_COMPILE_AS_WINDOWS) && !defined(WINDOWS_PHONE_8)
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( "sendto failed:Error code - %d\n%s", dwIOError, messageBuffer );
//Free the buffer.
LocalFree( messageBuffer );
#endif
}
*/
return;
}
recvFromStruct->timeRead=RakNet::GetTimeUS();
{
recvFromStruct->systemAddress.SetPortNetworkOrder( sa.sin_port );
recvFromStruct->systemAddress.address.addr4.sin_addr.s_addr=sa.sin_addr.s_addr;
}
// printf("--- Got %i bytes from %s\n", recvFromStruct->bytesRead, recvFromStruct->systemAddress.ToString());
}
void RNS2_Berkley::RecvFromBlocking(RNS2RecvStruct *recvFromStruct)
{
#if RAKNET_SUPPORT_IPV6==1
return RecvFromBlockingIPV4And6(recvFromStruct);
#else
return RecvFromBlockingIPV4(recvFromStruct);
#endif
}
#endif // !defined(WINDOWS_STORE_RT) && !defined(__native_client__)
#endif // file header
#endif // #ifdef RAKNET_SOCKET_2_INLINE_FUNCTIONS