Update ENetAddress to use 5 uint32_t to store IP

ENetAddress ea = {} will allow to listen to any IPv4 or IPv6 address
when using system or bundled enet

The last uint32_t is for IPv6 scope id (required for IPv6 only lan
servers)
This commit is contained in:
Benau 2020-02-28 00:59:37 +08:00
parent 8995491eb6
commit fa0da462fb
20 changed files with 377 additions and 378 deletions

View File

@ -81,7 +81,7 @@ The current server configuration xml looks like this:
<!-- Disable it to turn off all stun related code in server, it allows for saving of server resources if your server is not behind a firewall. -->
<firewalled-server value="true" />
<!-- Enable to allow IPv6 connection if you have a public IPv6 address. STK currently uses dual-stack mode which requires server to have both IPv4 and IPv6 and listen to same port. If STK detects your server has no public IPv6 address or port differs between IPv4 and IPv6 then it will use IPv4 only socket. -->
<!-- Enable to allow IPv6 connection if you have a public IPv6 address. STK currently uses dual-stack mode which requires server to have both IPv4 and IPv6 and listen to same port. If STK detects your server has no public IPv6 address or port differs between IPv4 and IPv6 then it will use IPv4 only socket. For system which doesn't support dual-stack socket (like OpenBSD) you may fail to be connected by IPv4 clients. -->
<ipv6-server value="true" />
<!-- No server owner in lobby which can control the starting of game or kick any players. -->

View File

@ -87,7 +87,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
host -> commandCount = 0;
host -> bufferCount = 0;
host -> checksum = NULL;
host -> receivedAddress.host = ENET_HOST_ANY;
host -> receivedAddress.host = (ENetIP) { 0 };
host -> receivedAddress.port = 0;
host -> receivedData = NULL;
host -> receivedDataLength = 0;

View File

@ -76,6 +76,19 @@ typedef enum _ENetSocketShutdown
#define ENET_HOST_BROADCAST 0xFFFFFFFFU
#define ENET_PORT_ANY 0
typedef struct _ENetIP
{
enet_uint32 p0; // uint32_t here for IPv4, or 4 uint32_t IPv6 address
enet_uint32 p1;
enet_uint32 p2;
enet_uint32 p3;
enet_uint32 p4; // sockaddr_in6 sin6_scope_id (required for local link address)
} ENetIP;
// We don't need to test sin6_scope_id as it only used for connection, and sin6_flowinfo is always zero
#define enet_ip_equal(a, b) (a.p0 == b.p0 && a.p1 == b.p1 && a.p2 == b.p2 && a.p3 == b.p3)
#define enet_ip_not_equal(a, b) (a.p0 != b.p0 || a.p1 != b.p1 || a.p2 != b.p2 || a.p3 != b.p3)
/**
* Portable internet address structure.
*
@ -88,7 +101,7 @@ typedef enum _ENetSocketShutdown
*/
typedef struct _ENetAddress
{
enet_uint32 host;
ENetIP host;
enet_uint16 port;
} ENetAddress;

View File

@ -307,7 +307,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
}
else
if (currentPeer -> state != ENET_PEER_STATE_CONNECTING &&
currentPeer -> address.host == host -> receivedAddress.host)
enet_ip_equal(currentPeer -> address.host, host -> receivedAddress.host))
{
if (currentPeer -> address.port == host -> receivedAddress.port &&
currentPeer -> connectID == command -> connect.connectID)
@ -1019,9 +1019,9 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
if (peer -> state == ENET_PEER_STATE_DISCONNECTED ||
peer -> state == ENET_PEER_STATE_ZOMBIE ||
((host -> receivedAddress.host != peer -> address.host ||
((enet_ip_not_equal(host -> receivedAddress.host, peer -> address.host) ||
host -> receivedAddress.port != peer -> address.port) &&
peer -> address.host != ENET_HOST_BROADCAST) ||
peer -> address.host.p0 != ENET_HOST_BROADCAST) ||
(peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID &&
sessionID != peer -> incomingSessionID))
return 0;

View File

@ -63,6 +63,9 @@ typedef int socklen_t;
static enet_uint32 timeBase = 0;
// Global variable handled by STK
extern int isIPv6Socket(void);
int
enet_initialize (void)
{
@ -104,9 +107,9 @@ int
enet_address_set_host_ip (ENetAddress * address, const char * name)
{
#ifdef HAS_INET_PTON
if (! inet_pton (AF_INET, name, & address -> host))
if (! inet_pton (AF_INET, name, & address -> host.p0))
#else
if (! inet_aton (name, (struct in_addr *) & address -> host))
if (! inet_aton (name, (struct in_addr *) & address -> host.p0))
#endif
return -1;
@ -131,7 +134,7 @@ enet_address_set_host (ENetAddress * address, const char * name)
{
struct sockaddr_in * sin = (struct sockaddr_in *) result -> ai_addr;
address -> host = sin -> sin_addr.s_addr;
address -> host.p0 = sin -> sin_addr.s_addr;
freeaddrinfo (resultList);
@ -159,7 +162,7 @@ enet_address_set_host (ENetAddress * address, const char * name)
if (hostEntry != NULL && hostEntry -> h_addrtype == AF_INET)
{
address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
address -> host.p0 = * (enet_uint32 *) hostEntry -> h_addr_list [0];
return 0;
}
@ -172,9 +175,9 @@ int
enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
{
#ifdef HAS_INET_NTOP
if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL)
if (inet_ntop (AF_INET, & address -> host.p0, name, nameLength) == NULL)
#else
char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
char * addr = inet_ntoa (* (struct in_addr *) & address -> host.p0);
if (addr != NULL)
{
size_t addrLen = strlen(addr);
@ -199,7 +202,7 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng
sin.sin_family = AF_INET;
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
sin.sin_addr.s_addr = address -> host.p0;
err = getnameinfo ((struct sockaddr *) & sin, sizeof (sin), name, nameLength, NULL, 0, NI_NAMEREQD);
if (! err)
@ -218,7 +221,7 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng
char buffer [2048];
int errnum;
in.s_addr = address -> host;
in.s_addr = address -> host.p0;
#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum);
@ -226,7 +229,7 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng
hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum);
#endif
#else
in.s_addr = address -> host;
in.s_addr = address -> host.p0;
hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
#endif
@ -246,6 +249,29 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng
int
enet_socket_bind (ENetSocket socket, const ENetAddress * address)
{
if (isIPv6Socket() == 1)
{
struct sockaddr_in6 sin;
memset (& sin, 0, sizeof (sin));
sin.sin6_family = AF_INET6;
if (address != NULL)
{
sin.sin6_port = ENET_HOST_TO_NET_16 (address -> port);
memcpy (sin.sin6_addr.s6_addr, & address -> host.p0, 16);
}
else
{
sin.sin6_port = 0;
sin.sin6_addr = in6addr_any;
}
return bind (socket,
(struct sockaddr *) & sin,
sizeof (struct sockaddr_in6));
}
else
{
struct sockaddr_in sin;
@ -256,7 +282,7 @@ enet_socket_bind (ENetSocket socket, const ENetAddress * address)
if (address != NULL)
{
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
sin.sin_addr.s_addr = address -> host.p0;
}
else
{
@ -268,9 +294,27 @@ enet_socket_bind (ENetSocket socket, const ENetAddress * address)
(struct sockaddr *) & sin,
sizeof (struct sockaddr_in));
}
}
int
enet_socket_get_address (ENetSocket socket, ENetAddress * address)
{
if (isIPv6Socket() == 1)
{
struct sockaddr_in6 sin;
memset (& sin, 0, sizeof (sin));
socklen_t sinLength = sizeof (struct sockaddr_in6);
if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1)
return -1;
memcpy (& address -> host.p0, sin.sin6_addr.s6_addr, 16);
address -> host.p4 = sin.sin6_scope_id;
address -> port = ENET_NET_TO_HOST_16 (sin.sin6_port);
return 0;
}
else
{
struct sockaddr_in sin;
socklen_t sinLength = sizeof (struct sockaddr_in);
@ -278,11 +322,12 @@ enet_socket_get_address (ENetSocket socket, ENetAddress * address)
if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1)
return -1;
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> host.p0 = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
return 0;
}
}
int
enet_socket_listen (ENetSocket socket, int backlog)
@ -293,7 +338,16 @@ enet_socket_listen (ENetSocket socket, int backlog)
ENetSocket
enet_socket_create (ENetSocketType type)
{
return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
int pf_family = isIPv6Socket() == 1 ? PF_INET6 : PF_INET;
int socket_fd = socket (pf_family, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
if (isIPv6Socket() == 1 && socket_fd != -1)
{
int no = 0;
// Allow IPv6 socket listen to IPv4 connection (as long as the host has IPv4 address)
// We always use dual stack in STK
setsockopt (socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) & no, sizeof (no));
}
return socket_fd;
}
int
@ -382,7 +436,7 @@ enet_socket_connect (ENetSocket socket, const ENetAddress * address)
sin.sin_family = AF_INET;
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
sin.sin_addr.s_addr = address -> host.p0;
result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
if (result == -1 && errno == EINPROGRESS)
@ -407,7 +461,7 @@ enet_socket_accept (ENetSocket socket, ENetAddress * address)
if (address != NULL)
{
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> host.p0 = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
}
@ -434,22 +488,36 @@ enet_socket_send (ENetSocket socket,
size_t bufferCount)
{
struct msghdr msgHdr;
struct sockaddr_in sin;
struct sockaddr_storage sin;
memset (& sin, 0, sizeof (sin));
int sentLength;
memset (& msgHdr, 0, sizeof (struct msghdr));
if (address != NULL)
{
memset (& sin, 0, sizeof (struct sockaddr_in));
if (isIPv6Socket() == 1)
{
struct sockaddr_in6 * v6 = (struct sockaddr_in6 *) & sin;
v6 -> sin6_family = AF_INET6;
v6 -> sin6_port = ENET_HOST_TO_NET_16 (address -> port);
memcpy (v6 -> sin6_addr.s6_addr, & address -> host.p0, 16);
v6 -> sin6_scope_id = address -> host.p4;
sin.sin_family = AF_INET;
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
msgHdr.msg_name = & sin;
msgHdr.msg_namelen = sizeof (struct sockaddr_in6);
}
else
{
struct sockaddr_in * v4 = (struct sockaddr_in *) & sin;
v4 -> sin_family = AF_INET;
v4 -> sin_port = ENET_HOST_TO_NET_16 (address -> port);
v4 -> sin_addr.s_addr = address -> host.p0;
msgHdr.msg_name = & sin;
msgHdr.msg_namelen = sizeof (struct sockaddr_in);
}
}
msgHdr.msg_iov = (struct iovec *) buffers;
msgHdr.msg_iovlen = bufferCount;
@ -474,7 +542,8 @@ enet_socket_receive (ENetSocket socket,
size_t bufferCount)
{
struct msghdr msgHdr;
struct sockaddr_in sin;
struct sockaddr_storage sin;
memset (& sin, 0, sizeof (sin));
int recvLength;
memset (& msgHdr, 0, sizeof (struct msghdr));
@ -482,7 +551,7 @@ enet_socket_receive (ENetSocket socket,
if (address != NULL)
{
msgHdr.msg_name = & sin;
msgHdr.msg_namelen = sizeof (struct sockaddr_in);
msgHdr.msg_namelen = sizeof (sin);
}
msgHdr.msg_iov = (struct iovec *) buffers;
@ -505,8 +574,27 @@ enet_socket_receive (ENetSocket socket,
if (address != NULL)
{
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
switch (sin.ss_family)
{
case AF_INET:
// Should not happen if dual stack is working
if (isIPv6Socket() == 1)
return -1;
struct sockaddr_in * v4 = (struct sockaddr_in *) & sin;
address -> host.p0 = (enet_uint32) v4 -> sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (v4->sin_port);
break;
case AF_INET6:
if (isIPv6Socket() != 1)
return -1;
struct sockaddr_in6 * v6 = (struct sockaddr_in6 *) & sin;
memcpy (& address -> host.p0, v6 -> sin6_addr.s6_addr, 16);
address -> host.p4 = v6 -> sin6_scope_id;
address -> port = ENET_NET_TO_HOST_16 (v6 -> sin6_port);
break;
default:
return -1;
}
}
return recvLength;

View File

@ -6,11 +6,15 @@
#define ENET_BUILDING_LIB 1
#include "enet/enet.h"
#include <ws2tcpip.h>
#include <windows.h>
#include <mmsystem.h>
static enet_uint32 timeBase = 0;
// Global variable handled by STK
extern int isIPv6Socket(void);
int
enet_initialize (void)
{
@ -81,7 +85,7 @@ enet_address_set_host_ip (ENetAddress * address, const char * name)
name = next + 1;
}
memcpy (& address -> host, vals, sizeof (enet_uint32));
memcpy (& address -> host.p0, vals, sizeof (enet_uint32));
return 0;
}
@ -95,7 +99,7 @@ enet_address_set_host (ENetAddress * address, const char * name)
hostEntry -> h_addrtype != AF_INET)
return enet_address_set_host_ip (address, name);
address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
address -> host.p0 = * (enet_uint32 *) hostEntry -> h_addr_list [0];
return 0;
}
@ -103,7 +107,7 @@ enet_address_set_host (ENetAddress * address, const char * name)
int
enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
{
char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
char * addr = inet_ntoa (* (struct in_addr *) & address -> host.p0);
if (addr == NULL)
return -1;
else
@ -122,7 +126,7 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng
struct in_addr in;
struct hostent * hostEntry;
in.s_addr = address -> host;
in.s_addr = address -> host.p0;
hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
if (hostEntry == NULL)
@ -140,6 +144,29 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng
int
enet_socket_bind (ENetSocket socket, const ENetAddress * address)
{
if (isIPv6Socket() == 1)
{
struct sockaddr_in6 sin;
memset (& sin, 0, sizeof (sin));
sin.sin6_family = AF_INET6;
if (address != NULL)
{
sin.sin6_port = ENET_HOST_TO_NET_16 (address -> port);
memcpy (sin.sin6_addr.s6_addr, &address->host.p0, 16);
}
else
{
sin.sin6_port = 0;
sin.sin6_addr = in6addr_any;
}
return bind (socket,
(struct sockaddr *) & sin,
sizeof (struct sockaddr_in6)) == SOCKET_ERROR ? -1 : 0;
}
else
{
struct sockaddr_in sin;
@ -150,7 +177,7 @@ enet_socket_bind (ENetSocket socket, const ENetAddress * address)
if (address != NULL)
{
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
sin.sin_addr.s_addr = address -> host.p0;
}
else
{
@ -162,21 +189,40 @@ enet_socket_bind (ENetSocket socket, const ENetAddress * address)
(struct sockaddr *) & sin,
sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0;
}
}
int
enet_socket_get_address (ENetSocket socket, ENetAddress * address)
{
struct sockaddr_in sin;
int sinLength = sizeof (struct sockaddr_in);
if (isIPv6Socket() == 1)
{
struct sockaddr_in6 sin;
memset (& sin, 0, sizeof (sin));
socklen_t sinLength = sizeof (struct sockaddr_in6);
if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1)
return -1;
address -> host = (enet_uint32) sin.sin_addr.s_addr;
memcpy (& address->host.p0, sin.sin6_addr.s6_addr, 16);
address -> host.p4 = sin.sin6_scope_id;
address -> port = ENET_NET_TO_HOST_16 (sin.sin6_port);
return 0;
}
else
{
struct sockaddr_in sin;
socklen_t sinLength = sizeof (struct sockaddr_in);
if (getsockname (socket, (struct sockaddr *) & sin, & sinLength) == -1)
return -1;
address -> host.p0 = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
return 0;
}
}
int
enet_socket_listen (ENetSocket socket, int backlog)
@ -187,7 +233,16 @@ enet_socket_listen (ENetSocket socket, int backlog)
ENetSocket
enet_socket_create (ENetSocketType type)
{
return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
int pf_family = isIPv6Socket() == 1 ? PF_INET6 : PF_INET;
SOCKET socket_fd = socket (pf_family, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
if (isIPv6Socket() == 1 && socket_fd != INVALID_SOCKET)
{
int no = 0;
// Allow IPv6 socket listen to IPv4 connection (as long as the host has IPv4 address)
// We always use dual stack in STK
setsockopt (socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) & no, sizeof (no));
}
return socket_fd;
}
int
@ -264,7 +319,7 @@ enet_socket_connect (ENetSocket socket, const ENetAddress * address)
sin.sin_family = AF_INET;
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
sin.sin_addr.s_addr = address -> host.p0;
result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
if (result == SOCKET_ERROR && WSAGetLastError () != WSAEWOULDBLOCK)
@ -289,7 +344,7 @@ enet_socket_accept (ENetSocket socket, ENetAddress * address)
if (address != NULL)
{
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> host.p0 = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
}
@ -315,16 +370,33 @@ enet_socket_send (ENetSocket socket,
const ENetBuffer * buffers,
size_t bufferCount)
{
struct sockaddr_in sin;
struct sockaddr_storage sin;
memset (& sin, 0, sizeof (sin));
size_t sin_size = 0;
DWORD sentLength;
if (address != NULL)
{
memset (& sin, 0, sizeof (struct sockaddr_in));
if (isIPv6Socket() == 1)
{
struct sockaddr_in6 * v6 = (struct sockaddr_in6 *) & sin;
v6 -> sin6_family = AF_INET6;
v6 -> sin6_port = ENET_HOST_TO_NET_16 (address -> port);
memcpy (v6 -> sin6_addr.s6_addr, & address -> host.p0, 16);
v6 -> sin6_scope_id = address -> host.p4;
sin.sin_family = AF_INET;
sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
sin.sin_addr.s_addr = address -> host;
sin_size = sizeof (struct sockaddr_in6);
}
else
{
struct sockaddr_in * v4 = (struct sockaddr_in *) & sin;
v4 -> sin_family = AF_INET;
v4 -> sin_port = ENET_HOST_TO_NET_16 (address -> port);
v4 -> sin_addr.s_addr = address -> host.p0;
sin_size = sizeof (struct sockaddr_in);
}
}
if (WSASendTo (socket,
@ -333,7 +405,7 @@ enet_socket_send (ENetSocket socket,
& sentLength,
0,
address != NULL ? (struct sockaddr *) & sin : NULL,
address != NULL ? sizeof (struct sockaddr_in) : 0,
address != NULL ? (int)sin_size : 0,
NULL,
NULL) == SOCKET_ERROR)
{
@ -352,10 +424,11 @@ enet_socket_receive (ENetSocket socket,
ENetBuffer * buffers,
size_t bufferCount)
{
INT sinLength = sizeof (struct sockaddr_in);
INT sinLength = sizeof (struct sockaddr_storage);
DWORD flags = 0,
recvLength;
struct sockaddr_in sin;
struct sockaddr_storage sin;
memset (& sin, 0, sizeof (sin));
if (WSARecvFrom (socket,
(LPWSABUF) buffers,
@ -382,8 +455,27 @@ enet_socket_receive (ENetSocket socket,
if (address != NULL)
{
address -> host = (enet_uint32) sin.sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
switch (sin.ss_family)
{
case AF_INET:
// Should not happen if dual stack is working
if (isIPv6Socket() == 1)
return -1;
struct sockaddr_in * v4 = (struct sockaddr_in *) & sin;
address -> host.p0 = (enet_uint32) v4 -> sin_addr.s_addr;
address -> port = ENET_NET_TO_HOST_16 (v4->sin_port);
break;
case AF_INET6:
if (isIPv6Socket() != 1)
return -1;
struct sockaddr_in6 * v6 = (struct sockaddr_in6 *) & sin;
memcpy (& address -> host.p0, v6 -> sin6_addr.s6_addr, 16);
address -> host.p4 = v6 -> sin6_scope_id;
address -> port = ENET_NET_TO_HOST_16 (v6 -> sin6_port);
break;
default:
return -1;
}
}
return (int) recvLength;

View File

@ -69,7 +69,7 @@ Network::Network(int peer_count, int channel_limit,
{
Log::warn("Network", "%d port is in used, use another port",
address->port);
ENetAddress new_addr;
ENetAddress new_addr = {};
new_addr.host = address->host;
// Any port
new_addr.port = 0;

View File

@ -210,9 +210,7 @@ void NetworkConfig::detectIPType()
return;
}
#ifdef ENABLE_IPV6
ENetAddress eaddr;
eaddr.host = STKHost::HOST_ANY;
eaddr.port = STKHost::PORT_ANY;
ENetAddress eaddr = {};
// We don't need to result of stun, just to check if the socket can be
// used in ipv4 or ipv6
uint8_t stun_tansaction_id[16] = {};

View File

@ -69,8 +69,7 @@ ConnectToServer::ConnectToServer(std::shared_ptr<Server> server)
: Protocol(PROTOCOL_CONNECTION)
{
m_quick_play_err_msg = _("No quick play server available.");
m_server_address.host = 0;
m_server_address.port = 0;
m_server_address = {};
if (server)
m_server = server;
} // ConnectToServer(server, host)
@ -252,8 +251,7 @@ void ConnectToServer::asynchronousUpdate()
// Free the bound socket first
delete STKHost::get()->getNetwork();
setIPv6Socket(1);
ENetAddress addr;
addr.host = STKHost::HOST_ANY;
ENetAddress addr = {};
addr.port = NetworkConfig::get()->getClientPort();
auto new_network = new Network(/*peer_count*/1,
/*channel_limit*/EVENT_CHANNEL_COUNT,
@ -409,22 +407,16 @@ int ConnectToServer::interceptCallback(ENetHost* host, ENetEvent* event)
host->receivedData[8] == '-' && host->receivedData[9] == 's' &&
host->receivedData[10] == 't' && host->receivedData[11] == 'k')
{
#ifdef ENABLE_IPV6
if (enet_ip_not_equal(host->receivedAddress.host, m_server_address.host) ||
#else
if (host->receivedAddress.host != m_server_address.host ||
#endif
host->receivedAddress.port != m_server_address.port)
{
std::string new_address =
enetAddressToString(host->receivedAddress);
if (isIPv6Socket())
{
// It was already mapped to real IPv6 before the intercept
// callback
new_address = "[";
new_address += getIPV6ReadableFromMappedAddress
(&host->receivedAddress) + "]:" +
StringUtils::toString(host->receivedAddress.port);
}
SocketAddress new_address(host->receivedAddress);
Log::info("ConnectToServer", "Using new server address %s",
new_address.c_str());
new_address.toString().c_str());
m_retry_count = 15;
m_server_address = host->receivedAddress;
m_done_intecept = true;
@ -441,9 +433,7 @@ bool ConnectToServer::tryConnect(int timeout, int retry, bool another_port,
{
m_retry_count = retry;
ENetEvent event;
ENetAddress ea;
ea.host = STKHost::HOST_ANY;
ea.port = STKHost::PORT_ANY;
ENetAddress ea = {};
Network* nw = another_port ? new Network(/*peer_count*/1,
/*channel_limit*/EVENT_CHANNEL_COUNT,
/*max_in_bandwidth*/0, /*max_out_bandwidth*/0, &ea,
@ -453,31 +443,21 @@ bool ConnectToServer::tryConnect(int timeout, int retry, bool another_port,
m_done_intecept = false;
nw->getENetHost()->intercept = ConnectToServer::interceptCallback;
const SocketAddress* sa;
if (ipv6)
{
SocketAddress* sa = m_server->getIPV6Address();
sa = m_server->getIPV6Address();
if (!sa)
return false;
struct sockaddr_in6* in6 = (struct sockaddr_in6*)sa->getSockaddr();
addMappedAddress(&m_server_address, in6);
}
else
{
// IPv4 address
m_server_address = toENetAddress(m_server->getAddress().getIP(),
m_server->getAddress().getPort());
}
sa = &m_server->getAddress();
m_server_address = sa->toENetAddress();
while (--m_retry_count >= 0 && !ProtocolManager::lock()->isExiting())
{
std::string connecting_address = enetAddressToString(m_server_address);
if (ipv6)
{
connecting_address = "[";
connecting_address += getIPV6ReadableFromMappedAddress
(&m_server_address) + "]:" +
StringUtils::toString(m_server->getIPV6Address()->getPort());
}
std::string connecting_address =
SocketAddress(m_server_address).toString();
ENetPeer* p = nw->connectTo(m_server_address);
if (!p)
break;
@ -555,30 +535,6 @@ void ConnectToServer::registerWithSTKServer()
}
} // registerWithSTKServer
// ----------------------------------------------------------------------------
std::string ConnectToServer::enetAddressToString(const ENetAddress& addr)
{
uint32_t ip = htonl(addr.host);
std::string s =
StringUtils::insertValues("%d.%d.%d.%d",
((ip >> 24) & 0xff), ((ip >> 16) & 0xff),
((ip >> 8) & 0xff), ((ip >> 0) & 0xff));
s += StringUtils::insertValues(":%d", addr.port);
return s;
} // enetAddressToString
// ----------------------------------------------------------------------------
ENetAddress ConnectToServer::toENetAddress(uint32_t ip, uint16_t port)
{
// because ENet wants little endian
ENetAddress a;
a.host = ((ip & 0xff000000) >> 24) +
((ip & 0x00ff0000) >> 8) + ((ip & 0x0000ff00) << 8) +
((ip & 0x000000ff) << 24);
a.port = port;
return a;
} // toENetAddress
// ----------------------------------------------------------------------------
bool ConnectToServer::detectPort()
{
@ -663,9 +619,7 @@ bool ConnectToServer::detectPort()
}
#endif
ENetAddress ea;
ea.host = STKHost::HOST_ANY;
ea.port = STKHost::PORT_ANY;
ENetAddress ea = {};
std::unique_ptr<Network> nw(new Network(/*peer_count*/1,
/*channel_limit*/EVENT_CHANNEL_COUNT,
/*max_in_bandwidth*/0, /*max_out_bandwidth*/0, &ea,

View File

@ -68,8 +68,6 @@ public:
virtual void setup() OVERRIDE;
virtual void asynchronousUpdate() OVERRIDE;
virtual void update(int ticks) OVERRIDE;
static std::string enetAddressToString(const ENetAddress& addr);
static ENetAddress toENetAddress(uint32_t ip, uint16_t port);
}; // class ConnectToServer
#endif // CONNECT_TO_SERVER_HPP

View File

@ -189,7 +189,9 @@ namespace ServerConfig
"STK currently uses dual-stack mode which requires server to have both "
"IPv4 and IPv6 and listen to same port. If STK detects your server "
"has no public IPv6 address or port differs between IPv4 and IPv6 "
"then it will use IPv4 only socket."));
"then it will use IPv4 only socket. For system which doesn't support "
"dual-stack socket (like OpenBSD) you may fail to be connected by "
"IPv4 clients."));
SERVER_CFG_PREFIX BoolServerConfigParam m_owner_less
SERVER_CFG_DEFAULT(BoolServerConfigParam(false, "owner-less",

View File

@ -159,9 +159,7 @@ std::shared_ptr<Online::XMLRequest> ServersManager::getLANRefreshRequest() const
// --------------------------------------------------------------------
virtual void operation() OVERRIDE
{
ENetAddress addr;
addr.host = STKHost::HOST_ANY;
addr.port = STKHost::PORT_ANY;
ENetAddress addr = {};
setIPv6Socket(UserConfigParams::m_ipv6_lan ? 1 : 0);
NetworkConfig::get()->setIPType(UserConfigParams::m_ipv6_lan ?
NetworkConfig::IP_DUAL_STACK : NetworkConfig::IP_V4);

View File

@ -63,6 +63,33 @@ SocketAddress::SocketAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4,
{
} // SocketAddress(uint8_t,...)
// ----------------------------------------------------------------------------
/** ENetAddress constructor. */
SocketAddress::SocketAddress(const ENetAddress& ea)
{
#ifdef ENABLE_IPV6
if (isIPv6Socket())
{
m_family = AF_INET6;
m_sockaddr = {};
struct sockaddr_in6* in6 = (struct sockaddr_in6*)m_sockaddr.data();
in6->sin6_family = AF_INET6;
in6->sin6_port = htons(ea.port);
// We modify host to use 5 uint32_t (see enet.h)
memcpy(in6->sin6_addr.s6_addr, &ea.host.p0, 16);
in6->sin6_scope_id = ea.host.p4;
}
else
{
setIP(htonl(ea.host.p0));
setPort(ea.port);
}
#else
setIP(htonl(ea.host));
setPort(ea.port);
#endif
} // SocketAddress(const ENetAddress&)
// ----------------------------------------------------------------------------
/** String initialization (Can be IPv4, IPv6 or domain).
* \param str The address (can have a port with :)
@ -680,3 +707,31 @@ void SocketAddress::unitTesting()
assert(ipv6_port.getPort() == 1);
} // unitTesting
// ----------------------------------------------------------------------------
ENetAddress SocketAddress::toENetAddress() const
{
ENetAddress ea = {};
uint32_t ip = getIP();
#ifdef ENABLE_IPV6
if (isIPv6Socket())
{
struct sockaddr_in6* in6 = (struct sockaddr_in6*)m_sockaddr.data();
memcpy(&ea.host.p0, in6->sin6_addr.s6_addr, 16);
ea.host.p4 = in6->sin6_scope_id;
}
else
{
// because ENet wants little endian
ea.host.p0 = ((ip & 0xff000000) >> 24) +
((ip & 0x00ff0000) >> 8) + ((ip & 0x0000ff00) << 8) +
((ip & 0x000000ff) << 24);
}
#else
ea.host = ((ip & 0xff000000) >> 24) +
((ip & 0x00ff0000) >> 8) + ((ip & 0x0000ff00) << 8) +
((ip & 0x000000ff) << 24);
#endif
ea.port = getPort();
return ea;
} // toENetAddress

View File

@ -31,6 +31,7 @@
# include <netinet/in.h>
# include <sys/socket.h>
#endif
#include <enet/enet.h>
#include <array>
#include <cstring>
@ -69,6 +70,8 @@ public:
init(str, port_number, family);
}
// ------------------------------------------------------------------------
SocketAddress(const ENetAddress& ea);
// ------------------------------------------------------------------------
bool operator==(const SocketAddress& other) const;
// ------------------------------------------------------------------------
bool operator!=(const SocketAddress& other) const;
@ -154,6 +157,8 @@ public:
bool isLoopback() const;
// ------------------------------------------------------------------------
void convertForIPv6Socket(bool ipv6);
// ------------------------------------------------------------------------
ENetAddress toENetAddress() const;
}; // SocketAddress
#endif // HEADER_SOCKET_ADDRESS_HPP

View File

@ -256,9 +256,7 @@ STKHost::STKHost(bool server)
init();
m_host_id = std::numeric_limits<uint32_t>::max();
ENetAddress addr;
addr.host = STKHost::HOST_ANY;
ENetAddress addr = {};
if (server)
{
setIPv6Socket(ServerConfig::m_ipv6_server ? 1 : 0);
@ -758,8 +756,7 @@ void STKHost::mainLoop()
if ((NetworkConfig::get()->isLAN() && is_server) ||
NetworkConfig::get()->isPublicServer())
{
ENetAddress eaddr;
eaddr.host = STKHost::HOST_ANY;
ENetAddress eaddr = {};
eaddr.port = stk_config->m_server_discovery_port;
direct_socket = new Network(1, 1, 0, 0, &eaddr);
if (direct_socket->getENetHost() == NULL)
@ -774,7 +771,6 @@ void STKHost::mainLoop()
uint64_t last_ping_time = StkTime::getMonoTimeMs();
uint64_t last_update_speed_time = StkTime::getMonoTimeMs();
uint64_t last_ping_time_update_for_client = StkTime::getMonoTimeMs();
uint64_t last_disconnect_time_update = StkTime::getMonoTimeMs();
std::map<std::string, uint64_t> ctp;
while (m_exit_timeout.load() > StkTime::getMonoTimeMs())
{
@ -812,15 +808,6 @@ void STKHost::mainLoop()
}
} // if discovery host
if (isIPv6Socket() &&
last_disconnect_time_update < StkTime::getMonoTimeMs())
{
// Check per 20 second, client needs to be handled too in case
// the address changed in intercept callback
// (see ConnectToServer::interceptCallback)
last_disconnect_time_update = StkTime::getMonoTimeMs() + 20000;
removeDisconnectedMappedAddress();
}
if (is_server)
{
std::unique_lock<std::mutex> peer_lock(m_peers_mutex);
@ -969,7 +956,12 @@ void STKHost::mainLoop()
// Enet will reuse a disconnected peer so we check here to avoid
// sending to wrong peer
if (peer->state != ENET_PEER_STATE_CONNECTED ||
#ifdef ENABLE_IPV6
(enet_ip_not_equal(ea_peer_now.host, ea.host) &&
ea_peer_now.port != ea.port))
#else
(ea_peer_now.host != ea.host && ea_peer_now.port != ea.port))
#endif
{
if (packet != NULL)
enet_packet_destroy(packet);

View File

@ -69,17 +69,6 @@ enum ENetCommandType : unsigned int
class STKHost
{
public:
/** \brief Defines three host types for the server.
* These values tells the host where he will accept connections from.
*/
enum
{
HOST_ANY = 0, //!< Any host.
HOST_BROADCAST = 0xFFFFFFFF, //!< Defines the broadcast address.
PORT_ANY = 0 //!< Any port.
};
private:
/** Singleton pointer to the instance. */
static STKHost* m_stk_host;

View File

@ -334,188 +334,31 @@ extern "C" int insideIPv6CIDR(const char* ipv6_cidr, const char* ipv6_in)
} // andIPv6
#ifndef ENABLE_IPV6
#include "network/stk_ipv6.hpp"
// ----------------------------------------------------------------------------
int isIPv6Socket()
extern "C" int isIPv6Socket()
{
return 0;
} // isIPV6
// ----------------------------------------------------------------------------
void setIPv6Socket(int val)
extern "C" void setIPv6Socket(int val)
{
} // setIPV6
// ----------------------------------------------------------------------------
std::string getIPV6ReadableFromMappedAddress(const ENetAddress* ea)
{
return "";
} // getIPV6ReadableFromMappedAddress
// ----------------------------------------------------------------------------
void removeDisconnectedMappedAddress()
{
} // removeDisconnectedMappedAddress
// ----------------------------------------------------------------------------
void addMappedAddress(const ENetAddress* ea, const struct sockaddr_in6* in6)
{
} // addMappedAddress
#else
#include "network/stk_ipv6.hpp"
#include "network/protocols/connect_to_server.hpp"
#include "utils/string_utils.hpp"
#include "utils/log.hpp"
#include "utils/time.hpp"
#include "utils/types.hpp"
#include <algorithm>
#include <vector>
// ============================================================================
uint32_t g_mapped_ipv6_used;
int g_ipv6;
struct MappedAddress
{
ENetAddress m_addr;
struct sockaddr_in6 m_in6;
uint64_t m_last_activity;
MappedAddress(const ENetAddress& addr, const struct sockaddr_in6& in6)
{
m_addr = addr;
m_in6 = in6;
m_last_activity = StkTime::getMonoTimeMs();
}
};
std::vector<MappedAddress> g_mapped_ips;
// ============================================================================
int isIPv6Socket()
extern "C" int isIPv6Socket()
{
return g_ipv6;
} // isIPV6
// ----------------------------------------------------------------------------
void setIPv6Socket(int val)
extern "C" void setIPv6Socket(int val)
{
g_ipv6 = val;
} // setIPV6
// ----------------------------------------------------------------------------
void stkInitialize()
{
// Clear previous setting, in case user changed wifi or mobile data
g_mapped_ipv6_used = 0;
g_ipv6 = 0;
g_mapped_ips.clear();
} // stkInitialize
// ----------------------------------------------------------------------------
std::string getIPV6ReadableFromMappedAddress(const ENetAddress* ea)
{
std::string result;
auto it = std::find_if(g_mapped_ips.begin(), g_mapped_ips.end(),
[ea](const MappedAddress& addr)
{
return ea->host == addr.m_addr.host &&
ea->port == addr.m_addr.port;
});
if (it != g_mapped_ips.end())
result = getIPV6ReadableFromIn6(&it->m_in6);
return result;
} // getIPV6ReadableFromMappedAddress
// ----------------------------------------------------------------------------
/** Add a (fake or synthesized by ios / osx) IPv4 address and map it to an IPv6
* one, used in client to set the game server address or server to initialize
* host.
*/
void addMappedAddress(const ENetAddress* ea, const struct sockaddr_in6* in6)
{
g_mapped_ips.emplace_back(*ea, *in6);
} // addMappedAddress
// ----------------------------------------------------------------------------
/* This is called when enet needs to sent to an mapped IPv4 address, we look up
* the map here and get the real IPv6 address, so you need to call
* addMappedAddress above first (for client mostly).
*/
void getIPV6FromMappedAddress(const ENetAddress* ea, struct sockaddr_in6* in6)
{
auto it = std::find_if(g_mapped_ips.begin(), g_mapped_ips.end(),
[ea](const MappedAddress& addr)
{
return ea->host == addr.m_addr.host &&
ea->port == addr.m_addr.port;
});
if (it != g_mapped_ips.end())
{
it->m_last_activity = StkTime::getMonoTimeMs();
memcpy(in6, &it->m_in6, sizeof(struct sockaddr_in6));
}
else
memset(in6, 0, sizeof(struct sockaddr_in6));
} // getIPV6FromMappedAddress
// ----------------------------------------------------------------------------
/* This is called when enet recieved a packet from its socket, we create an
* real IPv4 address out of it or a fake one if it's from IPv6 connection.
*/
void getMappedFromIPV6(const struct sockaddr_in6* in6, ENetAddress* ea)
{
auto it = std::find_if(g_mapped_ips.begin(), g_mapped_ips.end(),
[in6](const MappedAddress& addr)
{
return sameIPV6(in6, &addr.m_in6);
});
if (it != g_mapped_ips.end())
{
it->m_last_activity = StkTime::getMonoTimeMs();
*ea = it->m_addr;
return;
}
if (isIPv4MappedAddress(in6))
{
ea->host = ((in_addr*)(in6->sin6_addr.s6_addr + 12))->s_addr;
ea->port = ntohs(in6->sin6_port);
addMappedAddress(ea, in6);
}
else
{
// Create a fake IPv4 address of 0.x.x.x if it's a real IPv6 connection
if (g_mapped_ipv6_used >= 16777215)
g_mapped_ipv6_used = 0;
*ea = ConnectToServer::toENetAddress(++g_mapped_ipv6_used,
ntohs(in6->sin6_port));
Log::debug("IPv6", "Fake IPv4 address %s mapped to %s",
ConnectToServer::enetAddressToString(*ea).c_str(),
getIPV6ReadableFromIn6(in6).c_str());
addMappedAddress(ea, in6);
}
} // getMappedFromIPV6
// ----------------------------------------------------------------------------
/* Called when a peer is expired (no activity for 20 seconds) and we remove its
* reference to the IPv6.
*/
void removeDisconnectedMappedAddress()
{
for (auto it = g_mapped_ips.begin(); it != g_mapped_ips.end();)
{
if (it->m_last_activity + 20000 < StkTime::getMonoTimeMs())
{
Log::debug("IPv6", "Removing expired %s, IPv4 address %s.",
getIPV6ReadableFromIn6(&it->m_in6).c_str(),
ConnectToServer::enetAddressToString(it->m_addr).c_str());
it = g_mapped_ips.erase(it);
Log::debug("IPv6", "Mapped address size now: %d.",
g_mapped_ips.size());
}
else
it++;
}
} // removeDisconnectedMappedAddress
#endif

View File

@ -23,10 +23,6 @@ extern "C" {
#endif
int isIPv6Socket();
void setIPv6Socket(int val);
void stkInitialize();
void getIPV6FromMappedAddress(const ENetAddress* ea, struct sockaddr_in6* in6);
void getMappedFromIPV6(const struct sockaddr_in6* in6, ENetAddress* ea);
void addMappedAddress(const ENetAddress* ea, const struct sockaddr_in6* in6);
int getaddrinfo_compat(const char* hostname, const char* servname,
const struct addrinfo* hints, struct addrinfo** res);
int64_t upperIPv6(const char* ipv6);
@ -34,9 +30,7 @@ int insideIPv6CIDR(const char* ipv6_cidr, const char* ipv6_in);
#ifdef __cplusplus
}
#endif
std::string getIPV6ReadableFromMappedAddress(const ENetAddress* ea);
std::string getIPV6ReadableFromIn6(const struct sockaddr_in6* in);
bool sameIPV6(const struct sockaddr_in6* in_1,
const struct sockaddr_in6* in_2);
void removeDisconnectedMappedAddress();
bool isIPv4MappedAddress(const struct sockaddr_in6* in6);

View File

@ -39,25 +39,7 @@ STKPeer::STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id)
: m_address(enet_peer->address), m_host(host)
{
m_addons_scores.fill(-1);
uint32_t addr = htonl(enet_peer->address.host);
#ifdef ENABLE_IPV6
if (isIPv6Socket())
{
// This will return the mapped IPv4 address too for IPv6 socket
// So we can sendto directly with it
struct sockaddr_in6 in6 = {};
getIPV6FromMappedAddress(&enet_peer->address, &in6);
m_socket_address.reset(new SocketAddress());
m_socket_address->setSockAddrIn(AF_INET6, (sockaddr*)&in6, sizeof(in6));
if (m_socket_address->isIPv6())
m_ipv6_address = m_socket_address->toString(false/*show_port*/);
}
else
#endif
{
m_socket_address.reset(
new SocketAddress(addr, enet_peer->address.port));
}
m_socket_address.reset(new SocketAddress(m_address));
m_enet_peer = enet_peer;
m_host_id = host_id;
m_connected_time = StkTime::getMonoTimeMs();

View File

@ -117,8 +117,6 @@ protected:
std::string m_user_version;
std::string m_ipv6_address;
/** List of client capabilities set when connecting it, to determine
* features available in same version. */
std::set<std::string> m_client_capabilities;
@ -140,8 +138,6 @@ public:
// ------------------------------------------------------------------------
bool isConnected() const;
// ------------------------------------------------------------------------
const std::string& getIPV6Address() const { return m_ipv6_address; }
// ------------------------------------------------------------------------
bool isSamePeer(const STKPeer* peer) const;
bool isSamePeer(const ENetPeer* peer) const;
// ------------------------------------------------------------------------