Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ws2_32/protocol.c | 44 +++++++++++++++------ dlls/ws2_32/unixlib.c | 75 ++++++++++++++++-------------------- dlls/ws2_32/ws2_32_private.h | 4 +- 3 files changed, 67 insertions(+), 56 deletions(-)
diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c index 7b6e68555b0..eb97e0d612d 100644 --- a/dlls/ws2_32/protocol.c +++ b/dlls/ws2_32/protocol.c @@ -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 ); }
diff --git a/dlls/ws2_32/unixlib.c b/dlls/ws2_32/unixlib.c index 4b63e8e6415..2ed8ce2f762 100644 --- a/dlls/ws2_32/unixlib.c +++ b/dlls/ws2_32/unixlib.c @@ -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; diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h index 5fd083eac31..5c0f0af5bd9 100644 --- a/dlls/ws2_32/ws2_32_private.h +++ b/dlls/ws2_32/ws2_32_private.h @@ -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;