ws2_32: Allocate the addrinfo buffer on the PE side.

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-08-03 23:53:34 -05:00 committed by Alexandre Julliard
parent e58405000c
commit d6555b966e
3 changed files with 67 additions and 56 deletions

View File

@ -130,6 +130,33 @@ static char *get_fqdn(void)
return ret;
}
/* call Unix getaddrinfo, allocating a large enough buffer */
static int do_getaddrinfo( const char *node, const char *service,
const struct WS_addrinfo *hints, struct WS_addrinfo **info )
{
struct WS_addrinfo *buffer, *new_buffer;
unsigned int size = 1024;
int ret;
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size )))
return WSA_NOT_ENOUGH_MEMORY;
while ((ret = unix_funcs->getaddrinfo( node, service, hints, buffer, &size )) == ERROR_INSUFFICIENT_BUFFER)
{
if (!(new_buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, size )))
{
HeapFree( GetProcessHeap(), 0, buffer );
return WSA_NOT_ENOUGH_MEMORY;
}
buffer = new_buffer;
}
if (!ret)
*info = buffer;
else
HeapFree( GetProcessHeap(), 0, buffer );
return ret;
}
/***********************************************************************
@ -173,7 +200,7 @@ int WINAPI WS_getaddrinfo( const char *node, const char *service,
}
}
ret = unix_funcs->getaddrinfo( node, service, hints, info );
ret = do_getaddrinfo( node, service, hints, info );
if (ret && (!hints || !(hints->ai_flags & WS_AI_NUMERICHOST)) && node)
{
@ -188,7 +215,7 @@ int WINAPI WS_getaddrinfo( const char *node, const char *service,
* by sending a NULL host and avoid sending a NULL servname too because that
* is invalid */
ERR_(winediag)( "Failed to resolve your host name IP\n" );
ret = unix_funcs->getaddrinfo( NULL, service, hints, info );
ret = do_getaddrinfo( NULL, service, hints, info );
if (!ret && hints && (hints->ai_flags & WS_AI_CANONNAME) && *info && !(*info)->ai_canonname)
{
WS_freeaddrinfo( *info );
@ -542,18 +569,11 @@ int WINAPI GetAddrInfoW(const WCHAR *nodename, const WCHAR *servname, const ADDR
/***********************************************************************
* freeaddrinfo (ws2_32.@)
*/
void WINAPI WS_freeaddrinfo( struct WS_addrinfo *res )
void WINAPI WS_freeaddrinfo( struct WS_addrinfo *info )
{
while (res)
{
struct WS_addrinfo *next;
TRACE( "%p\n", info );
HeapFree( GetProcessHeap(), 0, res->ai_canonname );
HeapFree( GetProcessHeap(), 0, res->ai_addr );
next = res->ai_next;
HeapFree( GetProcessHeap(), 0, res );
res = next;
}
HeapFree( GetProcessHeap(), 0, info );
}

View File

@ -468,17 +468,16 @@ static BOOL addrinfo_in_list( const struct WS_addrinfo *list, const struct WS_ad
return FALSE;
}
static int CDECL unix_getaddrinfo( const char *node, const char *service,
const struct WS_addrinfo *hints, struct WS_addrinfo **info )
static int CDECL unix_getaddrinfo( const char *node, const char *service, const struct WS_addrinfo *hints,
struct WS_addrinfo *info, unsigned int *size )
{
#ifdef HAVE_GETADDRINFO
struct addrinfo unix_hints = {0};
struct addrinfo *unix_info, *src;
struct WS_addrinfo *dst, *prev = NULL;
unsigned int needed_size = 0;
int ret;
*info = NULL;
/* servname tweak required by OSX and BSD kernels */
if (service && !service[0]) service = "0";
@ -528,12 +527,28 @@ static int CDECL unix_getaddrinfo( const char *node, const char *service,
if (ret)
return addrinfo_err_from_unix( ret );
*info = NULL;
for (src = unix_info; src != NULL; src = src->ai_next)
{
needed_size += sizeof(struct WS_addrinfo);
if (src->ai_canonname)
needed_size += strlen( src->ai_canonname ) + 1;
needed_size += sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, NULL, 0 );
}
if (*size < needed_size)
{
*size = needed_size;
freeaddrinfo( unix_info );
return ERROR_INSUFFICIENT_BUFFER;
}
dst = info;
memset( info, 0, needed_size );
for (src = unix_info; src != NULL; src = src->ai_next)
{
if (!(dst = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dst) )))
goto fail;
void *next = dst + 1;
dst->ai_flags = addrinfo_flags_from_unix( src->ai_flags );
dst->ai_family = family_from_unix( src->ai_family );
@ -549,55 +564,31 @@ static int CDECL unix_getaddrinfo( const char *node, const char *service,
}
if (src->ai_canonname)
{
if (!(dst->ai_canonname = RtlAllocateHeap( GetProcessHeap(), 0, strlen( src->ai_canonname ) + 1 )))
{
RtlFreeHeap( GetProcessHeap(), 0, dst );
goto fail;
}
strcpy( dst->ai_canonname, src->ai_canonname );
size_t len = strlen( src->ai_canonname ) + 1;
dst->ai_canonname = next;
memcpy( dst->ai_canonname, src->ai_canonname, len );
next = dst->ai_canonname + len;
}
dst->ai_addrlen = sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, NULL, 0 );
if (!(dst->ai_addr = RtlAllocateHeap( GetProcessHeap(), 0, dst->ai_addrlen )))
{
RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
RtlFreeHeap( GetProcessHeap(), 0, dst );
goto fail;
}
dst->ai_addr = next;
sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, dst->ai_addr, dst->ai_addrlen );
next = (char *)dst->ai_addr + dst->ai_addrlen;
if (addrinfo_in_list( *info, dst ))
{
RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
RtlFreeHeap( GetProcessHeap(), 0, dst->ai_addr );
RtlFreeHeap( GetProcessHeap(), 0, dst );
}
else
if (dst == info || !addrinfo_in_list( info, dst ))
{
if (prev)
prev->ai_next = dst;
else
*info = dst;
prev = dst;
dst = next;
}
}
dst->ai_next = NULL;
freeaddrinfo( unix_info );
return 0;
fail:
dst = *info;
while (dst)
{
struct WS_addrinfo *next;
RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
RtlFreeHeap( GetProcessHeap(), 0, dst->ai_addr );
next = dst->ai_next;
RtlFreeHeap( GetProcessHeap(), 0, dst );
dst = next;
}
return WS_EAI_MEMORY;
#else
FIXME( "getaddrinfo() not found during build time\n" );
return WS_EAI_FAIL;

View File

@ -198,8 +198,8 @@ struct per_thread_data *get_per_thread_data(void) DECLSPEC_HIDDEN;
struct unix_funcs
{
int (CDECL *getaddrinfo)( const char *node, const char *service,
const struct WS(addrinfo) *hints, struct WS(addrinfo) **info );
int (CDECL *getaddrinfo)( const char *node, const char *service, const struct WS(addrinfo) *hints,
struct WS(addrinfo) *info, unsigned int *size );
};
extern const struct unix_funcs *unix_funcs;