Fix Windows net_udp.cpp build

The Windows implementation of inet_ntop incorrectly omits the `const`
qualifier on the input address.  This broke the Windows build, since
Rebirth passes a const-qualified input address, as permitted by POSIX.

Some Windows cross-compilers, such as mingw32, lack a definition of
inet_ntop entirely.  For such environments, fall back to inet_ntoa and
disallow building with IPv6.

Rework the formatting and add a Windows-specific test for whether
inet_ntop is available.  As inet_ntop is specified by POSIX, assume all
modern non-Windows platforms support it.
This commit is contained in:
Kp 2017-04-22 21:23:56 +00:00
parent edc3b93c9b
commit b98053a34f
2 changed files with 77 additions and 6 deletions

View file

@ -2167,6 +2167,22 @@ where the cast is useless.
freeaddrinfo(res);
return 0;
''', msg='for getaddrinfo', successflags=_successflags)
@_guarded_test_windows
def check_inet_ntop_present(self,context,_successflags={'CPPDEFINES' : ['DXX_HAVE_INET_NTOP']}):
# Linux and OS X have working inet_ntop on all supported
# platforms. Only Windows sometimes lacks support for this
# function.
if self.Compile(context, text='''
#include <winsock2.h>
#include <ws2tcpip.h>
''', main='''
struct sockaddr_in sai;
char dbuf[64];
return inet_ntop(AF_INET, &sai.sin_addr, dbuf, sizeof(dbuf)) ? 0 : 1;
''', msg='for inet_ntop', successflags=_successflags):
return
if self.user_settings.ipv6:
raise SCons.Errors.StopError("IPv6 enabled and inet_ntop not available: disable IPv6 or upgrade headers to support inet_ntop.")
@_custom_test
def check_timespec_present(self,context,_successflags={'CPPDEFINES' : ['DXX_HAVE_STRUCT_TIMESPEC']}):
self.Compile(context, text='''

View file

@ -273,13 +273,68 @@ public:
namespace dcx {
static const void *get_addr_from_sockaddr(const _sockaddr &s)
static const char *dxx_ntop(const _sockaddr &sa, array<char, _sockaddr::presentation_buffer_size> &dbuf)
{
#ifdef WIN32
#ifdef DXX_HAVE_INET_NTOP
/*
* Windows and inet_ntop: copy the in_addr/in6_addr to local
* variables because the Microsoft prototype lacks a const
* qualifier.
*/
union {
in_addr ia;
#if DXX_USE_IPv6
if (s.sa.sa_family == AF_INET6)
return &s.sin6.sin6_addr;
in6_addr ia6;
#endif
};
const auto addr =
#if DXX_USE_IPv6
(sa.sa.sa_family == AF_INET6)
? &(ia6 = sa.sin6.sin6_addr)
:
#endif
static_cast<void *>(&(ia = sa.sin.sin_addr));
#else
/*
* Windows and not inet_ntop: only inet_ntoa available.
*
* SConf check_inet_ntop_present enforces that Windows without
* inet_ntop cannot enable IPv6, so the IPv4 branch must be correct
* here.
*
* The reverse is not true. Windows with inet_ntop might not enable
* IPv6.
*/
#if DXX_USE_IPv6
#error "IPv6 requires inet_ntop; SConf should prevent this path"
#endif
dbuf.back() = 0;
/*
* Copy the formatted string to the local buffer `dbuf` to guard
* against concurrent uses of `dxx_ntop`.
*/
return reinterpret_cast<const char *>(memcpy(dbuf.data(), inet_ntoa(sa.sin.sin_addr), dbuf.size() - 1));
#endif
#else
/*
* Not Windows; assume inet_ntop present. Non-Windows platforms
* declare inet_ntop with a const qualifier, so take a pointer to
* the underlying data.
*/
const auto addr =
#if DXX_USE_IPv6
(sa.sa.sa_family == AF_INET6)
? &sa.sin6.sin6_addr
:
#endif
static_cast<const void *>(&sa.sin.sin_addr);
#endif
#if !defined(WIN32) || defined(DXX_HAVE_INET_NTOP)
if (const auto r = inet_ntop(sa.sa.sa_family, addr, dbuf.data(), dbuf.size()))
return r;
return "address";
#endif
return &s.sin.sin_addr;
}
}
@ -803,7 +858,7 @@ static int net_udp_game_connect(direct_join *const dj)
if (timer_query() >= dj->start_time + (F1_0*10))
{
dj->connecting = 0;
char dbuf[_sockaddr::presentation_buffer_size];
array<char, _sockaddr::presentation_buffer_size> dbuf;
const auto port =
#if DXX_USE_IPv6
dj->host_addr.sa.sa_family == AF_INET6
@ -818,7 +873,7 @@ Possible reasons:\n\
* Host port %hu is not open\n\
* Game is hosted on a different port\n\
* Host uses a game version\n\
I do not understand", inet_ntop(dj->host_addr.sa.sa_family, get_addr_from_sockaddr(dj->host_addr), dbuf, sizeof(dbuf)) ? dbuf : "address", ntohs(port));
I do not understand", dxx_ntop(dj->host_addr, dbuf), ntohs(port));
return 0;
}