wsock: fix init problem (if getnameinfo et al were the first function called from winsock - as happens when using quickstart - ws2_32 wasn't loaded first)
This was SVN commit r5142.
This commit is contained in:
parent
d802b73d94
commit
0db787bf58
@ -671,7 +671,8 @@ LONG WINAPI wdbg_exception_filter(EXCEPTION_POINTERS* ep)
|
||||
//-----------------------------------------------------------------------------
|
||||
// install SEH exception handler
|
||||
|
||||
typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)(_EXCEPTION_RECORD* ExceptionRecord, PVOID EstablisherFrame, _CONTEXT* ContextRecord, PVOID DispatcherContext);
|
||||
typedef EXCEPTION_DISPOSITION (*PEXCEPTION_ROUTINE)(_EXCEPTION_RECORD* ExceptionRecord,
|
||||
PVOID EstablisherFrame, _CONTEXT* ContextRecord, PVOID DispatcherContext);
|
||||
|
||||
struct _EXCEPTION_REGISTRATION_RECORD
|
||||
{
|
||||
@ -684,7 +685,8 @@ static bool IsUnwinding(DWORD exceptionFlags)
|
||||
return (exceptionFlags & 2) != 0;
|
||||
}
|
||||
|
||||
static EXCEPTION_DISPOSITION ExceptionHandler(_EXCEPTION_RECORD* ExceptionRecord, PVOID EstablisherFrame, _CONTEXT* ContextRecord, PVOID DispatcherContext)
|
||||
static EXCEPTION_DISPOSITION ExceptionHandler(_EXCEPTION_RECORD* ExceptionRecord,
|
||||
PVOID UNUSED(EstablisherFrame), _CONTEXT* ContextRecord, PVOID UNUSED(DispatcherContext))
|
||||
{
|
||||
if(!IsUnwinding(ExceptionRecord->ExceptionFlags))
|
||||
{
|
||||
|
@ -23,10 +23,6 @@
|
||||
WINIT_REGISTER_MAIN_INIT(wsock_Init);
|
||||
WINIT_REGISTER_MAIN_SHUTDOWN(wsock_Shutdown);
|
||||
|
||||
uint16_t htons(uint16_t s)
|
||||
{
|
||||
return (s >> 8) | ((s & 0xff) << 8);
|
||||
}
|
||||
|
||||
// IPv6 globals
|
||||
// These are included in the linux C libraries and in newer platform SDKs,
|
||||
@ -36,56 +32,79 @@ const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; // ::_1
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// manual import of certain functions
|
||||
// 'optional' IPv6 routines
|
||||
|
||||
// don't delay-load because we don't want to require these functions to be
|
||||
// present. the user must be able to check if they are available (currently,
|
||||
// on Win2k with IPv6 update or WinXP). can't use compile-time HAVE_* to
|
||||
// make that decision because we don't want to distribute a separate EXE.
|
||||
// we hide the function pointers behind stub functions - this avoids
|
||||
// surprising users. speed is irrelevant here. manually writing these stubs
|
||||
// is ugly, but delay-load error handling is hairy, so don't use that.
|
||||
//
|
||||
// the first call of these stubs must trigger wsock_ActualInit in case no
|
||||
// other winsock function was called yet. we can't simply rely on
|
||||
// ModuleShouldInitialize because taking references prevents shutdown.
|
||||
// adding an extra haveInitialized flag would be redundant. instead,
|
||||
// enter a clever but safe hack: we call a harmless winsock function that
|
||||
// triggers the delay load or does nothing if init has already happened.
|
||||
|
||||
// function pointers, automatically initialized before any use of ws2_32.dll
|
||||
static int (WINAPI *pgetnameinfo)(const struct sockaddr*, socklen_t, char*, socklen_t, char*, socklen_t, unsigned int);
|
||||
static int (WINAPI *pgetaddrinfo)(const char*, const char*, const struct addrinfo*, struct addrinfo**);
|
||||
static void (WINAPI *pfreeaddrinfo)(struct addrinfo*);
|
||||
|
||||
static HMODULE hWs2_32Dll;
|
||||
|
||||
static void ImportOptionalFunctions()
|
||||
{
|
||||
*(void**)&pgetnameinfo = GetProcAddress(hWs2_32Dll, "getnameinfo");
|
||||
*(void**)&pgetaddrinfo = GetProcAddress(hWs2_32Dll, "getaddrinfo");
|
||||
*(void**)&pfreeaddrinfo = GetProcAddress(hWs2_32Dll, "freeaddrinfo");
|
||||
}
|
||||
|
||||
int getnameinfo(const struct sockaddr* sa, socklen_t salen, char* host, socklen_t hostlen, char* serv, socklen_t servlen, unsigned int flags)
|
||||
{
|
||||
(void)htonl(0); // trigger init if not done already
|
||||
if(!pgetnameinfo)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pgetnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
|
||||
}
|
||||
|
||||
int getaddrinfo(const char* nodename, const char* servname, const struct addrinfo* hints, struct addrinfo** res)
|
||||
{
|
||||
(void)htonl(0); // trigger init if not done already
|
||||
if(!pgetaddrinfo)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pgetaddrinfo(nodename, servname, hints, res);
|
||||
}
|
||||
|
||||
void freeaddrinfo(struct addrinfo* ai)
|
||||
{
|
||||
// (no dummy htonl call or checking of the function pointer is needed
|
||||
// since getaddrinfo must succeed to get a valid addrinfo*.)
|
||||
|
||||
pfreeaddrinfo(ai);
|
||||
}
|
||||
|
||||
|
||||
static void ImportOptionalFunctions()
|
||||
{
|
||||
// (by the time we get here, ws2_32.dll will have been loaded, so
|
||||
// this isn't the only reference and can be freed immediately)
|
||||
HMODULE hWs2_32Dll = LoadLibrary("ws2_32.dll");
|
||||
*(void**)&pgetnameinfo = GetProcAddress(hWs2_32Dll, "getnameinfo");
|
||||
*(void**)&pgetaddrinfo = GetProcAddress(hWs2_32Dll, "getaddrinfo");
|
||||
*(void**)&pfreeaddrinfo = GetProcAddress(hWs2_32Dll, "freeaddrinfo");
|
||||
FreeLibrary(hWs2_32Dll);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static ModuleInitState initState;
|
||||
|
||||
// called from delay loader the first time a wsock function is called
|
||||
// (shortly before the actual wsock function is called).
|
||||
static LibError wsock_actual_init()
|
||||
static LibError wsock_ActualInit()
|
||||
{
|
||||
if(!ModuleShouldInitialize(&initState))
|
||||
return INFO::OK;
|
||||
|
||||
hWs2_32Dll = LoadLibrary("ws2_32.dll");
|
||||
|
||||
char d[1024];
|
||||
int ret = WSAStartup(0x0002, d); // want 2.0
|
||||
debug_assert(ret == 0);
|
||||
@ -97,8 +116,8 @@ static LibError wsock_actual_init()
|
||||
|
||||
static LibError wsock_Init()
|
||||
{
|
||||
// trigger wsock_actual_init when someone first calls a wsock function.
|
||||
static WdllLoadNotify loadNotify = { "ws2_32", wsock_actual_init };
|
||||
// trigger wsock_ActualInit when someone first calls a winsock function.
|
||||
static WdllLoadNotify loadNotify = { "ws2_32", wsock_ActualInit };
|
||||
wdll_add_notify(&loadNotify);
|
||||
return INFO::OK;
|
||||
}
|
||||
@ -112,7 +131,5 @@ static LibError wsock_Shutdown()
|
||||
int ret = WSACleanup();
|
||||
debug_assert(ret >= 0);
|
||||
|
||||
FreeLibrary(hWs2_32Dll);
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
@ -169,6 +169,8 @@ struct addrinfo
|
||||
#define NI_MAXHOST 1025
|
||||
#define NI_MAXSERV 32
|
||||
|
||||
// these functions are only supported on WinXP+, and Win2k with IPv6 update.
|
||||
// otherwise, they return -1 with errno = ENOSYS.
|
||||
extern int getnameinfo(const struct sockaddr*, socklen_t, char*, socklen_t, char*, socklen_t, unsigned int);
|
||||
extern int getaddrinfo(const char*, const char*, const struct addrinfo*, struct addrinfo**);
|
||||
extern void freeaddrinfo(struct addrinfo*);
|
||||
@ -183,10 +185,10 @@ extern void freeaddrinfo(struct addrinfo*);
|
||||
// <arpa/inet.h>
|
||||
//
|
||||
|
||||
extern uint16_t htons(uint16_t hostshort);
|
||||
#define ntohs htons
|
||||
IMP(unsigned short, htons, (unsigned short hostlong))
|
||||
IMP(unsigned short, ntohs, (unsigned short hostlong))
|
||||
IMP(unsigned long, htonl, (unsigned long hostlong))
|
||||
|
||||
IMP(unsigned long, ntohl, (unsigned long hostlong))
|
||||
|
||||
IMP(in_addr_t, inet_addr, (const char*))
|
||||
IMP(char*, inet_ntoa, (in_addr))
|
||||
|
@ -106,67 +106,60 @@ CSocketAddress CSocketAddress::Loopback(int port, ESocketProtocol proto)
|
||||
|
||||
PS_RESULT CSocketAddress::Resolve(const char *name, int port, CSocketAddress &addr)
|
||||
{
|
||||
if ((getaddrinfo) != NULL)
|
||||
addrinfo *ai;
|
||||
int res=getaddrinfo(name, NULL, NULL, &ai);
|
||||
if (res == 0)
|
||||
{
|
||||
addrinfo *ai;
|
||||
int res=getaddrinfo(name, NULL, NULL, &ai);
|
||||
if (res == 0)
|
||||
if (ai->ai_addrlen < sizeof(addr.m_Union))
|
||||
cpu_memcpy(&addr.m_Union, ai->ai_addr, ai->ai_addrlen);
|
||||
switch (addr.m_Union.m_Family)
|
||||
{
|
||||
if (ai->ai_addrlen < sizeof(addr.m_Union))
|
||||
cpu_memcpy(&addr.m_Union, ai->ai_addr, ai->ai_addrlen);
|
||||
switch (addr.m_Union.m_Family)
|
||||
{
|
||||
case IPv4:
|
||||
addr.m_Union.m_IPv4.sin_port=htons(port);
|
||||
break;
|
||||
case IPv6:
|
||||
addr.m_Union.m_IPv6.sin6_port=htons(port);
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
return PS_OK;
|
||||
}
|
||||
else
|
||||
return NO_SUCH_HOST;
|
||||
}
|
||||
else
|
||||
{
|
||||
hostent *he;
|
||||
|
||||
addr.m_Union.m_IPv4.sin_family=AF_INET;
|
||||
addr.m_Union.m_IPv4.sin_port=htons(port);
|
||||
// Try to parse dot-notation IP
|
||||
addr.m_Union.m_IPv4.sin_addr.s_addr=inet_addr(name);
|
||||
if (addr.m_Union.m_IPv4.sin_addr.s_addr==INADDR_NONE) // Not a dotted IP, try name resolution
|
||||
{
|
||||
he=gethostbyname(name);
|
||||
if (!he)
|
||||
{
|
||||
return NO_SUCH_HOST;
|
||||
}
|
||||
addr.m_Union.m_IPv4.sin_addr=*(struct in_addr *)(he->h_addr_list[0]);
|
||||
case IPv4:
|
||||
addr.m_Union.m_IPv4.sin_port=htons(port);
|
||||
break;
|
||||
case IPv6:
|
||||
addr.m_Union.m_IPv6.sin6_port=htons(port);
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
return PS_OK;
|
||||
}
|
||||
// supported, but failed
|
||||
if (errno != ENOSYS)
|
||||
return NO_SUCH_HOST;
|
||||
// else: IPv6 not supported, fall back to IPv4
|
||||
|
||||
hostent *he;
|
||||
|
||||
addr.m_Union.m_IPv4.sin_family=AF_INET;
|
||||
addr.m_Union.m_IPv4.sin_port=htons(port);
|
||||
// Try to parse dot-notation IP
|
||||
addr.m_Union.m_IPv4.sin_addr.s_addr=inet_addr(name);
|
||||
if (addr.m_Union.m_IPv4.sin_addr.s_addr==INADDR_NONE) // Not a dotted IP, try name resolution
|
||||
{
|
||||
he=gethostbyname(name);
|
||||
if (!he)
|
||||
return NO_SUCH_HOST;
|
||||
addr.m_Union.m_IPv4.sin_addr=*(struct in_addr *)(he->h_addr_list[0]);
|
||||
}
|
||||
return PS_OK;
|
||||
}
|
||||
|
||||
CStr CSocketAddress::GetString() const
|
||||
{
|
||||
char convBuf[NI_MAXHOST];
|
||||
if ((getnameinfo) != NULL)
|
||||
{
|
||||
int res=getnameinfo((sockaddr *)&m_Union, sizeof(m_Union), convBuf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
||||
if (res == 0)
|
||||
{
|
||||
return CStr(convBuf);
|
||||
}
|
||||
// getnameinfo won't return a string for the IPv6 unspecified address
|
||||
else if (m_Union.m_Family == IPv6 && res==EAI_NONAME)
|
||||
return "::";
|
||||
else
|
||||
return "";
|
||||
}
|
||||
else if (m_Union.m_Family == IPv4)
|
||||
int res=getnameinfo((sockaddr *)&m_Union, sizeof(m_Union), convBuf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
||||
if (res == 0)
|
||||
return CStr(convBuf);
|
||||
// getnameinfo won't return a string for the IPv6 unspecified address
|
||||
else if (m_Union.m_Family == IPv6 && res==EAI_NONAME)
|
||||
return "::";
|
||||
// supported, but failed
|
||||
else if (errno != ENOSYS)
|
||||
return "";
|
||||
// else: IPv6 not supported, fall back to IPv4
|
||||
|
||||
if (m_Union.m_Family == IPv4)
|
||||
{
|
||||
sprintf(convBuf, "%d.%d.%d.%d",
|
||||
m_Union.m_IPv4.sin_addr.s_addr&0xff,
|
||||
|
Loading…
Reference in New Issue
Block a user