1
0
forked from 0ad/0ad

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:
janwas 2007-06-04 23:55:29 +00:00
parent d802b73d94
commit 0db787bf58
4 changed files with 96 additions and 82 deletions

View File

@ -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))
{

View File

@ -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;
}

View File

@ -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))

View File

@ -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,