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; 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) 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 * by sending a NULL host and avoid sending a NULL servname too because that
* is invalid */ * is invalid */
ERR_(winediag)( "Failed to resolve your host name IP\n" ); 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) if (!ret && hints && (hints->ai_flags & WS_AI_CANONNAME) && *info && !(*info)->ai_canonname)
{ {
WS_freeaddrinfo( *info ); WS_freeaddrinfo( *info );
@ -542,18 +569,11 @@ int WINAPI GetAddrInfoW(const WCHAR *nodename, const WCHAR *servname, const ADDR
/*********************************************************************** /***********************************************************************
* freeaddrinfo (ws2_32.@) * freeaddrinfo (ws2_32.@)
*/ */
void WINAPI WS_freeaddrinfo( struct WS_addrinfo *res ) void WINAPI WS_freeaddrinfo( struct WS_addrinfo *info )
{ {
while (res) TRACE( "%p\n", info );
{
struct WS_addrinfo *next;
HeapFree( GetProcessHeap(), 0, res->ai_canonname ); HeapFree( GetProcessHeap(), 0, info );
HeapFree( GetProcessHeap(), 0, res->ai_addr );
next = res->ai_next;
HeapFree( GetProcessHeap(), 0, res );
res = next;
}
} }

View File

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

View File

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