2012-09-19 15:15:01 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
|
|
|
//
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
// of this software and associated documentation files (the "Software"), to
|
|
|
|
|
// deal in the Software without restriction, including without limitation the
|
|
|
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
|
//
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
|
//
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
|
// IN THE SOFTWARE.
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
#include "platform/platformNet.h"
|
2016-09-10 22:01:10 +00:00
|
|
|
#include "platform/threads/mutex.h"
|
2012-09-19 15:15:01 +00:00
|
|
|
#include "core/strings/stringFunctions.h"
|
2016-09-10 22:01:10 +00:00
|
|
|
#include "core/util/hashFunction.h"
|
|
|
|
|
#include "console/consoleTypes.h"
|
|
|
|
|
|
|
|
|
|
// jamesu - debug DNS
|
|
|
|
|
//#define TORQUE_DEBUG_LOOKUPS
|
|
|
|
|
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2014-03-15 14:10:14 +00:00
|
|
|
#if defined (TORQUE_OS_WIN)
|
2012-09-19 15:15:01 +00:00
|
|
|
#define TORQUE_USE_WINSOCK
|
|
|
|
|
#include <errno.h>
|
2016-09-10 22:01:10 +00:00
|
|
|
#include <ws2tcpip.h>
|
2014-03-15 10:51:36 +00:00
|
|
|
|
|
|
|
|
#ifndef EINPROGRESS
|
2012-09-19 15:15:01 +00:00
|
|
|
#define EINPROGRESS WSAEINPROGRESS
|
2014-03-15 10:51:36 +00:00
|
|
|
#endif // EINPROGRESS
|
|
|
|
|
|
2012-09-19 15:15:01 +00:00
|
|
|
#define ioctl ioctlsocket
|
|
|
|
|
|
2013-08-04 21:26:01 +00:00
|
|
|
typedef S32 socklen_t;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
#elif defined ( TORQUE_OS_MAC )
|
|
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/poll.h>
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
#include <netdb.h>
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <sys/ioctl.h>
|
2016-10-28 10:33:43 +00:00
|
|
|
#include <net/if.h>
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
typedef sockaddr_in SOCKADDR_IN;
|
|
|
|
|
typedef sockaddr * PSOCKADDR;
|
|
|
|
|
typedef sockaddr SOCKADDR;
|
|
|
|
|
typedef in_addr IN_ADDR;
|
2016-09-10 22:01:10 +00:00
|
|
|
typedef int SOCKET;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
#define INVALID_SOCKET -1
|
|
|
|
|
#define SOCKET_ERROR -1
|
|
|
|
|
|
|
|
|
|
#define closesocket close
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
#elif defined( TORQUE_OS_LINUX )
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/poll.h>
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
#include <netdb.h>
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <sys/ioctl.h>
|
2016-09-10 22:01:10 +00:00
|
|
|
#include <net/if.h>
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
typedef sockaddr_in SOCKADDR_IN;
|
2016-09-10 22:01:10 +00:00
|
|
|
typedef sockaddr_in6 SOCKADDR_IN6;
|
2012-09-19 15:15:01 +00:00
|
|
|
typedef sockaddr * PSOCKADDR;
|
|
|
|
|
typedef sockaddr SOCKADDR;
|
|
|
|
|
typedef in_addr IN_ADDR;
|
2016-09-10 22:01:10 +00:00
|
|
|
typedef in6_addr IN6_ADDR;
|
|
|
|
|
typedef int SOCKET;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
#define INVALID_SOCKET -1
|
|
|
|
|
#define SOCKET_ERROR -1
|
|
|
|
|
|
|
|
|
|
#define closesocket close
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(TORQUE_USE_WINSOCK)
|
2013-08-04 21:26:01 +00:00
|
|
|
static const char* strerror_wsa( S32 code )
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
switch( code )
|
|
|
|
|
{
|
|
|
|
|
#define E( name ) case name: return #name;
|
|
|
|
|
E( WSANOTINITIALISED );
|
|
|
|
|
E( WSAENETDOWN );
|
|
|
|
|
E( WSAEADDRINUSE );
|
|
|
|
|
E( WSAEINPROGRESS );
|
|
|
|
|
E( WSAEALREADY );
|
|
|
|
|
E( WSAEADDRNOTAVAIL );
|
|
|
|
|
E( WSAEAFNOSUPPORT );
|
|
|
|
|
E( WSAEFAULT );
|
|
|
|
|
E( WSAEINVAL );
|
|
|
|
|
E( WSAEISCONN );
|
|
|
|
|
E( WSAENETUNREACH );
|
|
|
|
|
E( WSAEHOSTUNREACH );
|
|
|
|
|
E( WSAENOBUFS );
|
|
|
|
|
E( WSAENOTSOCK );
|
|
|
|
|
E( WSAETIMEDOUT );
|
|
|
|
|
E( WSAEWOULDBLOCK );
|
|
|
|
|
E( WSAEACCES );
|
|
|
|
|
#undef E
|
|
|
|
|
default:
|
|
|
|
|
return "Unknown";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "core/util/tVector.h"
|
|
|
|
|
#include "platform/platformNetAsync.h"
|
|
|
|
|
#include "console/console.h"
|
|
|
|
|
#include "core/util/journal/process.h"
|
|
|
|
|
#include "core/util/journal/journal.h"
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
|
|
|
|
|
NetSocket NetSocket::INVALID = NetSocket::fromHandle(-1);
|
|
|
|
|
|
|
|
|
|
template<class T> class ReservedSocketList
|
|
|
|
|
{
|
|
|
|
|
public:
|
2016-10-28 17:31:47 +00:00
|
|
|
struct EntryType
|
|
|
|
|
{
|
|
|
|
|
T value;
|
|
|
|
|
bool used;
|
|
|
|
|
|
|
|
|
|
EntryType() : value(-1), used(false) { ; }
|
|
|
|
|
|
|
|
|
|
bool operator==(const EntryType &e1)
|
|
|
|
|
{
|
|
|
|
|
return value == e1.value && used == e1.used;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator!=(const EntryType &e1)
|
|
|
|
|
{
|
|
|
|
|
return !(value == e1.value && used == e1.used);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Vector<EntryType> mSocketList;
|
2016-09-10 22:01:10 +00:00
|
|
|
Mutex *mMutex;
|
|
|
|
|
|
|
|
|
|
ReservedSocketList()
|
|
|
|
|
{
|
|
|
|
|
mMutex = new Mutex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~ReservedSocketList()
|
|
|
|
|
{
|
|
|
|
|
delete mMutex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void modify() { Mutex::lockMutex(mMutex); }
|
|
|
|
|
inline void endModify() { Mutex::unlockMutex(mMutex); }
|
|
|
|
|
|
|
|
|
|
NetSocket reserve(SOCKET reserveId = -1, bool doLock = true);
|
|
|
|
|
void remove(NetSocket socketToRemove, bool doLock = true);
|
|
|
|
|
|
|
|
|
|
T activate(NetSocket socketToActivate, int family, bool useUDP, bool clearOnFail = false);
|
|
|
|
|
T resolve(NetSocket socketToResolve);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const SOCKET InvalidSocketHandle = -1;
|
|
|
|
|
|
|
|
|
|
static void IPSocketToNetAddress(const struct sockaddr_in *sockAddr, NetAddress *address);
|
2016-12-17 23:08:43 +00:00
|
|
|
static void IPSocket6ToNetAddress(const struct sockaddr_in6 *sockAddr, NetAddress *address);
|
2016-09-10 22:01:10 +00:00
|
|
|
|
|
|
|
|
namespace PlatformNetState
|
|
|
|
|
{
|
|
|
|
|
static S32 initCount = 0;
|
|
|
|
|
|
|
|
|
|
static const S32 defaultPort = 28000;
|
|
|
|
|
static S32 netPort = 0;
|
|
|
|
|
|
|
|
|
|
static NetSocket udpSocket = NetSocket::INVALID;
|
|
|
|
|
static NetSocket udp6Socket = NetSocket::INVALID;
|
|
|
|
|
static NetSocket multicast6Socket = NetSocket::INVALID;
|
|
|
|
|
|
|
|
|
|
static ipv6_mreq multicast6Group;
|
|
|
|
|
|
|
|
|
|
static ReservedSocketList<SOCKET> smReservedSocketList;
|
|
|
|
|
|
2016-12-17 23:08:43 +00:00
|
|
|
Net::Error getLastError()
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
#if defined(TORQUE_USE_WINSOCK)
|
|
|
|
|
S32 err = WSAGetLastError();
|
|
|
|
|
switch (err)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
return Net::NoError;
|
|
|
|
|
case WSAEWOULDBLOCK:
|
|
|
|
|
return Net::WouldBlock;
|
|
|
|
|
default:
|
|
|
|
|
return Net::UnknownError;
|
|
|
|
|
}
|
|
|
|
|
#else
|
2016-10-28 18:34:01 +00:00
|
|
|
int theError = errno;
|
2016-09-10 22:01:10 +00:00
|
|
|
if (errno == EAGAIN)
|
|
|
|
|
return Net::WouldBlock;
|
|
|
|
|
if (errno == 0)
|
|
|
|
|
return Net::NoError;
|
2016-10-28 18:34:01 +00:00
|
|
|
if (errno == EINPROGRESS)
|
|
|
|
|
return Net::WouldBlock;
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
return Net::UnknownError;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-17 23:08:43 +00:00
|
|
|
S32 getDefaultGameProtocol()
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
// we turn off VDP in non-release builds because VDP does not support broadcast packets
|
|
|
|
|
// which are required for LAN queries (PC->Xbox connectivity). The wire protocol still
|
|
|
|
|
// uses the VDP packet structure, though.
|
|
|
|
|
S32 protocol = IPPROTO_UDP;
|
|
|
|
|
#ifdef TORQUE_DISABLE_PC_CONNECTIVITY
|
|
|
|
|
// Xbox uses a VDP (voice/data protocol) socket for networking
|
|
|
|
|
protocol = IPPROTO_VDP;
|
|
|
|
|
useVDP = true;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return protocol;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-17 23:08:43 +00:00
|
|
|
struct addrinfo* pickAddressByProtocol(struct addrinfo* addr, int protocol)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
2021-10-05 00:04:21 +00:00
|
|
|
for (; addr != NULL; addr = addr->ai_next)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
if (addr->ai_family == protocol)
|
|
|
|
|
return addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Extracts core address parts from an address string. Returns false if it's malformed.
|
2016-12-17 23:08:43 +00:00
|
|
|
bool extractAddressParts(const char *addressString, char outAddress[256], int &outPort, int &outFamily)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
outPort = 0;
|
|
|
|
|
outFamily = AF_UNSPEC;
|
|
|
|
|
|
|
|
|
|
if (!dStrnicmp(addressString, "ipx:", 4))
|
|
|
|
|
// ipx support deprecated
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!dStrnicmp(addressString, "ip:", 3))
|
|
|
|
|
{
|
|
|
|
|
addressString += 3; // eat off the ip:
|
|
|
|
|
outFamily = AF_INET;
|
|
|
|
|
}
|
|
|
|
|
else if (!dStrnicmp(addressString, "ip6:", 4))
|
|
|
|
|
{
|
|
|
|
|
addressString += 4; // eat off the ip6:
|
|
|
|
|
outFamily = AF_INET6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strlen(addressString) > 255)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
char *portString = NULL;
|
|
|
|
|
|
|
|
|
|
if (addressString[0] == '[')
|
|
|
|
|
{
|
|
|
|
|
// Must be ipv6 notation
|
2018-03-06 06:59:05 +00:00
|
|
|
dStrcpy(outAddress, addressString+1, 256);
|
2016-09-10 22:01:10 +00:00
|
|
|
addressString = outAddress;
|
|
|
|
|
|
|
|
|
|
portString = dStrchr(outAddress, ']');
|
|
|
|
|
if (portString)
|
|
|
|
|
{
|
|
|
|
|
// Sort out the :port after the ]
|
|
|
|
|
*portString++ = '\0';
|
|
|
|
|
if (*portString != ':')
|
|
|
|
|
{
|
|
|
|
|
portString = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*portString++ = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (outFamily == AF_UNSPEC)
|
|
|
|
|
{
|
|
|
|
|
outFamily = AF_INET6;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-03-06 06:59:05 +00:00
|
|
|
dStrcpy(outAddress, addressString, 256);
|
2016-09-10 22:01:10 +00:00
|
|
|
addressString = outAddress;
|
|
|
|
|
|
|
|
|
|
// Check to see if we have multiple ":" which would indicate this is an ipv6 address
|
|
|
|
|
char* scan = outAddress;
|
|
|
|
|
int colonCount = 0;
|
|
|
|
|
while (*scan != '\0' && colonCount < 2)
|
|
|
|
|
{
|
|
|
|
|
if (*scan++ == ':')
|
|
|
|
|
colonCount++;
|
|
|
|
|
}
|
|
|
|
|
if (colonCount <= 1)
|
|
|
|
|
{
|
|
|
|
|
// either ipv4 or host
|
|
|
|
|
portString = dStrchr(outAddress, ':');
|
|
|
|
|
|
|
|
|
|
if (portString)
|
|
|
|
|
{
|
|
|
|
|
*portString++ = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (outFamily == AF_UNSPEC)
|
|
|
|
|
{
|
|
|
|
|
// Must be ipv6
|
|
|
|
|
outFamily = AF_INET6;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (portString)
|
|
|
|
|
{
|
|
|
|
|
outPort = dAtoi(portString);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-12-17 23:08:43 +00:00
|
|
|
|
|
|
|
|
Net::Error getSocketAddress(SOCKET socketFd, int requiredFamily, NetAddress *outAddress)
|
|
|
|
|
{
|
|
|
|
|
Net::Error error = Net::UnknownError;
|
|
|
|
|
|
|
|
|
|
if (requiredFamily == AF_INET)
|
|
|
|
|
{
|
|
|
|
|
sockaddr_in ipAddr;
|
2016-12-26 20:19:53 +00:00
|
|
|
socklen_t len = sizeof(ipAddr);
|
2016-12-17 23:08:43 +00:00
|
|
|
if (getsockname(socketFd, (struct sockaddr*)&ipAddr, &len) >= 0)
|
|
|
|
|
{
|
|
|
|
|
IPSocketToNetAddress(&ipAddr, outAddress);
|
|
|
|
|
error = Net::NoError;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
error = getLastError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (requiredFamily == AF_INET6)
|
|
|
|
|
{
|
|
|
|
|
sockaddr_in6 ipAddr;
|
2016-12-26 20:19:53 +00:00
|
|
|
socklen_t len = sizeof(ipAddr);
|
2016-12-17 23:08:43 +00:00
|
|
|
if (getsockname(socketFd, (struct sockaddr*)&ipAddr, &len) >= 0)
|
|
|
|
|
{
|
|
|
|
|
IPSocket6ToNetAddress(&ipAddr, outAddress);
|
|
|
|
|
error = Net::NoError;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
error = getLastError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class T> NetSocket ReservedSocketList<T>::reserve(SOCKET reserveId, bool doLock)
|
|
|
|
|
{
|
|
|
|
|
MutexHandle handle;
|
|
|
|
|
if (doLock)
|
|
|
|
|
{
|
|
|
|
|
handle.lock(mMutex, true);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
S32 idx = mSocketList.find_next(EntryType());
|
2016-09-10 22:01:10 +00:00
|
|
|
if (idx == -1)
|
|
|
|
|
{
|
2016-10-28 17:31:47 +00:00
|
|
|
EntryType entry;
|
|
|
|
|
entry.value = reserveId;
|
|
|
|
|
entry.used = true;
|
|
|
|
|
mSocketList.push_back(entry);
|
2016-09-10 22:01:10 +00:00
|
|
|
return NetSocket::fromHandle(mSocketList.size() - 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-10-28 17:31:47 +00:00
|
|
|
EntryType &entry = mSocketList[idx];
|
|
|
|
|
entry.used = true;
|
|
|
|
|
entry.value = reserveId;
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NetSocket::fromHandle(idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class T> void ReservedSocketList<T>::remove(NetSocket socketToRemove, bool doLock)
|
|
|
|
|
{
|
|
|
|
|
MutexHandle handle;
|
|
|
|
|
if (doLock)
|
|
|
|
|
{
|
|
|
|
|
handle.lock(mMutex, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((U32)socketToRemove.getHandle() >= (U32)mSocketList.size())
|
|
|
|
|
return;
|
|
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
mSocketList[socketToRemove.getHandle()] = EntryType();
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class T> T ReservedSocketList<T>::activate(NetSocket socketToActivate, int family, bool useUDP, bool clearOnFail)
|
|
|
|
|
{
|
|
|
|
|
MutexHandle h;
|
|
|
|
|
h.lock(mMutex, true);
|
|
|
|
|
|
|
|
|
|
int typeID = useUDP ? SOCK_DGRAM : SOCK_STREAM;
|
|
|
|
|
int protocol = useUDP ? PlatformNetState::getDefaultGameProtocol() : 0;
|
|
|
|
|
|
|
|
|
|
if ((U32)socketToActivate.getHandle() >= (U32)mSocketList.size())
|
|
|
|
|
return -1;
|
|
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
EntryType &entry = mSocketList[socketToActivate.getHandle()];
|
|
|
|
|
if (!entry.used)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
T socketFd = entry.value;
|
2016-09-10 22:01:10 +00:00
|
|
|
if (socketFd == -1)
|
|
|
|
|
{
|
|
|
|
|
socketFd = ::socket(family, typeID, protocol);
|
|
|
|
|
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
{
|
|
|
|
|
if (clearOnFail)
|
|
|
|
|
{
|
|
|
|
|
remove(socketToActivate, false);
|
|
|
|
|
}
|
|
|
|
|
return InvalidSocketHandle;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-10-28 17:31:47 +00:00
|
|
|
entry.used = true;
|
|
|
|
|
entry.value = socketFd;
|
2016-09-10 22:01:10 +00:00
|
|
|
return socketFd;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return socketFd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class T> T ReservedSocketList<T>::resolve(NetSocket socketToResolve)
|
|
|
|
|
{
|
|
|
|
|
MutexHandle h;
|
|
|
|
|
h.lock(mMutex, true);
|
|
|
|
|
|
|
|
|
|
if ((U32)socketToResolve.getHandle() >= (U32)mSocketList.size())
|
|
|
|
|
return -1;
|
|
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
EntryType &entry = mSocketList[socketToResolve.getHandle()];
|
|
|
|
|
return entry.used ? entry.value : -1;
|
|
|
|
|
}
|
2017-01-05 22:23:48 +00:00
|
|
|
|
2017-01-06 23:41:47 +00:00
|
|
|
ConnectionNotifyEvent* Net::smConnectionNotify = NULL;
|
|
|
|
|
ConnectionAcceptedEvent* Net::smConnectionAccept = NULL;
|
|
|
|
|
ConnectionReceiveEvent* Net::smConnectionReceive = NULL;
|
|
|
|
|
PacketReceiveEvent* Net::smPacketReceive = NULL;
|
2016-10-28 17:31:47 +00:00
|
|
|
|
|
|
|
|
ConnectionNotifyEvent& Net::getConnectionNotifyEvent()
|
|
|
|
|
{
|
|
|
|
|
return *smConnectionNotify;
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
ConnectionAcceptedEvent& Net::getConnectionAcceptedEvent()
|
|
|
|
|
{
|
|
|
|
|
return *smConnectionAccept;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ConnectionReceiveEvent& Net::getConnectionReceiveEvent()
|
|
|
|
|
{
|
|
|
|
|
return *smConnectionReceive;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PacketReceiveEvent& Net::getPacketReceiveEvent()
|
|
|
|
|
{
|
|
|
|
|
return *smPacketReceive;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
// Multicast stuff
|
|
|
|
|
bool Net::smMulticastEnabled = true;
|
|
|
|
|
//
|
|
|
|
|
// Protocol Stuff
|
|
|
|
|
bool Net::smIpv4Enabled = true;
|
|
|
|
|
bool Net::smIpv6Enabled = false;
|
|
|
|
|
//
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
// the Socket structure helps us keep track of the
|
|
|
|
|
// above states
|
2016-09-10 22:01:10 +00:00
|
|
|
struct PolledSocket
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
// local enum for socket states for polled sockets
|
|
|
|
|
enum SocketState
|
|
|
|
|
{
|
|
|
|
|
InvalidState,
|
|
|
|
|
Connected,
|
|
|
|
|
ConnectionPending,
|
|
|
|
|
Listening,
|
|
|
|
|
NameLookupRequired
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PolledSocket()
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
fd = -1;
|
|
|
|
|
handleFd = NetSocket::INVALID;
|
2012-09-19 15:15:01 +00:00
|
|
|
state = InvalidState;
|
|
|
|
|
remoteAddr[0] = 0;
|
|
|
|
|
remotePort = -1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET fd;
|
|
|
|
|
NetSocket handleFd;
|
2012-09-19 15:15:01 +00:00
|
|
|
S32 state;
|
|
|
|
|
char remoteAddr[256];
|
|
|
|
|
S32 remotePort;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// list of polled sockets
|
2016-09-10 22:01:10 +00:00
|
|
|
static Vector<PolledSocket*> gPolledSockets( __FILE__, __LINE__ );
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
static PolledSocket* addPolledSocket(NetSocket handleFd, SOCKET fd, S32 state,
|
2012-09-19 15:15:01 +00:00
|
|
|
char* remoteAddr = NULL, S32 port = -1)
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
PolledSocket* sock = new PolledSocket();
|
2012-09-19 15:15:01 +00:00
|
|
|
sock->fd = fd;
|
2016-09-10 22:01:10 +00:00
|
|
|
sock->handleFd = handleFd;
|
2012-09-19 15:15:01 +00:00
|
|
|
sock->state = state;
|
|
|
|
|
if (remoteAddr)
|
2018-03-06 06:59:05 +00:00
|
|
|
dStrcpy(sock->remoteAddr, remoteAddr, 256);
|
2012-09-19 15:15:01 +00:00
|
|
|
if (port != -1)
|
|
|
|
|
sock->remotePort = port;
|
|
|
|
|
gPolledSockets.push_back(sock);
|
|
|
|
|
return sock;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
bool netSocketWaitForWritable(NetSocket handleFd, S32 timeoutMs)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
fd_set writefds;
|
|
|
|
|
timeval timeout;
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
FD_ZERO( &writefds );
|
|
|
|
|
FD_SET( socketFd, &writefds );
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
timeout.tv_sec = timeoutMs / 1000;
|
|
|
|
|
timeout.tv_usec = ( timeoutMs % 1000 ) * 1000;
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
if( select(socketFd + 1, NULL, &writefds, NULL, &timeout) > 0 )
|
2012-09-19 15:15:01 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Net::init()
|
|
|
|
|
{
|
|
|
|
|
#if defined(TORQUE_USE_WINSOCK)
|
2016-09-10 22:01:10 +00:00
|
|
|
if(!PlatformNetState::initCount)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
WSADATA stWSAData;
|
|
|
|
|
AssertISV( !WSAStartup( 0x0101, &stWSAData ), "Net::init - failed to init WinSock!" );
|
|
|
|
|
|
|
|
|
|
//logprintf("Winsock initialization %s", success ? "succeeded." : "failed!");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2016-09-10 22:01:10 +00:00
|
|
|
PlatformNetState::initCount++;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
smConnectionNotify = new ConnectionNotifyEvent();
|
|
|
|
|
smConnectionAccept = new ConnectionAcceptedEvent();
|
|
|
|
|
smConnectionReceive = new ConnectionReceiveEvent();
|
|
|
|
|
smPacketReceive = new PacketReceiveEvent();
|
|
|
|
|
|
|
|
|
|
|
2012-09-19 15:15:01 +00:00
|
|
|
Process::notify(&Net::process, PROCESS_NET_ORDER);
|
|
|
|
|
|
|
|
|
|
return(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Net::shutdown()
|
|
|
|
|
{
|
|
|
|
|
Process::remove(&Net::process);
|
|
|
|
|
|
|
|
|
|
while (gPolledSockets.size() > 0)
|
2016-10-28 18:34:01 +00:00
|
|
|
{
|
|
|
|
|
if (gPolledSockets[0] == NULL)
|
|
|
|
|
gPolledSockets.erase(gPolledSockets.begin());
|
|
|
|
|
else
|
|
|
|
|
closeConnectTo(gPolledSockets[0]->handleFd);
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
closePort();
|
2016-09-10 22:01:10 +00:00
|
|
|
PlatformNetState::initCount--;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
// Destroy event handlers
|
|
|
|
|
delete smConnectionNotify;
|
|
|
|
|
delete smConnectionAccept;
|
|
|
|
|
delete smConnectionReceive;
|
|
|
|
|
delete smPacketReceive;
|
|
|
|
|
|
2012-09-19 15:15:01 +00:00
|
|
|
#if defined(TORQUE_USE_WINSOCK)
|
2016-09-10 22:01:10 +00:00
|
|
|
if(!PlatformNetState::initCount)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
WSACleanup();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
// ipv4 version of name routines
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
static void NetAddressToIPSocket(const NetAddress *address, struct sockaddr_in *sockAddr)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
dMemset(sockAddr, 0, sizeof(struct sockaddr_in));
|
|
|
|
|
sockAddr->sin_family = AF_INET;
|
|
|
|
|
sockAddr->sin_port = htons(address->port);
|
2016-10-28 18:34:01 +00:00
|
|
|
#if defined(TORQUE_OS_BSD) || defined(TORQUE_OS_MAC)
|
2016-09-10 22:01:10 +00:00
|
|
|
sockAddr->sin_len = sizeof(struct sockaddr_in);
|
|
|
|
|
#endif
|
|
|
|
|
if (address->type == NetAddress::IPBroadcastAddress)
|
|
|
|
|
{
|
|
|
|
|
sockAddr->sin_addr.s_addr = htonl(INADDR_BROADCAST);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dMemcpy(&sockAddr->sin_addr, &address->address.ipv4.netNum[0], 4);
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
static void IPSocketToNetAddress(const struct sockaddr_in *sockAddr, NetAddress *address)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
address->type = NetAddress::IPAddress;
|
2016-09-10 22:01:10 +00:00
|
|
|
address->port = ntohs(sockAddr->sin_port);
|
|
|
|
|
dMemcpy(&address->address.ipv4.netNum[0], &sockAddr->sin_addr, 4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ipv6 version of name routines
|
|
|
|
|
|
|
|
|
|
static void NetAddressToIPSocket6(const NetAddress *address, struct sockaddr_in6 *sockAddr)
|
|
|
|
|
{
|
|
|
|
|
dMemset(sockAddr, 0, sizeof(struct sockaddr_in6));
|
|
|
|
|
#ifdef SIN6_LEN
|
|
|
|
|
sockAddr->sin6_len = sizeof(struct sockaddr_in6);
|
2012-09-19 15:15:01 +00:00
|
|
|
#endif
|
2016-09-10 22:01:10 +00:00
|
|
|
sockAddr->sin6_family = AF_INET6;
|
|
|
|
|
sockAddr->sin6_port = ntohs(address->port);
|
|
|
|
|
|
|
|
|
|
if (address->type == NetAddress::IPV6MulticastAddress)
|
|
|
|
|
{
|
|
|
|
|
sockAddr->sin6_addr = PlatformNetState::multicast6Group.ipv6mr_multiaddr;
|
|
|
|
|
sockAddr->sin6_scope_id = PlatformNetState::multicast6Group.ipv6mr_interface;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sockAddr->sin6_flowinfo = address->address.ipv6.netFlow;
|
|
|
|
|
sockAddr->sin6_scope_id = address->address.ipv6.netScope;
|
|
|
|
|
dMemcpy(&sockAddr->sin6_addr, address->address.ipv6.netNum, sizeof(address->address.ipv6.netNum));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void IPSocket6ToNetAddress(const struct sockaddr_in6 *sockAddr, NetAddress *address)
|
|
|
|
|
{
|
|
|
|
|
address->type = NetAddress::IPV6Address;
|
|
|
|
|
address->port = ntohs(sockAddr->sin6_port);
|
|
|
|
|
dMemcpy(address->address.ipv6.netNum, &sockAddr->sin6_addr, sizeof(address->address.ipv6.netNum));
|
|
|
|
|
address->address.ipv6.netFlow = sockAddr->sin6_flowinfo;
|
|
|
|
|
address->address.ipv6.netScope = sockAddr->sin6_scope_id;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
|
|
NetSocket Net::openListenPort(U16 port, NetAddress::Type addressType)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
if(Journal::IsPlaying())
|
|
|
|
|
{
|
|
|
|
|
U32 ret;
|
|
|
|
|
Journal::Read(&ret);
|
2016-09-10 22:01:10 +00:00
|
|
|
return NetSocket::fromHandle(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Net::Error error = NoError;
|
|
|
|
|
NetAddress address;
|
2016-10-28 17:31:47 +00:00
|
|
|
if (Net::getListenAddress(addressType, &address) != Net::NoError)
|
2016-09-10 22:01:10 +00:00
|
|
|
error = Net::WrongProtocolType;
|
|
|
|
|
|
|
|
|
|
NetSocket handleFd = NetSocket::INVALID;
|
|
|
|
|
SOCKET sockId = InvalidSocketHandle;
|
|
|
|
|
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
{
|
|
|
|
|
handleFd = openSocket();
|
|
|
|
|
sockId = PlatformNetState::smReservedSocketList.activate(handleFd, address.type == NetAddress::IPAddress ? AF_INET : AF_INET6, false, true);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
if (error == NoError && (handleFd == NetSocket::INVALID || sockId == InvalidSocketHandle))
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
Con::errorf("Unable to open listen socket: %s", strerror(errno));
|
2016-09-10 22:01:10 +00:00
|
|
|
error = NotASocket;
|
|
|
|
|
handleFd = NetSocket::INVALID;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
if (error == NoError)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
address.port = port;
|
|
|
|
|
error = bindAddress(address, handleFd, false);
|
|
|
|
|
if (error != NoError)
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("Unable to bind port %d: %s", port, strerror(errno));
|
|
|
|
|
closeSocket(handleFd);
|
|
|
|
|
handleFd = NetSocket::INVALID;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
|
|
|
|
|
if (error == NoError)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
error = listen(handleFd, 4);
|
|
|
|
|
if (error != NoError)
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("Unable to listen on port %d: %s", port, strerror(errno));
|
|
|
|
|
closeSocket(handleFd);
|
|
|
|
|
handleFd = NetSocket::INVALID;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
if (error == NoError)
|
|
|
|
|
{
|
|
|
|
|
setBlocking(handleFd, false);
|
|
|
|
|
addPolledSocket(handleFd, sockId, PolledSocket::Listening);
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
if(Journal::IsRecording())
|
2016-09-10 22:01:10 +00:00
|
|
|
Journal::Write(U32(handleFd.getHandle()));
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
return handleFd;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetSocket Net::openConnectTo(const char *addressString)
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if (Journal::IsPlaying())
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
U32 ret;
|
|
|
|
|
Journal::Read(&ret);
|
|
|
|
|
return NetSocket::fromHandle(ret);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
NetAddress address;
|
|
|
|
|
NetSocket handleFd = NetSocket::INVALID;
|
|
|
|
|
Net::Error error = NoError;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
error = Net::stringToAddress(addressString, &address, false);
|
|
|
|
|
|
|
|
|
|
if (error == NoError && address.type != NetAddress::IPAddress && address.type != NetAddress::IPV6Address)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
error = Net::WrongProtocolType;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2017-04-12 22:54:59 +00:00
|
|
|
// Open socket
|
2017-02-22 18:27:08 +00:00
|
|
|
if (error == NoError || error == NeedHostLookup)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
handleFd = openSocket();
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
// Attempt to connect or queue a lookup
|
|
|
|
|
if (error == NoError && address.type == NetAddress::IPAddress)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
sockaddr_in ipAddr;
|
|
|
|
|
NetAddressToIPSocket(&address, &ipAddr);
|
|
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET, false, true);
|
|
|
|
|
if (socketFd != InvalidSocketHandle)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
setBlocking(handleFd, false);
|
2017-02-22 18:27:08 +00:00
|
|
|
if (::connect(socketFd, (struct sockaddr *)&ipAddr, sizeof(ipAddr)) == -1)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2017-02-22 18:27:08 +00:00
|
|
|
Net::Error err = PlatformNetState::getLastError();
|
|
|
|
|
if (err != Net::WouldBlock)
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("Error connecting to %s: %u",
|
|
|
|
|
addressString, err);
|
|
|
|
|
closeSocket(handleFd);
|
|
|
|
|
handleFd = NetSocket::INVALID;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PlatformNetState::smReservedSocketList.remove(handleFd);
|
|
|
|
|
handleFd = NetSocket::INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (handleFd != NetSocket::INVALID)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
// add this socket to our list of polled sockets
|
2016-09-10 22:01:10 +00:00
|
|
|
addPolledSocket(handleFd, socketFd, PolledSocket::ConnectionPending);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
else if (error == NoError && address.type == NetAddress::IPV6Address)
|
|
|
|
|
{
|
|
|
|
|
sockaddr_in6 ipAddr6;
|
|
|
|
|
NetAddressToIPSocket6(&address, &ipAddr6);
|
|
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET6, false, true);
|
2017-02-22 18:27:08 +00:00
|
|
|
if (socketFd != InvalidSocketHandle)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
setBlocking(handleFd, false);
|
2017-02-22 18:27:08 +00:00
|
|
|
if (::connect(socketFd, (struct sockaddr *)&ipAddr6, sizeof(ipAddr6)) == -1)
|
|
|
|
|
{
|
|
|
|
|
Net::Error err = PlatformNetState::getLastError();
|
|
|
|
|
if (err != Net::WouldBlock)
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("Error connecting to %s: %u",
|
|
|
|
|
addressString, err);
|
|
|
|
|
closeSocket(handleFd);
|
|
|
|
|
handleFd = NetSocket::INVALID;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PlatformNetState::smReservedSocketList.remove(handleFd);
|
|
|
|
|
handleFd = NetSocket::INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (handleFd != NetSocket::INVALID)
|
|
|
|
|
{
|
|
|
|
|
// add this socket to our list of polled sockets
|
|
|
|
|
addPolledSocket(handleFd, socketFd, PolledSocket::ConnectionPending);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (error == Net::NeedHostLookup)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
// need to do an asynchronous name lookup. first, add the socket
|
|
|
|
|
// to the polled list
|
2016-10-28 17:31:47 +00:00
|
|
|
char addr[256];
|
|
|
|
|
int port = 0;
|
|
|
|
|
int actualFamily = AF_UNSPEC;
|
|
|
|
|
if (PlatformNetState::extractAddressParts(addressString, addr, port, actualFamily))
|
|
|
|
|
{
|
|
|
|
|
addPolledSocket(handleFd, InvalidSocketHandle, PolledSocket::NameLookupRequired, addr, port);
|
|
|
|
|
// queue the lookup
|
|
|
|
|
gNetAsync.queueLookup(addressString, handleFd);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
closeSocket(handleFd);
|
|
|
|
|
handleFd = NetSocket::INVALID;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
else
|
|
|
|
|
{
|
2016-10-28 17:31:47 +00:00
|
|
|
closeSocket(handleFd);
|
2016-09-10 22:01:10 +00:00
|
|
|
handleFd = NetSocket::INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Journal::IsRecording())
|
|
|
|
|
Journal::Write(U32(handleFd.getHandle()));
|
|
|
|
|
return handleFd;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
void Net::closeConnectTo(NetSocket handleFd)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
if(Journal::IsPlaying())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// if this socket is in the list of polled sockets, remove it
|
2013-08-04 21:26:01 +00:00
|
|
|
for (S32 i = 0; i < gPolledSockets.size(); ++i)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-10-28 18:34:01 +00:00
|
|
|
if (gPolledSockets[i] && gPolledSockets[i]->handleFd == handleFd)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
delete gPolledSockets[i];
|
2016-10-28 18:34:01 +00:00
|
|
|
gPolledSockets[i] = NULL;
|
2012-09-19 15:15:01 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
closeSocket(handleFd);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
Net::Error Net::sendtoSocket(NetSocket handleFd, const U8 *buffer, S32 bufferSize, S32 *outBufferWritten)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
if(Journal::IsPlaying())
|
|
|
|
|
{
|
|
|
|
|
U32 e;
|
2016-10-28 17:31:47 +00:00
|
|
|
S32 outBytes;
|
2012-09-19 15:15:01 +00:00
|
|
|
Journal::Read(&e);
|
2016-10-28 17:31:47 +00:00
|
|
|
Journal::Read(&outBytes);
|
|
|
|
|
if (outBufferWritten)
|
|
|
|
|
*outBufferWritten = outBytes;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
return (Net::Error) e;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
S32 outBytes = 0;
|
|
|
|
|
Net::Error e = send(handleFd, buffer, bufferSize, &outBytes);
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
if (Journal::IsRecording())
|
|
|
|
|
{
|
2012-09-19 15:15:01 +00:00
|
|
|
Journal::Write(U32(e));
|
2016-10-28 17:31:47 +00:00
|
|
|
Journal::Write(outBytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (outBufferWritten)
|
|
|
|
|
*outBufferWritten = outBytes;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Net::openPort(S32 port, bool doBind)
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if (PlatformNetState::udpSocket != NetSocket::INVALID)
|
|
|
|
|
{
|
|
|
|
|
closeSocket(PlatformNetState::udpSocket);
|
|
|
|
|
PlatformNetState::udpSocket = NetSocket::INVALID;
|
|
|
|
|
}
|
|
|
|
|
if (PlatformNetState::udp6Socket != NetSocket::INVALID)
|
|
|
|
|
{
|
|
|
|
|
closeSocket(PlatformNetState::udp6Socket);
|
|
|
|
|
PlatformNetState::udp6Socket = NetSocket::INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update prefs
|
|
|
|
|
Net::smMulticastEnabled = Con::getBoolVariable("pref::Net::Multicast6Enabled", true);
|
|
|
|
|
Net::smIpv4Enabled = Con::getBoolVariable("pref::Net::IPV4Enabled", true);
|
|
|
|
|
Net::smIpv6Enabled = Con::getBoolVariable("pref::Net::IPV6Enabled", false);
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
// we turn off VDP in non-release builds because VDP does not support broadcast packets
|
|
|
|
|
// which are required for LAN queries (PC->Xbox connectivity). The wire protocol still
|
|
|
|
|
// uses the VDP packet structure, though.
|
2016-09-10 22:01:10 +00:00
|
|
|
S32 protocol = PlatformNetState::getDefaultGameProtocol();
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd = InvalidSocketHandle;
|
|
|
|
|
NetAddress address;
|
2016-12-17 23:08:43 +00:00
|
|
|
NetAddress listenAddress;
|
|
|
|
|
char listenAddressStr[256];
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
if (Net::smIpv4Enabled)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-10-28 17:31:47 +00:00
|
|
|
if (Net::getListenAddress(NetAddress::IPAddress, &address) == Net::NoError)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
address.port = port;
|
|
|
|
|
socketFd = ::socket(AF_INET, SOCK_DGRAM, protocol);
|
|
|
|
|
|
|
|
|
|
if (socketFd != InvalidSocketHandle)
|
|
|
|
|
{
|
|
|
|
|
PlatformNetState::udpSocket = PlatformNetState::smReservedSocketList.reserve(socketFd);
|
|
|
|
|
Net::Error error = NoError;
|
|
|
|
|
if (doBind)
|
|
|
|
|
{
|
|
|
|
|
error = bindAddress(address, PlatformNetState::udpSocket, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
error = setBufferSize(PlatformNetState::udpSocket, 32768 * 8);
|
|
|
|
|
|
|
|
|
|
#ifndef TORQUE_DISABLE_PC_CONNECTIVITY
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
error = setBroadcast(PlatformNetState::udpSocket, true);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
error = setBlocking(PlatformNetState::udpSocket, false);
|
2016-12-17 23:08:43 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
if (error == NoError)
|
|
|
|
|
{
|
2016-12-17 23:08:43 +00:00
|
|
|
error = PlatformNetState::getSocketAddress(socketFd, AF_INET, &listenAddress);
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
{
|
|
|
|
|
Net::addressToString(&listenAddress, listenAddressStr);
|
|
|
|
|
Con::printf("UDP initialized on ipv4 %s", listenAddressStr);
|
|
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
2016-12-17 23:08:43 +00:00
|
|
|
|
|
|
|
|
if (error != NoError)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
closeSocket(PlatformNetState::udpSocket);
|
|
|
|
|
PlatformNetState::udpSocket = NetSocket::INVALID;
|
|
|
|
|
Con::printf("Unable to initialize UDP on ipv4 - error %d", error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
else
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
Con::errorf("Unable to initialize UDP on ipv4 - invalid address.");
|
|
|
|
|
PlatformNetState::udpSocket = NetSocket::INVALID;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
|
|
|
|
|
if (Net::smIpv6Enabled)
|
|
|
|
|
{
|
2016-10-28 17:31:47 +00:00
|
|
|
if (Net::getListenAddress(NetAddress::IPV6Address, &address) == Net::NoError)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
address.port = port;
|
|
|
|
|
socketFd = ::socket(AF_INET6, SOCK_DGRAM, protocol);
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
if (socketFd != InvalidSocketHandle)
|
|
|
|
|
{
|
|
|
|
|
PlatformNetState::udp6Socket = PlatformNetState::smReservedSocketList.reserve(socketFd);
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
Net::Error error = NoError;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
int v = 1;
|
|
|
|
|
setsockopt(socketFd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&v, sizeof(v));
|
|
|
|
|
PlatformNetState::getLastError();
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
if (doBind)
|
|
|
|
|
{
|
|
|
|
|
error = bindAddress(address, PlatformNetState::udp6Socket, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
error = setBufferSize(PlatformNetState::udp6Socket, 32768 * 8);
|
|
|
|
|
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
error = setBlocking(PlatformNetState::udp6Socket, false);
|
|
|
|
|
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
{
|
2016-12-17 23:08:43 +00:00
|
|
|
error = PlatformNetState::getSocketAddress(socketFd, AF_INET6, &listenAddress);
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
{
|
|
|
|
|
Net::addressToString(&listenAddress, listenAddressStr);
|
|
|
|
|
Con::printf("UDP initialized on ipv6 %s", listenAddressStr);
|
|
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
2016-12-17 23:08:43 +00:00
|
|
|
|
|
|
|
|
if (error != NoError)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
closeSocket(PlatformNetState::udp6Socket);
|
|
|
|
|
PlatformNetState::udp6Socket = NetSocket::INVALID;
|
|
|
|
|
Con::printf("Unable to initialize UDP on ipv6 - error %d", error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Net::smMulticastEnabled && doBind)
|
|
|
|
|
{
|
|
|
|
|
Net::enableMulticast();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Net::disableMulticast();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
PlatformNetState::netPort = port;
|
|
|
|
|
|
|
|
|
|
return PlatformNetState::udpSocket != NetSocket::INVALID || PlatformNetState::udp6Socket != NetSocket::INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetSocket Net::getPort()
|
|
|
|
|
{
|
|
|
|
|
return PlatformNetState::udpSocket;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
void Net::closePort()
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if (PlatformNetState::udpSocket != NetSocket::INVALID)
|
|
|
|
|
closeSocket(PlatformNetState::udpSocket);
|
|
|
|
|
if (PlatformNetState::udp6Socket != NetSocket::INVALID)
|
|
|
|
|
closeSocket(PlatformNetState::udp6Socket);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Net::Error Net::sendto(const NetAddress *address, const U8 *buffer, S32 bufferSize)
|
|
|
|
|
{
|
|
|
|
|
if(Journal::IsPlaying())
|
|
|
|
|
return NoError;
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd;
|
|
|
|
|
|
|
|
|
|
if(address->type == NetAddress::IPAddress || address->type == NetAddress::IPBroadcastAddress)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
socketFd = PlatformNetState::smReservedSocketList.resolve(PlatformNetState::udpSocket);
|
|
|
|
|
if (socketFd != InvalidSocketHandle)
|
|
|
|
|
{
|
|
|
|
|
sockaddr_in ipAddr;
|
|
|
|
|
NetAddressToIPSocket(address, &ipAddr);
|
|
|
|
|
|
|
|
|
|
if (::sendto(socketFd, (const char*)buffer, bufferSize, 0,
|
|
|
|
|
(sockaddr *)&ipAddr, sizeof(sockaddr_in)) == SOCKET_ERROR)
|
|
|
|
|
return PlatformNetState::getLastError();
|
|
|
|
|
else
|
|
|
|
|
return NoError;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
else
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
return NotASocket;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
else if (address->type == NetAddress::IPV6Address || address->type == NetAddress::IPV6MulticastAddress)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
socketFd = PlatformNetState::smReservedSocketList.resolve(address->type == NetAddress::IPV6MulticastAddress ? PlatformNetState::multicast6Socket : PlatformNetState::udp6Socket);
|
|
|
|
|
|
|
|
|
|
if (socketFd != InvalidSocketHandle)
|
|
|
|
|
{
|
|
|
|
|
sockaddr_in6 ipAddr;
|
|
|
|
|
NetAddressToIPSocket6(address, &ipAddr);
|
|
|
|
|
if (::sendto(socketFd, (const char*)buffer, bufferSize, 0,
|
|
|
|
|
(struct sockaddr *) &ipAddr, sizeof(sockaddr_in6)) == SOCKET_ERROR)
|
|
|
|
|
return PlatformNetState::getLastError();
|
|
|
|
|
else
|
|
|
|
|
return NoError;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
else
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
return NotASocket;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
|
|
|
|
|
return WrongProtocolType;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Net::process()
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
// Process listening sockets
|
|
|
|
|
processListenSocket(PlatformNetState::udpSocket);
|
|
|
|
|
processListenSocket(PlatformNetState::udp6Socket);
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
// process the polled sockets. This blob of code performs functions
|
|
|
|
|
// similar to WinsockProc in winNet.cc
|
|
|
|
|
|
|
|
|
|
if (gPolledSockets.size() == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
S32 optval;
|
|
|
|
|
socklen_t optlen = sizeof(S32);
|
|
|
|
|
S32 bytesRead;
|
|
|
|
|
Net::Error err;
|
|
|
|
|
bool removeSock = false;
|
2016-09-10 22:01:10 +00:00
|
|
|
PolledSocket *currentSock = NULL;
|
|
|
|
|
NetSocket incomingHandleFd = NetSocket::INVALID;
|
|
|
|
|
NetAddress out_h_addr;
|
2013-08-04 21:26:01 +00:00
|
|
|
S32 out_h_length = 0;
|
2012-09-19 15:15:01 +00:00
|
|
|
RawData readBuff;
|
2016-10-28 18:34:01 +00:00
|
|
|
NetSocket removeSockHandle;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
for (S32 i = 0; i < gPolledSockets.size();
|
|
|
|
|
/* no increment, this is done at end of loop body */)
|
|
|
|
|
{
|
|
|
|
|
removeSock = false;
|
|
|
|
|
currentSock = gPolledSockets[i];
|
2016-10-28 18:34:01 +00:00
|
|
|
|
|
|
|
|
// Cleanup if we've removed it
|
|
|
|
|
if (currentSock == NULL)
|
|
|
|
|
{
|
|
|
|
|
gPolledSockets.erase(i);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-19 15:15:01 +00:00
|
|
|
switch (currentSock->state)
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
case PolledSocket::InvalidState:
|
2012-09-19 15:15:01 +00:00
|
|
|
Con::errorf("Error, InvalidState socket in polled sockets list");
|
|
|
|
|
break;
|
2016-09-10 22:01:10 +00:00
|
|
|
case PolledSocket::ConnectionPending:
|
2012-09-19 15:15:01 +00:00
|
|
|
// see if it is now connected
|
|
|
|
|
if (getsockopt(currentSock->fd, SOL_SOCKET, SO_ERROR,
|
|
|
|
|
(char*)&optval, &optlen) == -1)
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("Error getting socket options: %s", strerror(errno));
|
2016-10-28 18:34:01 +00:00
|
|
|
|
|
|
|
|
removeSock = true;
|
|
|
|
|
removeSockHandle = currentSock->handleFd;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
smConnectionNotify->trigger(currentSock->handleFd, Net::ConnectFailed);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (optval == EINPROGRESS)
|
|
|
|
|
// still connecting...
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (optval == 0)
|
|
|
|
|
{
|
|
|
|
|
// poll for writable status to be sure we're connected.
|
2016-09-10 22:01:10 +00:00
|
|
|
bool ready = netSocketWaitForWritable(currentSock->handleFd,0);
|
2012-09-19 15:15:01 +00:00
|
|
|
if(!ready)
|
|
|
|
|
break;
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
currentSock->state = PolledSocket::Connected;
|
2016-10-28 17:31:47 +00:00
|
|
|
smConnectionNotify->trigger(currentSock->handleFd, Net::Connected);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// some kind of error
|
|
|
|
|
Con::errorf("Error connecting: %s", strerror(errno));
|
2016-10-28 18:34:01 +00:00
|
|
|
|
2012-09-19 15:15:01 +00:00
|
|
|
removeSock = true;
|
2016-10-28 18:34:01 +00:00
|
|
|
removeSockHandle = currentSock->handleFd;
|
|
|
|
|
|
|
|
|
|
smConnectionNotify->trigger(currentSock->handleFd, Net::ConnectFailed);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-09-10 22:01:10 +00:00
|
|
|
case PolledSocket::Connected:
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
// try to get some data
|
|
|
|
|
bytesRead = 0;
|
|
|
|
|
readBuff.alloc(MaxPacketDataSize);
|
2016-09-10 22:01:10 +00:00
|
|
|
err = Net::recv(currentSock->handleFd, (U8*)readBuff.data, MaxPacketDataSize, &bytesRead);
|
2012-09-19 15:15:01 +00:00
|
|
|
if(err == Net::NoError)
|
|
|
|
|
{
|
|
|
|
|
if (bytesRead > 0)
|
|
|
|
|
{
|
|
|
|
|
// got some data, post it
|
|
|
|
|
readBuff.size = bytesRead;
|
2016-10-28 17:31:47 +00:00
|
|
|
smConnectionReceive->trigger(currentSock->handleFd, readBuff);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// ack! this shouldn't happen
|
|
|
|
|
if (bytesRead < 0)
|
|
|
|
|
Con::errorf("Unexpected error on socket: %s", strerror(errno));
|
2016-10-28 18:34:01 +00:00
|
|
|
|
|
|
|
|
removeSock = true;
|
|
|
|
|
removeSockHandle = currentSock->handleFd;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
|
|
|
|
// zero bytes read means EOF
|
2016-10-28 17:31:47 +00:00
|
|
|
smConnectionNotify->trigger(currentSock->handleFd, Net::Disconnected);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (err != Net::NoError && err != Net::WouldBlock)
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("Error reading from socket: %s", strerror(errno));
|
2016-10-28 18:34:01 +00:00
|
|
|
|
2012-09-19 15:15:01 +00:00
|
|
|
removeSock = true;
|
2016-10-28 18:34:01 +00:00
|
|
|
removeSockHandle = currentSock->handleFd;
|
|
|
|
|
|
|
|
|
|
smConnectionNotify->trigger(currentSock->handleFd, Net::Disconnected);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
break;
|
2016-09-10 22:01:10 +00:00
|
|
|
case PolledSocket::NameLookupRequired:
|
|
|
|
|
U32 newState;
|
|
|
|
|
|
2012-09-19 15:15:01 +00:00
|
|
|
// is the lookup complete?
|
|
|
|
|
if (!gNetAsync.checkLookup(
|
2016-09-10 22:01:10 +00:00
|
|
|
currentSock->handleFd, &out_h_addr, &out_h_length,
|
2012-09-19 15:15:01 +00:00
|
|
|
sizeof(out_h_addr)))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (out_h_length == -1)
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
Con::errorf("DNS lookup failed: %s", currentSock->remoteAddr);
|
2012-09-19 15:15:01 +00:00
|
|
|
newState = Net::DNSFailed;
|
|
|
|
|
removeSock = true;
|
2016-10-28 18:34:01 +00:00
|
|
|
removeSockHandle = currentSock->handleFd;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// try to connect
|
2016-09-10 22:01:10 +00:00
|
|
|
out_h_addr.port = currentSock->remotePort;
|
|
|
|
|
const sockaddr *ai_addr = NULL;
|
|
|
|
|
int ai_addrlen = 0;
|
|
|
|
|
sockaddr_in socketAddress;
|
|
|
|
|
sockaddr_in6 socketAddress6;
|
|
|
|
|
|
|
|
|
|
if (out_h_addr.type == NetAddress::IPAddress)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
ai_addr = (const sockaddr*)&socketAddress;
|
|
|
|
|
ai_addrlen = sizeof(socketAddress);
|
|
|
|
|
NetAddressToIPSocket(&out_h_addr, &socketAddress);
|
|
|
|
|
|
|
|
|
|
currentSock->fd = PlatformNetState::smReservedSocketList.activate(currentSock->handleFd, AF_INET, false);
|
|
|
|
|
setBlocking(currentSock->handleFd, false);
|
|
|
|
|
|
|
|
|
|
#ifdef TORQUE_DEBUG_LOOKUPS
|
|
|
|
|
char addrString[256];
|
|
|
|
|
NetAddress addr;
|
|
|
|
|
IPSocketToNetAddress(&socketAddress, &addr);
|
|
|
|
|
Net::addressToString(&addr, addrString);
|
|
|
|
|
Con::printf("DNS: lookup resolved to %s", addrString);
|
2012-09-19 15:15:01 +00:00
|
|
|
#endif
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
else if (out_h_addr.type == NetAddress::IPV6Address)
|
|
|
|
|
{
|
|
|
|
|
ai_addr = (const sockaddr*)&socketAddress6;
|
|
|
|
|
ai_addrlen = sizeof(socketAddress6);
|
|
|
|
|
NetAddressToIPSocket6(&out_h_addr, &socketAddress6);
|
|
|
|
|
|
|
|
|
|
currentSock->fd = PlatformNetState::smReservedSocketList.activate(currentSock->handleFd, AF_INET6, false);
|
|
|
|
|
setBlocking(currentSock->handleFd, false);
|
|
|
|
|
|
|
|
|
|
#ifdef TORQUE_DEBUG_LOOKUPS
|
|
|
|
|
char addrString[256];
|
|
|
|
|
NetAddress addr;
|
|
|
|
|
IPSocket6ToNetAddress(&socketAddress6, &addr);
|
|
|
|
|
Net::addressToString(&addr, addrString);
|
|
|
|
|
Con::printf("DNS: lookup resolved to %s", addrString);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Con::errorf("Error connecting to %s: Invalid Protocol",
|
|
|
|
|
currentSock->remoteAddr);
|
|
|
|
|
newState = Net::ConnectFailed;
|
|
|
|
|
removeSock = true;
|
2016-10-28 18:34:01 +00:00
|
|
|
removeSockHandle = currentSock->handleFd;
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ai_addr)
|
|
|
|
|
{
|
|
|
|
|
if (::connect(currentSock->fd, ai_addr,
|
|
|
|
|
ai_addrlen) == -1)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-10-28 17:31:47 +00:00
|
|
|
err = PlatformNetState::getLastError();
|
|
|
|
|
if (err != Net::WouldBlock)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
2016-10-28 17:31:47 +00:00
|
|
|
Con::errorf("Error connecting to %s: %u",
|
|
|
|
|
currentSock->remoteAddr, err);
|
|
|
|
|
newState = Net::ConnectFailed;
|
|
|
|
|
removeSock = true;
|
2016-10-28 18:34:01 +00:00
|
|
|
removeSockHandle = currentSock->handleFd;
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-10-28 17:31:47 +00:00
|
|
|
newState = Net::DNSResolved;
|
|
|
|
|
currentSock->state = PolledSocket::ConnectionPending;
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
newState = Net::Connected;
|
|
|
|
|
currentSock->state = Connected;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
smConnectionNotify->trigger(currentSock->handleFd, newState);
|
2012-09-19 15:15:01 +00:00
|
|
|
break;
|
2016-09-10 22:01:10 +00:00
|
|
|
case PolledSocket::Listening:
|
2012-09-19 15:15:01 +00:00
|
|
|
NetAddress incomingAddy;
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
incomingHandleFd = Net::accept(currentSock->handleFd, &incomingAddy);
|
|
|
|
|
if(incomingHandleFd != NetSocket::INVALID)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
setBlocking(incomingHandleFd, false);
|
|
|
|
|
addPolledSocket(incomingHandleFd, PlatformNetState::smReservedSocketList.resolve(incomingHandleFd), Connected);
|
2016-10-28 17:31:47 +00:00
|
|
|
smConnectionAccept->trigger(currentSock->handleFd, incomingHandleFd, incomingAddy);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// only increment index if we're not removing the connection, since
|
|
|
|
|
// the removal will shift the indices down by one
|
|
|
|
|
if (removeSock)
|
2016-10-28 18:34:01 +00:00
|
|
|
closeConnectTo(removeSockHandle);
|
2012-09-19 15:15:01 +00:00
|
|
|
else
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
void Net::processListenSocket(NetSocket socketHandle)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if (socketHandle == NetSocket::INVALID)
|
|
|
|
|
return;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
sockaddr_storage sa;
|
|
|
|
|
sa.ss_family = AF_UNSPEC;
|
|
|
|
|
NetAddress srcAddress;
|
|
|
|
|
RawData tmpBuffer;
|
|
|
|
|
tmpBuffer.alloc(Net::MaxPacketDataSize);
|
|
|
|
|
|
|
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(socketHandle);
|
|
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
socklen_t addrLen = sizeof(sa);
|
|
|
|
|
S32 bytesRead = -1;
|
|
|
|
|
|
|
|
|
|
if (socketHandle != NetSocket::INVALID)
|
|
|
|
|
bytesRead = ::recvfrom(socketFd, (char *)tmpBuffer.data, Net::MaxPacketDataSize, 0, (struct sockaddr*)&sa, &addrLen);
|
|
|
|
|
|
|
|
|
|
if (bytesRead == -1)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (sa.ss_family == AF_INET)
|
|
|
|
|
IPSocketToNetAddress((sockaddr_in *)&sa, &srcAddress);
|
|
|
|
|
else if (sa.ss_family == AF_INET6)
|
|
|
|
|
IPSocket6ToNetAddress((sockaddr_in6 *)&sa, &srcAddress);
|
|
|
|
|
else
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (bytesRead <= 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (srcAddress.type == NetAddress::IPAddress &&
|
|
|
|
|
srcAddress.address.ipv4.netNum[0] == 127 &&
|
|
|
|
|
srcAddress.address.ipv4.netNum[1] == 0 &&
|
|
|
|
|
srcAddress.address.ipv4.netNum[2] == 0 &&
|
|
|
|
|
srcAddress.address.ipv4.netNum[3] == 1 &&
|
|
|
|
|
srcAddress.port == PlatformNetState::netPort)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
tmpBuffer.size = bytesRead;
|
|
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
smPacketReceive->trigger(srcAddress, tmpBuffer);
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetSocket Net::openSocket()
|
|
|
|
|
{
|
|
|
|
|
return PlatformNetState::smReservedSocketList.reserve();
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
Net::Error Net::closeSocket(NetSocket handleFd)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if(handleFd != NetSocket::INVALID)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
|
|
|
|
PlatformNetState::smReservedSocketList.remove(handleFd);
|
|
|
|
|
|
|
|
|
|
if(!::closesocket(socketFd))
|
2012-09-19 15:15:01 +00:00
|
|
|
return NoError;
|
|
|
|
|
else
|
2016-09-10 22:01:10 +00:00
|
|
|
return PlatformNetState::getLastError();
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return NotASocket;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
Net::Error Net::connect(NetSocket handleFd, const NetAddress *address)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if(!(address->type == NetAddress::IPAddress || address->type == NetAddress::IPV6Address))
|
2012-09-19 15:15:01 +00:00
|
|
|
return WrongProtocolType;
|
2016-09-10 22:01:10 +00:00
|
|
|
|
|
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
|
|
|
|
|
|
|
|
|
if (address->type == NetAddress::IPAddress)
|
|
|
|
|
{
|
|
|
|
|
sockaddr_in socketAddress;
|
|
|
|
|
NetAddressToIPSocket(address, &socketAddress);
|
|
|
|
|
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
{
|
|
|
|
|
socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!::connect(socketFd, (struct sockaddr *) &socketAddress, sizeof(socketAddress)))
|
|
|
|
|
return NoError;
|
|
|
|
|
}
|
|
|
|
|
else if (address->type == NetAddress::IPV6Address)
|
|
|
|
|
{
|
|
|
|
|
sockaddr_in6 socketAddress;
|
|
|
|
|
NetAddressToIPSocket6(address, &socketAddress);
|
|
|
|
|
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
{
|
|
|
|
|
socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET6, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!::connect(socketFd, (struct sockaddr *) &socketAddress, sizeof(socketAddress)))
|
|
|
|
|
return NoError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PlatformNetState::getLastError();
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
Net::Error Net::listen(NetSocket handleFd, S32 backlog)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
return NotASocket;
|
|
|
|
|
|
|
|
|
|
if(!::listen(socketFd, backlog))
|
2012-09-19 15:15:01 +00:00
|
|
|
return NoError;
|
2016-09-10 22:01:10 +00:00
|
|
|
return PlatformNetState::getLastError();
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
NetSocket Net::accept(NetSocket handleFd, NetAddress *remoteAddress)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
sockaddr_storage addr;
|
|
|
|
|
socklen_t addrLen = sizeof(addr);
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
return NetSocket::INVALID;
|
|
|
|
|
|
|
|
|
|
SOCKET acceptedSocketFd = ::accept(socketFd, (sockaddr *)&addr, &addrLen);
|
|
|
|
|
if (acceptedSocketFd != InvalidSocketHandle)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if (addr.ss_family == AF_INET)
|
|
|
|
|
{
|
|
|
|
|
// ipv4
|
|
|
|
|
IPSocketToNetAddress(((struct sockaddr_in*)&addr), remoteAddress);
|
|
|
|
|
}
|
|
|
|
|
else if (addr.ss_family == AF_INET6)
|
|
|
|
|
{
|
|
|
|
|
// ipv6
|
|
|
|
|
IPSocket6ToNetAddress(((struct sockaddr_in6*)&addr), remoteAddress);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetSocket newHandleFd = PlatformNetState::smReservedSocketList.reserve(acceptedSocketFd);
|
|
|
|
|
return newHandleFd;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
|
|
|
|
|
return NetSocket::INVALID;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
Net::Error Net::bindAddress(const NetAddress &address, NetSocket handleFd, bool useUDP)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
int error = 0;
|
|
|
|
|
sockaddr_storage socketAddress;
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
dMemset(&socketAddress, '\0', sizeof(socketAddress));
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
{
|
|
|
|
|
if (handleFd.getHandle() == -1)
|
|
|
|
|
return NotASocket;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
if (address.type == NetAddress::IPAddress)
|
|
|
|
|
{
|
|
|
|
|
socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET, useUDP);
|
|
|
|
|
NetAddressToIPSocket(&address, (struct sockaddr_in*)&socketAddress);
|
|
|
|
|
error = ::bind(socketFd, (struct sockaddr*)&socketAddress, sizeof(sockaddr_in));
|
|
|
|
|
}
|
|
|
|
|
else if (address.type == NetAddress::IPV6Address)
|
|
|
|
|
{
|
|
|
|
|
socketFd = PlatformNetState::smReservedSocketList.activate(handleFd, AF_INET6, useUDP);
|
|
|
|
|
NetAddressToIPSocket6(&address, (struct sockaddr_in6*)&socketAddress);
|
|
|
|
|
error = ::bind(socketFd, (struct sockaddr*)&socketAddress, sizeof(sockaddr_in6));
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
if (!error)
|
2012-09-19 15:15:01 +00:00
|
|
|
return NoError;
|
2016-09-10 22:01:10 +00:00
|
|
|
return PlatformNetState::getLastError();
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
Net::Error Net::setBufferSize(NetSocket handleFd, S32 bufferSize)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
S32 error;
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
return NotASocket;
|
|
|
|
|
|
|
|
|
|
error = ::setsockopt(socketFd, SOL_SOCKET, SO_RCVBUF, (char *) &bufferSize, sizeof(bufferSize));
|
2012-09-19 15:15:01 +00:00
|
|
|
if(!error)
|
2016-09-10 22:01:10 +00:00
|
|
|
error = ::setsockopt(socketFd, SOL_SOCKET, SO_SNDBUF, (char *) &bufferSize, sizeof(bufferSize));
|
2012-09-19 15:15:01 +00:00
|
|
|
if(!error)
|
|
|
|
|
return NoError;
|
2016-09-10 22:01:10 +00:00
|
|
|
return PlatformNetState::getLastError();
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
Net::Error Net::setBroadcast(NetSocket handleFd, bool broadcast)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
S32 bc = broadcast;
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
return NotASocket;
|
|
|
|
|
S32 error = ::setsockopt(socketFd, SOL_SOCKET, SO_BROADCAST, (char*)&bc, sizeof(bc));
|
2012-09-19 15:15:01 +00:00
|
|
|
if(!error)
|
|
|
|
|
return NoError;
|
2016-09-10 22:01:10 +00:00
|
|
|
return PlatformNetState::getLastError();
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
Net::Error Net::setBlocking(NetSocket handleFd, bool blockingIO)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
return NotASocket;
|
|
|
|
|
|
2012-09-19 15:15:01 +00:00
|
|
|
unsigned long notblock = !blockingIO;
|
2016-09-10 22:01:10 +00:00
|
|
|
S32 error = ioctl(socketFd, FIONBIO, ¬block);
|
2012-09-19 15:15:01 +00:00
|
|
|
if(!error)
|
|
|
|
|
return NoError;
|
2016-09-10 22:01:10 +00:00
|
|
|
return PlatformNetState::getLastError();
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
Net::Error Net::getListenAddress(const NetAddress::Type type, NetAddress *address, bool forceDefaults)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if (type == NetAddress::IPAddress)
|
|
|
|
|
{
|
|
|
|
|
const char* serverIP = forceDefaults ? NULL : Con::getVariable("pref::Net::BindAddress");
|
|
|
|
|
if (!serverIP || serverIP[0] == '\0')
|
|
|
|
|
{
|
|
|
|
|
address->type = type;
|
2016-12-17 23:08:43 +00:00
|
|
|
address->port = 0;
|
2016-09-10 22:01:10 +00:00
|
|
|
*((U32*)address->address.ipv4.netNum) = INADDR_ANY;
|
2016-10-28 17:31:47 +00:00
|
|
|
return Net::NoError;
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return Net::stringToAddress(serverIP, address, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (type == NetAddress::IPBroadcastAddress)
|
|
|
|
|
{
|
|
|
|
|
address->type = type;
|
2016-12-17 23:08:43 +00:00
|
|
|
address->port = 0;
|
2016-09-10 22:01:10 +00:00
|
|
|
*((U32*)address->address.ipv4.netNum) = INADDR_BROADCAST;
|
2016-10-28 17:31:47 +00:00
|
|
|
return Net::NoError;
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
else if (type == NetAddress::IPV6Address)
|
|
|
|
|
{
|
|
|
|
|
const char* serverIP6 = forceDefaults ? NULL : Con::getVariable("pref::Net::BindAddress6");
|
|
|
|
|
if (!serverIP6 || serverIP6[0] == '\0')
|
|
|
|
|
{
|
|
|
|
|
sockaddr_in6 addr;
|
|
|
|
|
dMemset(&addr, '\0', sizeof(addr));
|
|
|
|
|
|
2016-12-17 23:08:43 +00:00
|
|
|
addr.sin6_port = 0;
|
2016-09-10 22:01:10 +00:00
|
|
|
addr.sin6_addr = in6addr_any;
|
|
|
|
|
|
|
|
|
|
IPSocket6ToNetAddress(&addr, address);
|
2016-10-28 17:31:47 +00:00
|
|
|
return Net::NoError;
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return Net::stringToAddress(serverIP6, address, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (type == NetAddress::IPV6MulticastAddress)
|
|
|
|
|
{
|
|
|
|
|
const char* multicastAddressValue = forceDefaults ? NULL : Con::getVariable("pref::Net::Multicast6Address");
|
|
|
|
|
if (!multicastAddressValue || multicastAddressValue[0] == '\0')
|
|
|
|
|
{
|
|
|
|
|
multicastAddressValue = TORQUE_NET_DEFAULT_MULTICAST_ADDRESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Net::stringToAddress(multicastAddressValue, address, false);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-10-28 17:31:47 +00:00
|
|
|
return Net::WrongProtocolType;
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Net::getIdealListenAddress(NetAddress *address)
|
|
|
|
|
{
|
|
|
|
|
dMemset(address, '\0', sizeof(NetAddress));
|
|
|
|
|
|
|
|
|
|
if (Net::smIpv6Enabled)
|
|
|
|
|
{
|
|
|
|
|
if (Net::getListenAddress(NetAddress::IPV6Address, address) == NeedHostLookup)
|
|
|
|
|
{
|
|
|
|
|
Net::getListenAddress(NetAddress::IPV6Address, address, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (Net::getListenAddress(NetAddress::IPAddress, address) == NeedHostLookup)
|
|
|
|
|
{
|
|
|
|
|
Net::getListenAddress(NetAddress::IPAddress, address, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
Net::Error Net::send(NetSocket handleFd, const U8 *buffer, S32 bufferSize, S32 *outBytesWritten)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
return NotASocket;
|
|
|
|
|
|
2012-09-19 15:15:01 +00:00
|
|
|
errno = 0;
|
2016-09-10 22:01:10 +00:00
|
|
|
S32 bytesWritten = ::send(socketFd, (const char*)buffer, bufferSize, 0);
|
2012-09-19 15:15:01 +00:00
|
|
|
|
2016-10-28 17:31:47 +00:00
|
|
|
if (outBytesWritten)
|
2016-11-27 18:02:19 +00:00
|
|
|
{
|
2017-10-23 21:00:16 +00:00
|
|
|
*outBytesWritten = *outBytesWritten < 0 ? 0 : bytesWritten;
|
2016-11-27 18:02:19 +00:00
|
|
|
}
|
2016-10-28 17:31:47 +00:00
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
return PlatformNetState::getLastError();
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
Net::Error Net::recv(NetSocket handleFd, U8 *buffer, S32 bufferSize, S32 *bytesRead)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
SOCKET socketFd = PlatformNetState::smReservedSocketList.resolve(handleFd);
|
|
|
|
|
if (socketFd == InvalidSocketHandle)
|
|
|
|
|
return NotASocket;
|
|
|
|
|
|
|
|
|
|
*bytesRead = ::recv(socketFd, (char*)buffer, bufferSize, 0);
|
2012-09-19 15:15:01 +00:00
|
|
|
if(*bytesRead == -1)
|
2016-09-10 22:01:10 +00:00
|
|
|
return PlatformNetState::getLastError();
|
2012-09-19 15:15:01 +00:00
|
|
|
return NoError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Net::compareAddresses(const NetAddress *a1, const NetAddress *a2)
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
return a1->isSameAddressAndPort(*a2);
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
Net::Error Net::stringToAddress(const char *addressString, NetAddress *address, bool hostLookup, int requiredFamily)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
char addr[256];
|
|
|
|
|
int port = 0;
|
|
|
|
|
int actualFamily = AF_UNSPEC;
|
|
|
|
|
if (!PlatformNetState::extractAddressParts(addressString, addr, port, actualFamily))
|
|
|
|
|
{
|
|
|
|
|
return WrongProtocolType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure family matches (in cast we have IP: stuff in address)
|
|
|
|
|
if (requiredFamily != AF_UNSPEC && actualFamily != AF_UNSPEC && (actualFamily != requiredFamily))
|
|
|
|
|
{
|
|
|
|
|
return WrongProtocolType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (actualFamily == AF_UNSPEC)
|
|
|
|
|
{
|
|
|
|
|
actualFamily = requiredFamily;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addressString = addr;
|
|
|
|
|
dMemset(address, '\0', sizeof(NetAddress));
|
|
|
|
|
|
|
|
|
|
if (!dStricmp(addressString, "broadcast"))
|
|
|
|
|
{
|
|
|
|
|
address->type = NetAddress::IPBroadcastAddress;
|
|
|
|
|
if (!(actualFamily == AF_UNSPEC || actualFamily == AF_INET))
|
|
|
|
|
return WrongProtocolType;
|
|
|
|
|
|
|
|
|
|
if (port != 0)
|
|
|
|
|
address->port = port;
|
|
|
|
|
else
|
|
|
|
|
address->port = PlatformNetState::defaultPort;
|
|
|
|
|
}
|
|
|
|
|
else if (!dStricmp(addressString, "multicast"))
|
|
|
|
|
{
|
|
|
|
|
address->type = NetAddress::IPV6MulticastAddress;
|
|
|
|
|
if (!(actualFamily == AF_UNSPEC || actualFamily == AF_INET6))
|
|
|
|
|
return WrongProtocolType;
|
|
|
|
|
|
|
|
|
|
if (port != 0)
|
|
|
|
|
address->port = port;
|
|
|
|
|
else
|
|
|
|
|
address->port = PlatformNetState::defaultPort;
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
else
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
sockaddr_in ipAddr;
|
|
|
|
|
sockaddr_in6 ipAddr6;
|
|
|
|
|
|
|
|
|
|
dMemset(&ipAddr, 0, sizeof(ipAddr));
|
|
|
|
|
dMemset(&ipAddr6, 0, sizeof(ipAddr6));
|
|
|
|
|
|
|
|
|
|
bool hasInterface = dStrchr(addressString, '%') != NULL; // if we have an interface, best use getaddrinfo to parse
|
|
|
|
|
|
|
|
|
|
// Check if we've got a simple ipv4 / ipv6
|
|
|
|
|
|
|
|
|
|
if (inet_pton(AF_INET, addressString, &ipAddr.sin_addr) == 1)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if (!(actualFamily == AF_UNSPEC || actualFamily == AF_INET))
|
|
|
|
|
return WrongProtocolType;
|
|
|
|
|
IPSocketToNetAddress(((struct sockaddr_in*)&ipAddr), address);
|
|
|
|
|
|
|
|
|
|
if (port != 0)
|
|
|
|
|
address->port = port;
|
2012-09-19 15:15:01 +00:00
|
|
|
else
|
2016-09-10 22:01:10 +00:00
|
|
|
address->port = PlatformNetState::defaultPort;
|
|
|
|
|
|
|
|
|
|
return NoError;
|
|
|
|
|
}
|
|
|
|
|
else if (!hasInterface && inet_pton(AF_INET6, addressString, &ipAddr6.sin6_addr) == 1)
|
|
|
|
|
{
|
|
|
|
|
if (!(actualFamily == AF_UNSPEC || actualFamily == AF_INET6))
|
|
|
|
|
return WrongProtocolType;
|
|
|
|
|
IPSocket6ToNetAddress(((struct sockaddr_in6*)&ipAddr6), address);
|
|
|
|
|
|
|
|
|
|
if (port != 0)
|
|
|
|
|
address->port = port;
|
|
|
|
|
else
|
|
|
|
|
address->port = PlatformNetState::defaultPort;
|
|
|
|
|
|
|
|
|
|
return NoError;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!hostLookup && !hasInterface)
|
|
|
|
|
return NeedHostLookup;
|
|
|
|
|
|
|
|
|
|
struct addrinfo hint, *res = NULL;
|
|
|
|
|
dMemset(&hint, 0, sizeof(hint));
|
|
|
|
|
hint.ai_family = actualFamily;
|
|
|
|
|
hint.ai_flags = hostLookup ? 0 : AI_NUMERICHOST;
|
|
|
|
|
|
2016-11-27 17:58:34 +00:00
|
|
|
if (getaddrinfo(addressString, NULL, &hint, &res) == 0)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if (actualFamily != AF_UNSPEC)
|
|
|
|
|
{
|
|
|
|
|
// Prefer desired protocol
|
|
|
|
|
res = PlatformNetState::pickAddressByProtocol(res, actualFamily);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (res && res->ai_family == AF_INET)
|
|
|
|
|
{
|
|
|
|
|
// ipv4
|
|
|
|
|
IPSocketToNetAddress(((struct sockaddr_in*)res->ai_addr), address);
|
|
|
|
|
}
|
|
|
|
|
else if (res && res->ai_family == AF_INET6)
|
|
|
|
|
{
|
|
|
|
|
// ipv6
|
|
|
|
|
IPSocket6ToNetAddress(((struct sockaddr_in6*)res->ai_addr), address);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// unknown
|
|
|
|
|
return UnknownError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (port != 0)
|
|
|
|
|
address->port = port;
|
|
|
|
|
else
|
|
|
|
|
address->port = PlatformNetState::defaultPort;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
|
|
|
|
|
return NoError;
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Net::addressToString(const NetAddress *address, char addressString[256])
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
if(address->type == NetAddress::IPAddress || address->type == NetAddress::IPBroadcastAddress)
|
2012-09-19 15:15:01 +00:00
|
|
|
{
|
|
|
|
|
sockaddr_in ipAddr;
|
2016-09-10 22:01:10 +00:00
|
|
|
NetAddressToIPSocket(address, &ipAddr);
|
|
|
|
|
|
|
|
|
|
if (ipAddr.sin_addr.s_addr == htonl(INADDR_BROADCAST) || address->type == NetAddress::IPBroadcastAddress)
|
|
|
|
|
{
|
|
|
|
|
if (ipAddr.sin_port == 0)
|
|
|
|
|
dSprintf(addressString, 256, "IP:Broadcast");
|
|
|
|
|
else
|
|
|
|
|
dSprintf(addressString, 256, "IP:Broadcast:%d", ntohs(ipAddr.sin_port));
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
else
|
|
|
|
|
{
|
2016-09-10 22:01:10 +00:00
|
|
|
char buffer[256];
|
|
|
|
|
buffer[0] = '\0';
|
|
|
|
|
inet_ntop(AF_INET, &(ipAddr.sin_addr), buffer, sizeof(buffer));
|
|
|
|
|
if (ipAddr.sin_port == 0)
|
|
|
|
|
dSprintf(addressString, 256, "IP:%s", buffer);
|
|
|
|
|
else
|
|
|
|
|
dSprintf(addressString, 256, "IP:%s:%i", buffer, ntohs(ipAddr.sin_port));
|
2012-09-19 15:15:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
2016-09-10 22:01:10 +00:00
|
|
|
else if (address->type == NetAddress::IPV6Address)
|
|
|
|
|
{
|
|
|
|
|
char buffer[256];
|
|
|
|
|
buffer[0] = '\0';
|
|
|
|
|
sockaddr_in6 ipAddr;
|
|
|
|
|
NetAddressToIPSocket6(address, &ipAddr);
|
|
|
|
|
inet_ntop(AF_INET6, &(ipAddr.sin6_addr), buffer, sizeof(buffer));
|
|
|
|
|
if (ipAddr.sin6_port == 0)
|
|
|
|
|
dSprintf(addressString, 256, "IP6:%s", buffer);
|
|
|
|
|
else
|
|
|
|
|
dSprintf(addressString, 256, "IP6:[%s]:%i", buffer, ntohs(ipAddr.sin6_port));
|
|
|
|
|
}
|
|
|
|
|
else if (address->type == NetAddress::IPV6MulticastAddress)
|
|
|
|
|
{
|
|
|
|
|
if (address->port == 0)
|
|
|
|
|
dSprintf(addressString, 256, "IP6:Multicast");
|
|
|
|
|
else
|
|
|
|
|
dSprintf(addressString, 256, "IP6:Multicast:%d", address->port);
|
|
|
|
|
}
|
2012-09-19 15:15:01 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*addressString = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-10 22:01:10 +00:00
|
|
|
void Net::enableMulticast()
|
|
|
|
|
{
|
|
|
|
|
SOCKET socketFd;
|
|
|
|
|
|
|
|
|
|
if (Net::smIpv6Enabled)
|
|
|
|
|
{
|
|
|
|
|
socketFd = PlatformNetState::smReservedSocketList.resolve(PlatformNetState::udp6Socket);
|
|
|
|
|
|
|
|
|
|
if (socketFd != InvalidSocketHandle)
|
|
|
|
|
{
|
|
|
|
|
PlatformNetState::multicast6Socket = PlatformNetState::udp6Socket;
|
|
|
|
|
|
|
|
|
|
Net::Error error = NoError;
|
|
|
|
|
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
{
|
|
|
|
|
unsigned long multicastTTL = 1;
|
|
|
|
|
|
|
|
|
|
if (setsockopt(socketFd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
|
|
|
|
(char*)&multicastTTL, sizeof(multicastTTL)) < 0)
|
|
|
|
|
{
|
|
|
|
|
error = PlatformNetState::getLastError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find multicast to bind to...
|
|
|
|
|
|
|
|
|
|
NetAddress multicastAddress;
|
|
|
|
|
sockaddr_in6 multicastSocketAddress;
|
|
|
|
|
|
|
|
|
|
const char *multicastAddressValue = Con::getVariable("pref::Net::Multicast6Address");
|
|
|
|
|
if (!multicastAddressValue || multicastAddressValue[0] == '\0')
|
|
|
|
|
{
|
|
|
|
|
multicastAddressValue = TORQUE_NET_DEFAULT_MULTICAST_ADDRESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error = Net::stringToAddress(multicastAddressValue, &multicastAddress, false);
|
|
|
|
|
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
{
|
|
|
|
|
dMemset(&PlatformNetState::multicast6Group, '\0', sizeof(&PlatformNetState::multicast6Group));
|
|
|
|
|
NetAddressToIPSocket6(&multicastAddress, &multicastSocketAddress);
|
|
|
|
|
dMemcpy(&PlatformNetState::multicast6Group.ipv6mr_multiaddr, &multicastSocketAddress.sin6_addr, sizeof(PlatformNetState::multicast6Group.ipv6mr_multiaddr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Setup group
|
|
|
|
|
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
{
|
|
|
|
|
const char *multicastInterface = Con::getVariable("pref::Net::Multicast6Interface");
|
|
|
|
|
|
|
|
|
|
if (multicastInterface && multicastInterface[0] != '\0')
|
|
|
|
|
{
|
|
|
|
|
#ifdef TORQUE_USE_WINSOCK
|
|
|
|
|
PlatformNetState::multicast6Group.ipv6mr_interface = dAtoi(multicastInterface);
|
|
|
|
|
#else
|
|
|
|
|
PlatformNetState::multicast6Group.ipv6mr_interface = if_nametoindex(multicastInterface);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PlatformNetState::multicast6Group.ipv6mr_interface = 0; // 0 == accept from any interface
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PlatformNetState::multicast6Group.ipv6mr_interface && error == NoError)
|
|
|
|
|
{
|
|
|
|
|
if (setsockopt(socketFd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&PlatformNetState::multicast6Group.ipv6mr_interface, sizeof(PlatformNetState::multicast6Group.ipv6mr_interface)) < 0)
|
|
|
|
|
{
|
|
|
|
|
error = PlatformNetState::getLastError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (error == NoError && setsockopt(socketFd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&PlatformNetState::multicast6Group, sizeof(PlatformNetState::multicast6Group)) < 0)
|
|
|
|
|
{
|
|
|
|
|
error = PlatformNetState::getLastError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (error == NoError)
|
|
|
|
|
{
|
2016-12-17 23:08:43 +00:00
|
|
|
char listenAddressStr[256];
|
2016-12-20 23:52:31 +00:00
|
|
|
Net::addressToString(&multicastAddress, listenAddressStr);
|
|
|
|
|
Con::printf("Multicast initialized on %s", listenAddressStr);
|
2016-09-10 22:01:10 +00:00
|
|
|
}
|
2016-12-17 23:08:43 +00:00
|
|
|
|
|
|
|
|
if (error != NoError)
|
2016-09-10 22:01:10 +00:00
|
|
|
{
|
|
|
|
|
PlatformNetState::multicast6Socket = NetSocket::INVALID;
|
|
|
|
|
Con::printf("Unable to multicast UDP - error %d", error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Net::disableMulticast()
|
|
|
|
|
{
|
|
|
|
|
if (PlatformNetState::multicast6Socket != NetSocket::INVALID)
|
|
|
|
|
{
|
|
|
|
|
PlatformNetState::multicast6Socket = NetSocket::INVALID;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Net::isMulticastEnabled()
|
|
|
|
|
{
|
|
|
|
|
return PlatformNetState::multicast6Socket != NetSocket::INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
U32 NetAddress::getHash() const
|
|
|
|
|
{
|
|
|
|
|
U32 value = 0;
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case NetAddress::IPAddress:
|
|
|
|
|
value = Torque::hash((const U8*)&address.ipv4.netNum, sizeof(address.ipv4.netNum), 0);
|
|
|
|
|
break;
|
|
|
|
|
case NetAddress::IPV6Address:
|
|
|
|
|
value = Torque::hash((const U8*)address.ipv6.netNum, sizeof(address.ipv6.netNum), 0);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
value = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Net::isAddressTypeAvailable(NetAddress::Type addressType)
|
|
|
|
|
{
|
|
|
|
|
switch (addressType)
|
|
|
|
|
{
|
|
|
|
|
case NetAddress::IPAddress:
|
|
|
|
|
return PlatformNetState::udpSocket != NetSocket::INVALID;
|
|
|
|
|
case NetAddress::IPV6Address:
|
|
|
|
|
return PlatformNetState::udp6Socket != NetSocket::INVALID;
|
|
|
|
|
case NetAddress::IPBroadcastAddress:
|
|
|
|
|
return PlatformNetState::udpSocket != NetSocket::INVALID;
|
|
|
|
|
case NetAddress::IPV6MulticastAddress:
|
|
|
|
|
return PlatformNetState::multicast6Socket != NetSocket::INVALID;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|