1852 lines
41 KiB
C++
Executable File
1852 lines
41 KiB
C++
Executable File
/// \file
|
|
/// \brief SocketLayer class implementation
|
|
///
|
|
/// This file is part of RakNet Copyright 2003 Jenkins Software LLC
|
|
///
|
|
/// Usage of RakNet is subject to the appropriate license agreement.
|
|
|
|
|
|
#include "SocketLayer.h"
|
|
#include "RakAssert.h"
|
|
#include "RakNetTypes.h"
|
|
#include "GetTime.h"
|
|
#include "LinuxStrings.h"
|
|
#include "SocketDefines.h"
|
|
|
|
using namespace RakNet;
|
|
|
|
#if USE_SLIDING_WINDOW_CONGESTION_CONTROL!=1
|
|
#include "CCRakNetUDT.h"
|
|
#else
|
|
#include "CCRakNetSlidingWindow.h"
|
|
#endif
|
|
|
|
SocketLayerOverride *SocketLayer::slo=0;
|
|
|
|
#ifdef _WIN32
|
|
#else
|
|
#include <string.h> // memcpy
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <arpa/inet.h>
|
|
#include <errno.h> // error numbers
|
|
#include <stdio.h> // RAKNET_DEBUG_PRINTF
|
|
#if !defined(ANDROID)
|
|
#include <ifaddrs.h>
|
|
#endif
|
|
#include <netinet/in.h>
|
|
#include <net/if.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
#include "WSAStartupSingleton.h"
|
|
#include <ws2tcpip.h> // 'IP_DONTFRAGMENT' 'IP_TTL'
|
|
#elif defined SN_TARGET_PSP2
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "RakSleep.h"
|
|
#include <stdio.h>
|
|
#include "Itoa.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( push )
|
|
#endif
|
|
|
|
namespace RakNet
|
|
{
|
|
extern void ProcessNetworkPacket( const SystemAddress systemAddress, const char *data, const int length, RakPeer *rakPeer, RakNet::TimeUS timeRead );
|
|
extern void ProcessNetworkPacket( const SystemAddress systemAddress, const char *data, const int length, RakPeer *rakPeer, RakNetSmartPtr<RakNetSocket> rakNetSocket, RakNet::TimeUS timeRead );
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
// http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#ip4to6
|
|
// http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#getaddrinfo
|
|
|
|
#if RAKNET_SUPPORT_IPV6==1
|
|
void PrepareAddrInfoHints(addrinfo *hints)
|
|
{
|
|
memset(hints, 0, sizeof (addrinfo)); // make sure the struct is empty
|
|
hints->ai_socktype = SOCK_DGRAM; // UDP sockets
|
|
hints->ai_flags = AI_PASSIVE; // fill in my IP for me
|
|
}
|
|
#endif
|
|
|
|
// Frogwares: Define this
|
|
// #define DEBUG_SENDTO_SPIKES
|
|
|
|
bool SocketLayer::IsPortInUse_Old(unsigned short port, const char *hostAddress)
|
|
{
|
|
SOCKET listenSocket;
|
|
sockaddr_in listenerSocketAddress;
|
|
memset(&listenerSocketAddress,0,sizeof(sockaddr_in));
|
|
// Listen on our designated Port#
|
|
listenerSocketAddress.sin_port = htons( port );
|
|
listenSocket = socket__( AF_INET, SOCK_DGRAM, 0 );
|
|
if ( listenSocket == (SOCKET) -1 )
|
|
return true;
|
|
// bind our name to the socket
|
|
// Fill in the rest of the address structure
|
|
listenerSocketAddress.sin_family = AF_INET;
|
|
|
|
if ( hostAddress && hostAddress[0] )
|
|
{
|
|
|
|
|
|
|
|
listenerSocketAddress.sin_addr.s_addr = inet_addr__( hostAddress );
|
|
|
|
}
|
|
else
|
|
listenerSocketAddress.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ret = bind__( listenSocket, ( struct sockaddr * ) & listenerSocketAddress, sizeof( listenerSocketAddress ) );
|
|
closesocket__(listenSocket);
|
|
|
|
|
|
|
|
|
|
// #if defined(_DEBUG)
|
|
// if (ret == -1)
|
|
// perror("Failed to bind to address:");
|
|
// #endif
|
|
return ret <= -1;
|
|
|
|
}
|
|
bool SocketLayer::IsSocketFamilySupported(const char *hostAddress, unsigned short socketFamily)
|
|
{
|
|
(void) hostAddress;
|
|
(void) socketFamily;
|
|
|
|
#if RAKNET_SUPPORT_IPV6!=1
|
|
return socketFamily==AF_INET;
|
|
#else
|
|
struct addrinfo hints;
|
|
#if RAKNET_SUPPORT_IPV6==1
|
|
PrepareAddrInfoHints(&hints);
|
|
#endif
|
|
hints.ai_family = socketFamily;
|
|
struct addrinfo *servinfo=0;
|
|
int error;
|
|
// On Ubuntu, "" returns "No address associated with hostname" while 0 works.
|
|
if (hostAddress &&
|
|
(_stricmp(hostAddress,"UNASSIGNED_SYSTEM_ADDRESS")==0 || hostAddress[0]==0))
|
|
{
|
|
getaddrinfo(0, "0", &hints, &servinfo);
|
|
}
|
|
else
|
|
{
|
|
getaddrinfo(hostAddress, "0", &hints, &servinfo);
|
|
}
|
|
|
|
|
|
(void) error;
|
|
if (servinfo)
|
|
{
|
|
freeaddrinfo(servinfo);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
#if (defined(__GNUC__) || defined(__GCCXML__)) && !defined(_WIN32)
|
|
printf("IsSocketFamilySupported failed. hostAddress=%s. %s\n", hostAddress, gai_strerror(error));
|
|
#endif
|
|
}
|
|
return false;
|
|
#endif
|
|
}
|
|
bool SocketLayer::IsPortInUse(unsigned short port, const char *hostAddress, unsigned short socketFamily)
|
|
{
|
|
#if RAKNET_SUPPORT_IPV6!=1
|
|
(void) socketFamily;
|
|
return IsPortInUse_Old(port, hostAddress);
|
|
#else
|
|
SOCKET listenSocket;
|
|
struct addrinfo hints;
|
|
struct addrinfo *servinfo=0, *aip; // will point to the results
|
|
PrepareAddrInfoHints(&hints);
|
|
hints.ai_family = socketFamily;
|
|
char portStr[32];
|
|
Itoa(port,portStr,10);
|
|
|
|
// On Ubuntu, "" returns "No address associated with hostname" while 0 works.
|
|
if (hostAddress &&
|
|
(_stricmp(hostAddress,"UNASSIGNED_SYSTEM_ADDRESS")==0 || hostAddress[0]==0))
|
|
{
|
|
getaddrinfo(0, portStr, &hints, &servinfo);
|
|
}
|
|
else
|
|
{
|
|
getaddrinfo(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.
|
|
listenSocket = socket__(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
|
|
if (listenSocket != -1)
|
|
{
|
|
int ret = bind__( listenSocket, aip->ai_addr, (int) aip->ai_addrlen );
|
|
closesocket__(listenSocket);
|
|
if (ret>=0)
|
|
{
|
|
freeaddrinfo(servinfo); // free the linked-list
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// If the user didn't specify which host address, then only apply the first
|
|
if (hostAddress==0 || hostAddress[0]==0)
|
|
break;
|
|
}
|
|
|
|
freeaddrinfo(servinfo); // free the linked-list
|
|
return true;
|
|
#endif // #if RAKNET_SUPPORT_IPV6!=1
|
|
}
|
|
void SocketLayer::SetDoNotFragment( SOCKET listenSocket, int opt, int IPPROTO )
|
|
{
|
|
#if defined(IP_DONTFRAGMENT )
|
|
|
|
#if defined(_WIN32) && defined(_DEBUG)
|
|
// If this assert hit you improperly linked against WSock32.h
|
|
RakAssert(IP_DONTFRAGMENT==14);
|
|
#endif
|
|
|
|
if ( setsockopt__( listenSocket, IPPROTO, IP_DONTFRAGMENT, ( char * ) & opt, sizeof ( opt ) ) == -1 )
|
|
{
|
|
#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 );
|
|
// I see this hit on XP with IPV6 for some reason
|
|
RAKNET_DEBUG_PRINTF( "Warning: setsockopt__(IP_DONTFRAGMENT) failed:Error code - %d\n%s", dwIOError, messageBuffer );
|
|
LocalFree( messageBuffer );
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void SocketLayer::SetNonBlocking( SOCKET listenSocket)
|
|
{
|
|
#ifdef _WIN32
|
|
unsigned long nonBlocking = 1;
|
|
ioctlsocket__( listenSocket, FIONBIO, &nonBlocking );
|
|
|
|
|
|
|
|
#else
|
|
int flags = fcntl(listenSocket, F_GETFL, 0);
|
|
fcntl(listenSocket, F_SETFL, flags | O_NONBLOCK);
|
|
#endif
|
|
}
|
|
|
|
void SocketLayer::SetSocketOptions( SOCKET listenSocket)
|
|
{
|
|
int sock_opt = 1;
|
|
// // On Vista, can get WSAEACCESS (10013)
|
|
/*
|
|
if ( setsockopt__( listenSocket, SOL_SOCKET, SO_REUSEADDR, ( char * ) & sock_opt, sizeof ( sock_opt ) ) == -1 )
|
|
{
|
|
#if defined(_WIN32) && !defined(_XBOX) && defined(_DEBUG) && !defined(X360)
|
|
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( "setsockopt__(SO_REUSEADDR) failed:Error code - %d\n%s", dwIOError, messageBuffer );
|
|
//Free the buffer.
|
|
LocalFree( messageBuffer );
|
|
#endif
|
|
}
|
|
*/
|
|
|
|
// This doubles the max throughput rate
|
|
sock_opt=1024*256;
|
|
setsockopt__(listenSocket, SOL_SOCKET, SO_RCVBUF, ( char * ) & sock_opt, sizeof ( sock_opt ) );
|
|
|
|
// Immediate hard close. Don't linger the socket, or recreating the socket quickly on Vista fails.
|
|
// Fail with voice and xbox
|
|
|
|
sock_opt=0;
|
|
setsockopt__(listenSocket, SOL_SOCKET, SO_LINGER, ( char * ) & sock_opt, sizeof ( sock_opt ) );
|
|
|
|
|
|
|
|
// This doesn't make much difference: 10% maybe
|
|
// Not supported on console 2
|
|
sock_opt=1024*16;
|
|
setsockopt__(listenSocket, SOL_SOCKET, SO_SNDBUF, ( char * ) & sock_opt, sizeof ( sock_opt ) );
|
|
|
|
#ifdef __APPLE__
|
|
// Preventing SEGPIPE on "broken" socket
|
|
int set = 1;
|
|
setsockopt__(listenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
|
|
#endif
|
|
|
|
/*
|
|
#ifdef _WIN32
|
|
unsigned long nonblocking = 1;
|
|
ioctlsocket__( listenSocket, FIONBIO, &nonblocking );
|
|
#elif defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3) || defined(SN_TARGET_PSP2)
|
|
sock_opt=1;
|
|
setsockopt__(listenSocket, SOL_SOCKET, SO_NBIO, ( char * ) & sock_opt, sizeof ( sock_opt ) );
|
|
#else
|
|
fcntl( listenSocket, F_SETFL, O_NONBLOCK );
|
|
#endif
|
|
*/
|
|
|
|
// TODO - teston ipv6
|
|
|
|
// Note: Fails with VDP but not xbox
|
|
// Set broadcast capable
|
|
sock_opt=1;
|
|
if ( setsockopt__( listenSocket, SOL_SOCKET, SO_BROADCAST, ( char * ) & sock_opt, sizeof( sock_opt ) ) == -1 )
|
|
{
|
|
#if defined(_WIN32) && defined(_DEBUG)
|
|
|
|
DWORD dwIOError = GetLastError();
|
|
// On Vista, can get WSAEACCESS (10013)
|
|
// See http://support.microsoft.com/kb/819124
|
|
// http://blogs.msdn.com/wndp/archive/2007/03/19/winsock-so-exclusiveaddruse-on-vista.aspx
|
|
// http://msdn.microsoft.com/en-us/library/ms740621(VS.85).aspx
|
|
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( "setsockopt__(SO_BROADCAST) failed:Error code - %d\n%s", dwIOError, messageBuffer );
|
|
//Free the buffer.
|
|
LocalFree( messageBuffer );
|
|
|
|
#endif
|
|
|
|
}
|
|
}
|
|
SOCKET SocketLayer::CreateBoundSocket_PS3Lobby( unsigned short port, bool blockingSocket, const char *forceHostAddress, unsigned short socketFamily )
|
|
{
|
|
(void) port;
|
|
(void) blockingSocket;
|
|
(void) forceHostAddress;
|
|
(void) socketFamily;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
SOCKET SocketLayer::CreateBoundSocket_PSP2( unsigned short port, bool blockingSocket, const char *forceHostAddress, unsigned short socketFamily )
|
|
{
|
|
(void) port;
|
|
(void) blockingSocket;
|
|
(void) forceHostAddress;
|
|
(void) socketFamily;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
SOCKET SocketLayer::CreateBoundSocket_Old( unsigned short port, bool blockingSocket, const char *forceHostAddress, unsigned int sleepOn10048, unsigned int extraSocketOptions )
|
|
{
|
|
(void) blockingSocket;
|
|
|
|
int ret;
|
|
SOCKET listenSocket;
|
|
sockaddr_in listenerSocketAddress;
|
|
memset(&listenerSocketAddress,0,sizeof(sockaddr_in));
|
|
// Listen on our designated Port#
|
|
listenerSocketAddress.sin_port = htons( port );
|
|
|
|
listenSocket = socket__( AF_INET, SOCK_DGRAM, extraSocketOptions );
|
|
|
|
if ( listenSocket == (SOCKET) -1 )
|
|
{
|
|
#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( "socket__(...) failed:Error code - %d\n%s", dwIOError, messageBuffer );
|
|
char str[512];
|
|
strcpy(str,(const char*) messageBuffer);
|
|
//Free the buffer.
|
|
LocalFree( messageBuffer );
|
|
#endif
|
|
|
|
return (SOCKET) -1;
|
|
}
|
|
|
|
SetSocketOptions(listenSocket);
|
|
|
|
// Fill in the rest of the address structure
|
|
listenerSocketAddress.sin_family = AF_INET;
|
|
|
|
if (forceHostAddress && forceHostAddress[0])
|
|
{
|
|
// RAKNET_DEBUG_PRINTF("Force binding %s:%i\n", forceHostAddress, port);
|
|
|
|
|
|
|
|
listenerSocketAddress.sin_addr.s_addr = inet_addr__( forceHostAddress );
|
|
|
|
}
|
|
else
|
|
{
|
|
// RAKNET_DEBUG_PRINTF("Binding any on port %i\n", port);
|
|
listenerSocketAddress.sin_addr.s_addr = INADDR_ANY;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// bind our name to the socket
|
|
ret = bind__( listenSocket, ( struct sockaddr * ) & listenerSocketAddress, sizeof( listenerSocketAddress ) );
|
|
|
|
if ( ret <= -1 )
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
DWORD dwIOError = GetLastError();
|
|
if (dwIOError==10048)
|
|
{
|
|
if (sleepOn10048==0)
|
|
return (SOCKET) -1;
|
|
// Vista has a bug where it returns WSAEADDRINUSE (10048) if you create, shutdown, then rebind the socket port unless you wait a while first.
|
|
// Wait, then rebind
|
|
RakSleep(100);
|
|
|
|
closesocket__(listenSocket);
|
|
listenerSocketAddress.sin_port = htons( port );
|
|
listenSocket = socket__( AF_INET, SOCK_DGRAM, 0 );
|
|
if ( listenSocket == (SOCKET) -1 )
|
|
return false;
|
|
SetSocketOptions(listenSocket);
|
|
|
|
// Fill in the rest of the address structure
|
|
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;
|
|
|
|
// bind our name to the socket
|
|
ret = bind__( listenSocket, ( struct sockaddr * ) & listenerSocketAddress, sizeof( listenerSocketAddress ) );
|
|
|
|
if ( ret >= 0 )
|
|
return listenSocket;
|
|
}
|
|
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( "bind__(...) failed:Error code - %d\n%s", (unsigned int) dwIOError, (char*) messageBuffer );
|
|
//Free the buffer.
|
|
LocalFree( messageBuffer );
|
|
#elif (defined(__GNUC__) || defined(__GCCXML__) ) && !defined(_WIN32)
|
|
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:
|
|
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 (SOCKET) -1;
|
|
}
|
|
|
|
return listenSocket;
|
|
}
|
|
SOCKET SocketLayer::CreateBoundSocket( unsigned short port, bool blockingSocket, const char *forceHostAddress, unsigned int sleepOn10048, unsigned int extraSocketOptions, unsigned short socketFamily )
|
|
{
|
|
(void) blockingSocket;
|
|
(void) extraSocketOptions;
|
|
(void) socketFamily;
|
|
|
|
#if RAKNET_SUPPORT_IPV6!=1
|
|
return CreateBoundSocket_Old(port,blockingSocket,forceHostAddress,sleepOn10048,extraSocketOptions);
|
|
#else
|
|
|
|
#ifdef _WIN32
|
|
// Vista has a bug where it returns WSAEADDRINUSE (10048) if you create, shutdown, then rebind the socket port unless you wait a while first.
|
|
if (sleepOn10048==0)
|
|
RakSleep(100);
|
|
#endif
|
|
|
|
int ret=0;
|
|
SOCKET listenSocket;
|
|
struct addrinfo hints;
|
|
struct addrinfo *servinfo=0, *aip; // will point to the results
|
|
PrepareAddrInfoHints(&hints);
|
|
hints.ai_family=socketFamily;
|
|
char portStr[32];
|
|
Itoa(port,portStr,10);
|
|
|
|
// On Ubuntu, "" returns "No address associated with hostname" while 0 works.
|
|
if (forceHostAddress &&
|
|
(_stricmp(forceHostAddress,"UNASSIGNED_SYSTEM_ADDRESS")==0 || forceHostAddress[0]==0))
|
|
{
|
|
getaddrinfo(0, portStr, &hints, &servinfo);
|
|
}
|
|
else
|
|
{
|
|
getaddrinfo(forceHostAddress, 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.
|
|
listenSocket = socket__(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
|
|
if (listenSocket != -1)
|
|
{
|
|
ret = bind__( listenSocket, aip->ai_addr, (int) aip->ai_addrlen );
|
|
if (ret>=0)
|
|
{
|
|
// Is this valid?
|
|
sockaddr_in6 addr6;
|
|
memcpy(&addr6, aip->ai_addr, sizeof(addr6));
|
|
|
|
freeaddrinfo(servinfo); // free the linked-list
|
|
|
|
SetSocketOptions(listenSocket);
|
|
return listenSocket;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
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( "bind__(...) failed:Error code - %d\n%s", (unsigned int) dwIOError, (char*) messageBuffer );
|
|
//Free the buffer.
|
|
LocalFree( messageBuffer );
|
|
#elif defined(__GNUC__) || defined(__GCCXML__) && !defined(_WIN32)
|
|
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:
|
|
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
|
|
|
|
|
|
#endif
|
|
|
|
return (SOCKET) -1;
|
|
}
|
|
const char* SocketLayer::DomainNameToIP_Old( const char *domainName )
|
|
{
|
|
struct in_addr addr;
|
|
memset(&addr,0,sizeof(in_addr));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Use inet_addr instead? What is the difference?
|
|
struct hostent * phe = gethostbyname( domainName );
|
|
|
|
if ( phe == 0 || phe->h_addr_list[ 0 ] == 0 )
|
|
{
|
|
//cerr << "Yow! Bad host lookup." << endl;
|
|
return 0;
|
|
}
|
|
|
|
if (phe->h_addr_list[ 0 ]==0)
|
|
return 0;
|
|
|
|
memcpy( &addr, phe->h_addr_list[ 0 ], sizeof( struct in_addr ) );
|
|
return inet_ntoa( addr );
|
|
|
|
|
|
return "";
|
|
}
|
|
const char* SocketLayer::DomainNameToIP( const char *domainName )
|
|
{
|
|
#if RAKNET_SUPPORT_IPV6!=1
|
|
return DomainNameToIP_Old(domainName);
|
|
#else
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct addrinfo hints, *res, *p;
|
|
int status;
|
|
static char ipstr[INET6_ADDRSTRLEN];
|
|
memset(&hints, 0, sizeof hints);
|
|
hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
|
|
if ((status = getaddrinfo(domainName, NULL, &hints, &res)) != 0) {
|
|
return 0;
|
|
}
|
|
|
|
p=res;
|
|
// for(p = res;p != NULL; p = p->ai_next) {
|
|
void *addr;
|
|
// char *ipver;
|
|
|
|
// get the pointer to the address itself,
|
|
// different fields in IPv4 and IPv6:
|
|
if (p->ai_family == AF_INET)
|
|
{
|
|
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
|
|
addr = &(ipv4->sin_addr);
|
|
strcpy(ipstr, inet_ntoa( ipv4->sin_addr ));
|
|
}
|
|
else
|
|
{
|
|
// TODO - test
|
|
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
|
|
addr = &(ipv6->sin6_addr);
|
|
// inet_ntop function does not exist on windows
|
|
// http://www.mail-archive.com/users@ipv6.org/msg02107.html
|
|
getnameinfo((struct sockaddr *)ipv6, sizeof(struct sockaddr_in6), ipstr, 1, NULL, 0, NI_NUMERICHOST);
|
|
}
|
|
freeaddrinfo(res); // free the linked list
|
|
return ipstr;
|
|
// }
|
|
|
|
|
|
|
|
return "";
|
|
|
|
#endif // #if RAKNET_SUPPORT_IPV6!=1
|
|
}
|
|
|
|
|
|
void SocketLayer::Write( const SOCKET writeSocket, const char* data, const int length )
|
|
{
|
|
#ifdef _DEBUG
|
|
RakAssert( writeSocket != (SOCKET) -1 );
|
|
#endif
|
|
|
|
send__( writeSocket, data, length, 0 );
|
|
}
|
|
void SocketLayer::RecvFromBlocking_Old( const SOCKET s, RakPeer *rakPeer, unsigned short remotePortRakNetWasStartedOn_PS3, unsigned int extraSocketOptions, char *dataOut, int *bytesReadOut, SystemAddress *systemAddressOut, RakNet::TimeUS *timeRead )
|
|
{
|
|
(void) rakPeer;
|
|
|
|
sockaddr* sockAddrPtr;
|
|
socklen_t sockLen;
|
|
socklen_t* socketlenPtr=(socklen_t*) &sockLen;
|
|
sockaddr_in sa;
|
|
memset(&sa,0,sizeof(sockaddr_in));
|
|
int dataOutSize;
|
|
const int flag=0;
|
|
|
|
(void) remotePortRakNetWasStartedOn_PS3;
|
|
(void) extraSocketOptions;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
sockLen=sizeof(sa);
|
|
sa.sin_family = AF_INET;
|
|
sa.sin_port=0;
|
|
sockAddrPtr=(sockaddr*) &sa;
|
|
}
|
|
|
|
|
|
|
|
|
|
dataOutSize=MAXIMUM_MTU_SIZE;
|
|
|
|
|
|
*bytesReadOut = recvfrom__( s, dataOut, dataOutSize, flag, sockAddrPtr, socketlenPtr );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (*bytesReadOut<=0)
|
|
return;
|
|
*timeRead=RakNet::GetTimeUS();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
systemAddressOut->SetPortNetworkOrder( sa.sin_port );
|
|
systemAddressOut->address.addr4.sin_addr.s_addr=sa.sin_addr.s_addr;
|
|
}
|
|
}
|
|
|
|
void SocketLayer::RecvFromBlocking( const SOCKET s, RakPeer *rakPeer, unsigned short remotePortRakNetWasStartedOn_PS3, unsigned int extraSocketOptions, char *dataOut, int *bytesReadOut, SystemAddress *systemAddressOut, RakNet::TimeUS *timeRead )
|
|
{
|
|
#if RAKNET_SUPPORT_IPV6!=1
|
|
RecvFromBlocking_Old(s,rakPeer,remotePortRakNetWasStartedOn_PS3,extraSocketOptions,dataOut,bytesReadOut,systemAddressOut,timeRead);
|
|
#else
|
|
(void) rakPeer;
|
|
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;
|
|
|
|
(void) remotePortRakNetWasStartedOn_PS3;
|
|
(void) extraSocketOptions;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
sockLen=sizeof(their_addr);
|
|
sockAddrPtr=(sockaddr*) &their_addr;
|
|
}
|
|
|
|
|
|
|
|
|
|
dataOutSize=MAXIMUM_MTU_SIZE;
|
|
|
|
|
|
*bytesReadOut = recvfrom__( s, dataOut, dataOutSize, flag, sockAddrPtr, socketlenPtr );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (*bytesReadOut<=0)
|
|
return;
|
|
*timeRead=RakNet::GetTimeUS();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
if (their_addr.ss_family==AF_INET)
|
|
{
|
|
memcpy(&systemAddressOut->address.addr4,(sockaddr_in *)&their_addr,sizeof(sockaddr_in));
|
|
systemAddressOut->debugPort=ntohs(systemAddressOut->address.addr4.sin_port);
|
|
// systemAddressOut->address.addr4.sin_port=ntohs( systemAddressOut->address.addr4.sin_port );
|
|
}
|
|
else
|
|
{
|
|
memcpy(&systemAddressOut->address.addr6,(sockaddr_in6 *)&their_addr,sizeof(sockaddr_in6));
|
|
systemAddressOut->debugPort=ntohs(systemAddressOut->address.addr6.sin6_port);
|
|
// systemAddressOut->address.addr6.sin6_port=ntohs( systemAddressOut->address.addr6.sin6_port );
|
|
}
|
|
}
|
|
|
|
#endif // defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3) || defined(SN_TARGET_PSP2)
|
|
}
|
|
|
|
int SocketLayer::SendTo_PS3Lobby( SOCKET s, const char *data, int length, const SystemAddress &systemAddress, unsigned short remotePortRakNetWasStartedOn_PS3 )
|
|
{
|
|
(void) s;
|
|
(void) data;
|
|
(void) length;
|
|
(void) remotePortRakNetWasStartedOn_PS3;
|
|
(void) systemAddress;
|
|
|
|
int len=0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return len;
|
|
}
|
|
int SocketLayer::SendTo_PSP2( SOCKET s, const char *data, int length, const SystemAddress &systemAddress, unsigned short remotePortRakNetWasStartedOn_PS3 )
|
|
{
|
|
(void) s;
|
|
(void) data;
|
|
(void) length;
|
|
(void) remotePortRakNetWasStartedOn_PS3;
|
|
(void) systemAddress;
|
|
|
|
int len=0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return len;
|
|
}
|
|
int SocketLayer::SendTo_360( SOCKET s, const char *data, int length, const char *voiceData, int voiceLength, const SystemAddress &systemAddress, unsigned int extraSocketOptions )
|
|
{
|
|
(void) s;
|
|
(void) data;
|
|
(void) length;
|
|
(void) voiceData;
|
|
(void) voiceLength;
|
|
(void) extraSocketOptions;
|
|
(void) systemAddress;
|
|
|
|
int len=0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return len;
|
|
}
|
|
int SocketLayer::SendTo_PC( SOCKET s, const char *data, int length, const SystemAddress &systemAddress, const char *file, const long line )
|
|
{
|
|
// TODO
|
|
// http://www.linuxquestions.org/questions/linux-software-2/ipv6-linux-sendto-problems-519485/
|
|
|
|
// #if RAKNET_SUPPORT_IPV6==1
|
|
// RakAssert(
|
|
// systemAddress.address.addr4.sin_family!=AF_MAX &&
|
|
// (systemAddress.address.addr4.sin_family==AF_INET || (systemAddress.address.addr6.sin6_scope_id!=0))
|
|
// );
|
|
// #endif
|
|
|
|
/*
|
|
sockaddr_in sa;
|
|
memset(&sa,0,sizeof(sockaddr_in));
|
|
sa.sin_port = htons( port ); // User port
|
|
sa.sin_addr.s_addr = binaryAddress;
|
|
sa.sin_family = socketFamily;
|
|
*/
|
|
|
|
int len=0;
|
|
do
|
|
{
|
|
#ifdef DEBUG_SENDTO_SPIKES
|
|
RakNetTime start = RakNet::GetTime();
|
|
#else
|
|
(void) file;
|
|
(void) line;
|
|
#endif
|
|
if (systemAddress.address.addr4.sin_family==AF_INET)
|
|
{
|
|
//systemAddress.address.addr4.sin_port=htons(systemAddress.address.addr4.sin_port);
|
|
len = sendto__( s, data, length, 0, ( const sockaddr* ) & systemAddress.address.addr4, sizeof( sockaddr_in ) );
|
|
//systemAddress.address.addr4.sin_port=ntohs(systemAddress.address.addr4.sin_port);
|
|
}
|
|
else
|
|
{
|
|
#if RAKNET_SUPPORT_IPV6==1
|
|
// systemAddress.address.addr6.sin6_port=htons(systemAddress.address.addr6.sin6_port);
|
|
len = sendto__( s, data, length, 0, ( const sockaddr* ) & systemAddress.address.addr6, sizeof( sockaddr_in6 ) );
|
|
//systemAddress.address.addr6.sin6_port=ntohs(systemAddress.address.addr6.sin6_port);
|
|
#endif
|
|
}
|
|
|
|
#ifdef DEBUG_SENDTO_SPIKES
|
|
RakNetTime end = RakNet::GetTime();
|
|
static unsigned int callCount=1;
|
|
RAKNET_DEBUG_PRINTF("%i. SendTo_PC, time=%llu, elapsed=%llu, length=%i, returned=%i, binaryAddress=%i, port=%i, file=%s, line=%i\n", callCount++, end, end-start, length, len, binaryAddress, port, file, line);
|
|
#endif
|
|
if (len<0)
|
|
{
|
|
RAKNET_DEBUG_PRINTF("sendto failed with code %i for char %i and length %i.\n", len, data[0], length);
|
|
}
|
|
}
|
|
while ( len == 0 );
|
|
return len;
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( disable : 4702 ) // warning C4702: unreachable code
|
|
#endif
|
|
int SocketLayer::SendTo( SOCKET s, const char *data, int length, SystemAddress &systemAddress, unsigned short remotePortRakNetWasStartedOn_PS3, unsigned int extraSocketOptions, const char *file, const long line )
|
|
{
|
|
(void) extraSocketOptions;
|
|
|
|
int len=0;
|
|
RakAssert(length<=MAXIMUM_MTU_SIZE-UDP_HEADER_SIZE);
|
|
#if !defined(__S3E__)
|
|
RakAssert(systemAddress.address.addr4.sin_family!=AF_MAX);
|
|
#endif
|
|
|
|
if (slo)
|
|
{
|
|
len = slo->RakNetSendTo(s,data,length,systemAddress);
|
|
if ( len != -1 )
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
if ( s == (SOCKET) -1 )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
|
|
if (remotePortRakNetWasStartedOn_PS3!=0)
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
len = SendTo_PC(s,data,length,systemAddress,file,line);
|
|
|
|
}
|
|
|
|
if ( len != -1 )
|
|
return 0;
|
|
|
|
#if defined(_WIN32) && !defined(_WIN32_WCE)
|
|
|
|
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(_DEBUG)
|
|
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 dwIOError;
|
|
#endif
|
|
|
|
return 1; // error
|
|
}
|
|
// Not enough info for IPV6
|
|
// int SocketLayer::SendTo( SOCKET s, const char *data, int length, const char ip[ 16 ], unsigned short port, unsigned short remotePortRakNetWasStartedOn_PS3, unsigned int extraSocketOptions, const char *file, const long line )
|
|
// {
|
|
// SystemAddress systemAddress;
|
|
// systemAddress.FromStringAndPort(ip,port);
|
|
// return SendTo( s, data, length, systemAddress,remotePortRakNetWasStartedOn_PS3, extraSocketOptions, file, line );
|
|
// }
|
|
int SocketLayer::SendToTTL( SOCKET s, const char *data, int length, SystemAddress &systemAddress, int ttl )
|
|
{
|
|
if (slo)
|
|
return slo->RakNetSendTo(s,data,length,systemAddress);
|
|
|
|
|
|
int oldTTL;
|
|
socklen_t opLen=sizeof(oldTTL);
|
|
// Get the current TTL
|
|
if (getsockopt__(s, systemAddress.GetIPPROTO(), IP_TTL, ( char * ) & oldTTL, &opLen ) == -1)
|
|
{
|
|
#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( "getsockopt__(IPPROTO_IP,IP_TTL) failed:Error code - %d\n%s", dwIOError, messageBuffer );
|
|
//Free the buffer.
|
|
LocalFree( messageBuffer );
|
|
#endif
|
|
}
|
|
|
|
// Set to TTL
|
|
int newTTL=ttl;
|
|
if (setsockopt__(s, systemAddress.GetIPPROTO(), IP_TTL, ( char * ) & newTTL, sizeof ( newTTL ) ) == -1)
|
|
{
|
|
|
|
#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( "setsockopt__(IPPROTO_IP,IP_TTL) failed:Error code - %d\n%s", dwIOError, messageBuffer );
|
|
//Free the buffer.
|
|
LocalFree( messageBuffer );
|
|
#endif
|
|
}
|
|
|
|
// Send
|
|
int res = SendTo(s,data,length,systemAddress,0,0, __FILE__, __LINE__ );
|
|
|
|
// Restore the old TTL
|
|
setsockopt__(s, systemAddress.GetIPPROTO(), IP_TTL, ( char * ) & oldTTL, opLen );
|
|
|
|
return res;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
RakNet::RakString SocketLayer::GetSubNetForSocketAndIp(SOCKET inSock, RakNet::RakString inIpString)
|
|
{
|
|
RakNet::RakString netMaskString;
|
|
RakNet::RakString ipString;
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
INTERFACE_INFO InterfaceList[20];
|
|
unsigned long nBytesReturned;
|
|
if (WSAIoctl(inSock, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList,
|
|
sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR) {
|
|
return "";
|
|
}
|
|
|
|
int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
|
|
|
|
for (int i = 0; i < nNumInterfaces; ++i)
|
|
{
|
|
sockaddr_in *pAddress;
|
|
pAddress = (sockaddr_in *) & (InterfaceList[i].iiAddress);
|
|
ipString=inet_ntoa(pAddress->sin_addr);
|
|
|
|
if (inIpString==ipString)
|
|
{
|
|
pAddress = (sockaddr_in *) & (InterfaceList[i].iiNetmask);
|
|
netMaskString=inet_ntoa(pAddress->sin_addr);
|
|
return netMaskString;
|
|
}
|
|
}
|
|
return "";
|
|
#else
|
|
|
|
int fd,fd2;
|
|
fd2 = socket__(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if(fd2 < 0)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
struct ifconf ifc;
|
|
char buf[1999];
|
|
ifc.ifc_len = sizeof(buf);
|
|
ifc.ifc_buf = buf;
|
|
if(ioctl(fd2, SIOCGIFCONF, &ifc) < 0)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
struct ifreq *ifr;
|
|
ifr = ifc.ifc_req;
|
|
int intNum = ifc.ifc_len / sizeof(struct ifreq);
|
|
for(int i = 0; i < intNum; i++)
|
|
{
|
|
ipString=inet_ntoa(((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr);
|
|
|
|
if (inIpString==ipString)
|
|
{
|
|
struct ifreq ifr2;
|
|
fd = socket__(AF_INET, SOCK_DGRAM, 0);
|
|
if(fd < 0)
|
|
{
|
|
return "";
|
|
}
|
|
ifr2.ifr_addr.sa_family = AF_INET;
|
|
|
|
strncpy(ifr2.ifr_name, ifr[i].ifr_name, IFNAMSIZ-1);
|
|
|
|
ioctl(fd, SIOCGIFNETMASK, &ifr2);
|
|
|
|
close(fd);
|
|
close(fd2);
|
|
netMaskString=inet_ntoa(((struct sockaddr_in *)&ifr2.ifr_addr)->sin_addr);
|
|
|
|
return netMaskString;
|
|
}
|
|
}
|
|
|
|
close(fd2);
|
|
return "";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void GetMyIP_Win32( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] )
|
|
{
|
|
char ac[ 80 ];
|
|
if ( gethostname( ac, sizeof( ac ) ) == -1 )
|
|
{
|
|
#if defined(_WIN32)
|
|
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( "gethostname failed:Error code - %d\n%s", dwIOError, messageBuffer );
|
|
//Free the buffer.
|
|
LocalFree( messageBuffer );
|
|
#endif
|
|
return ;
|
|
}
|
|
|
|
|
|
#if RAKNET_SUPPORT_IPV6==1
|
|
struct addrinfo hints;
|
|
struct addrinfo *servinfo=0, *aip; // will point to the results
|
|
PrepareAddrInfoHints(&hints);
|
|
getaddrinfo(ac, "", &hints, &servinfo);
|
|
|
|
int idx;
|
|
for (idx=0, aip = servinfo; aip != NULL && idx < MAXIMUM_NUMBER_OF_INTERNAL_IDS; aip = aip->ai_next, idx++)
|
|
{
|
|
if (aip->ai_family == AF_INET)
|
|
{
|
|
struct sockaddr_in *ipv4 = (struct sockaddr_in *)aip->ai_addr;
|
|
memcpy(&addresses[idx].address.addr4,ipv4,sizeof(sockaddr_in));
|
|
}
|
|
else
|
|
{
|
|
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)aip->ai_addr;
|
|
memcpy(&addresses[idx].address.addr4,ipv6,sizeof(sockaddr_in6));
|
|
}
|
|
|
|
}
|
|
|
|
freeaddrinfo(servinfo); // free the linked-list
|
|
#else
|
|
struct hostent *phe = gethostbyname( ac );
|
|
|
|
if ( phe == 0 )
|
|
{
|
|
#ifdef _WIN32
|
|
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( "gethostbyname failed:Error code - %d\n%s", dwIOError, messageBuffer );
|
|
|
|
//Free the buffer.
|
|
LocalFree( messageBuffer );
|
|
#endif
|
|
return ;
|
|
}
|
|
int idx;
|
|
for ( idx = 0; idx < MAXIMUM_NUMBER_OF_INTERNAL_IDS; ++idx )
|
|
{
|
|
if (phe->h_addr_list[ idx ] == 0)
|
|
break;
|
|
|
|
memcpy(&addresses[idx].address.addr4.sin_addr,phe->h_addr_list[ idx ],sizeof(struct in_addr));
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
while (idx < MAXIMUM_NUMBER_OF_INTERNAL_IDS)
|
|
{
|
|
addresses[idx]=UNASSIGNED_SYSTEM_ADDRESS;
|
|
idx++;
|
|
}
|
|
}
|
|
// #else
|
|
/*
|
|
void GetMyIP_Linux( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] )
|
|
{
|
|
struct ifaddrs *ifaddr, *ifa;
|
|
int family, s;
|
|
char host[NI_MAXHOST];
|
|
struct in_addr linux_in_addr;
|
|
|
|
if (getifaddrs(&ifaddr) == -1) {
|
|
printf( "Error getting interface list\n");
|
|
}
|
|
|
|
int idx = 0;
|
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
|
if (!ifa->ifa_addr) continue;
|
|
family = ifa->ifa_addr->sa_family;
|
|
|
|
if (family == AF_INET) {
|
|
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
|
if (s != 0) {
|
|
// printf ("getnameinfo() failed: %s\n", gai_strerror(s));
|
|
}
|
|
else if (strcmp(host,"127.0.0.1")!=0)
|
|
{
|
|
if (inet_aton(host, &addresses[idx].address.addr4.sin_addr)!=0)
|
|
idx++;
|
|
}
|
|
}
|
|
#if RAKNET_SUPPORT_IPV6==1
|
|
else
|
|
{
|
|
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
|
if (s != 0) {
|
|
// printf ("getnameinfo() failed: %s\n", gai_strerror(s));
|
|
}
|
|
else if (strcmp(host,"::1")!=0)
|
|
{
|
|
if (inet_pton(family, host, &addresses[idx].address.addr6.sin6_addr)!=0)
|
|
idx++;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
for ( ; idx < MAXIMUM_NUMBER_OF_INTERNAL_IDS; ++idx )
|
|
{
|
|
addresses[idx]=UNASSIGNED_SYSTEM_ADDRESS;
|
|
}
|
|
|
|
freeifaddrs(ifaddr);
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
void SocketLayer::GetMyIP( SystemAddress addresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS] )
|
|
{
|
|
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
GetMyIP_Win32(addresses);
|
|
#else
|
|
// GetMyIP_Linux(addresses);
|
|
GetMyIP_Win32(addresses);
|
|
#endif
|
|
}
|
|
|
|
|
|
unsigned short SocketLayer::GetLocalPort(SOCKET s)
|
|
{
|
|
SystemAddress sa;
|
|
GetSystemAddress(s,&sa);
|
|
return sa.GetPort();
|
|
}
|
|
void SocketLayer::GetSystemAddress_Old ( SOCKET s, SystemAddress *systemAddressOut )
|
|
{
|
|
sockaddr_in sa;
|
|
memset(&sa,0,sizeof(sockaddr_in));
|
|
socklen_t len = sizeof(sa);
|
|
if (getsockname__(s, (sockaddr*)&sa, &len)!=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 = UNASSIGNED_SYSTEM_ADDRESS;
|
|
return;
|
|
}
|
|
|
|
systemAddressOut->SetPortNetworkOrder(sa.sin_port);
|
|
systemAddressOut->address.addr4.sin_addr.s_addr=sa.sin_addr.s_addr;
|
|
}
|
|
void SocketLayer::GetSystemAddress ( SOCKET s, SystemAddress *systemAddressOut )
|
|
{
|
|
#if RAKNET_SUPPORT_IPV6!=1
|
|
GetSystemAddress_Old(s,systemAddressOut);
|
|
#else
|
|
socklen_t slen;
|
|
sockaddr_storage ss;
|
|
slen = sizeof(ss);
|
|
|
|
if (getsockname__(s, (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);
|
|
}
|
|
#endif // #if RAKNET_SUPPORT_IPV6!=1
|
|
}
|
|
|
|
void SocketLayer::SetSocketLayerOverride(SocketLayerOverride *_slo)
|
|
{
|
|
slo=_slo;
|
|
}
|
|
|
|
bool SocketLayer::GetFirstBindableIP(char firstBindable[128], int ipProto)
|
|
{
|
|
SystemAddress ipList[ MAXIMUM_NUMBER_OF_INTERNAL_IDS ];
|
|
SocketLayer::GetMyIP( ipList );
|
|
|
|
|
|
if (ipProto==AF_UNSPEC)
|
|
|
|
{
|
|
ipList[0].ToString(false,firstBindable);
|
|
return true;
|
|
}
|
|
|
|
// Find the first valid host address
|
|
unsigned int l;
|
|
for (l=0; l < MAXIMUM_NUMBER_OF_INTERNAL_IDS; l++)
|
|
{
|
|
if (ipList[l]==UNASSIGNED_SYSTEM_ADDRESS)
|
|
break;
|
|
if (ipList[l].GetIPVersion()==4 && ipProto==AF_INET)
|
|
break;
|
|
if (ipList[l].GetIPVersion()==6 && ipProto==AF_INET6)
|
|
break;
|
|
}
|
|
|
|
if (ipList[l]==UNASSIGNED_SYSTEM_ADDRESS || l==MAXIMUM_NUMBER_OF_INTERNAL_IDS)
|
|
return false;
|
|
// RAKNET_DEBUG_PRINTF("%i %i %i %i\n",
|
|
// ((char*)(&ipList[l].address.addr4.sin_addr.s_addr))[0],
|
|
// ((char*)(&ipList[l].address.addr4.sin_addr.s_addr))[1],
|
|
// ((char*)(&ipList[l].address.addr4.sin_addr.s_addr))[2],
|
|
// ((char*)(&ipList[l].address.addr4.sin_addr.s_addr))[3]
|
|
// );
|
|
ipList[l].ToString(false,firstBindable);
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning( pop )
|
|
#endif
|