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:
parent
edc3b93c9b
commit
b98053a34f
16
SConstruct
16
SConstruct
|
@ -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='''
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue