Zebediah Figura : ws2_32: Move gethostbyaddr() to the Unix library.
Alexandre Julliard
julliard at winehq.org
Wed Aug 4 16:41:36 CDT 2021
Module: wine
Branch: master
Commit: 684f03c4a3f7b1290ce69f6db133b6ecf27139ca
URL: https://source.winehq.org/git/wine.git/?a=commit;h=684f03c4a3f7b1290ce69f6db133b6ecf27139ca
Author: Zebediah Figura <zfigura at codeweavers.com>
Date: Tue Aug 3 23:53:35 2021 -0500
ws2_32: Move gethostbyaddr() to the Unix library.
Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ws2_32/protocol.c | 66 ++++----------------
dlls/ws2_32/unixlib.c | 141 +++++++++++++++++++++++++++++++++++++++++++
dlls/ws2_32/ws2_32_private.h | 2 +
3 files changed, 154 insertions(+), 55 deletions(-)
diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c
index eb97e0d612d..2a7200ee137 100644
--- a/dlls/ws2_32/protocol.c
+++ b/dlls/ws2_32/protocol.c
@@ -67,19 +67,6 @@ static const int ws_af_map[][2] =
{FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
};
-static int convert_af_w2u( int family )
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(ws_af_map); i++)
- {
- if (ws_af_map[i][0] == family)
- return ws_af_map[i][1];
- }
- FIXME( "unhandled Windows address family %d\n", family );
- return -1;
-}
-
static int convert_af_u2w( int family )
{
unsigned int i;
@@ -839,54 +826,23 @@ static struct WS_hostent *hostent_from_unix( const struct hostent *p_he )
/***********************************************************************
* gethostbyaddr (ws2_32.51)
*/
-struct WS_hostent * WINAPI WS_gethostbyaddr( const char *addr, int len, int type )
+struct WS_hostent * WINAPI WS_gethostbyaddr( const char *addr, int len, int family )
{
- struct WS_hostent *retval = NULL;
- struct hostent *host;
- int unixtype = convert_af_w2u(type);
- const char *paddr = addr;
- unsigned long loopback;
-#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
- char *extrabuf;
- int ebufsize = 1024;
- struct hostent hostentry;
- int locerr = ENOBUFS;
-#endif
+ unsigned int size = 1024;
+ struct WS_hostent *host;
+ int ret;
- /* convert back the magic loopback address if necessary */
- if (unixtype == AF_INET && len == 4 && !memcmp( addr, magic_loopback_addr, 4 ))
- {
- loopback = htonl( INADDR_LOOPBACK );
- paddr = (char *)&loopback;
- }
+ if (!(host = get_hostent_buffer( size )))
+ return NULL;
-#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
- host = NULL;
- extrabuf = HeapAlloc( GetProcessHeap(), 0, ebufsize );
- while (extrabuf)
+ while ((ret = unix_funcs->gethostbyaddr( addr, len, family, host, &size )) == ERROR_INSUFFICIENT_BUFFER)
{
- int res = gethostbyaddr_r( paddr, len, unixtype, &hostentry, extrabuf, ebufsize, &host, &locerr );
- if (res != ERANGE) break;
- ebufsize *= 2;
- extrabuf = HeapReAlloc( GetProcessHeap(), 0, extrabuf, ebufsize );
+ if (!(host = get_hostent_buffer( size )))
+ return NULL;
}
- if (host)
- retval = hostent_from_unix( host );
- else
- SetLastError( (locerr < 0) ? sock_get_error( errno ) : host_errno_from_unix( locerr ) );
- HeapFree( GetProcessHeap(), 0, extrabuf );
-#else
- EnterCriticalSection( &csWSgetXXXbyYYY );
- host = gethostbyaddr( paddr, len, unixtype );
- if (host)
- retval = hostent_from_unix( host );
- else
- SetLastError( (h_errno < 0) ? sock_get_error( errno ) : host_errno_from_unix( h_errno ) );
- LeaveCriticalSection( &csWSgetXXXbyYYY );
-#endif
- TRACE( "ptr %p, len %d, type %d ret %p\n", addr, len, type, retval );
- return retval;
+ SetLastError( ret );
+ return ret ? NULL : host;
}
diff --git a/dlls/ws2_32/unixlib.c b/dlls/ws2_32/unixlib.c
index 2ed8ce2f762..2423ef5aa2e 100644
--- a/dlls/ws2_32/unixlib.c
+++ b/dlls/ws2_32/unixlib.c
@@ -28,6 +28,7 @@
#include "config.h"
#include <errno.h>
+#include <pthread.h>
#include <stdarg.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
@@ -75,6 +76,10 @@
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
+#ifndef HAVE_LINUX_GETHOSTBYNAME_R_6
+static pthread_mutex_t host_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
#define MAP(x) {WS_ ## x, x}
static const int addrinfo_flag_map[][2] =
@@ -319,6 +324,24 @@ static unsigned int errno_from_unix( int err )
}
}
+static UINT host_errno_from_unix( int err )
+{
+ WARN( "%d\n", err );
+
+ switch (err)
+ {
+ case HOST_NOT_FOUND: return WSAHOST_NOT_FOUND;
+ case TRY_AGAIN: return WSATRY_AGAIN;
+ case NO_RECOVERY: return WSANO_RECOVERY;
+ case NO_DATA: return WSANO_DATA;
+ case ENOBUFS: return WSAENOBUFS;
+ case 0: return 0;
+ default:
+ WARN( "Unknown h_errno %d!\n", err );
+ return WSAEOPNOTSUPP;
+ }
+}
+
static int addrinfo_err_from_unix( int err )
{
switch (err)
@@ -595,9 +618,127 @@ static int CDECL unix_getaddrinfo( const char *node, const char *service, const
#endif
}
+
+static int hostent_from_unix( const struct hostent *unix_host, struct WS_hostent *host, unsigned int *const size )
+{
+ unsigned int needed_size = sizeof( struct WS_hostent ), alias_count = 0, addr_count = 0, i;
+ char *p;
+
+ needed_size += strlen( unix_host->h_name );
+
+ for (alias_count = 0; unix_host->h_aliases[alias_count] != NULL; ++alias_count)
+ needed_size += sizeof(char *) + strlen( unix_host->h_aliases[alias_count] ) + 1;
+ needed_size += sizeof(char *); /* null terminator */
+
+ for (addr_count = 0; unix_host->h_addr_list[addr_count] != NULL; ++addr_count)
+ needed_size += sizeof(char *) + unix_host->h_length;
+ needed_size += sizeof(char *); /* null terminator */
+
+ if (*size < needed_size)
+ {
+ *size = needed_size;
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ memset( host, 0, needed_size );
+
+ /* arrange the memory in the same order as windows >= XP */
+
+ host->h_addrtype = family_from_unix( unix_host->h_addrtype );
+ host->h_length = unix_host->h_length;
+
+ p = (char *)(host + 1);
+ host->h_aliases = (char **)p;
+ p += (alias_count + 1) * sizeof(char *);
+ host->h_addr_list = (char **)p;
+ p += (addr_count + 1) * sizeof(char *);
+
+ for (i = 0; i < addr_count; ++i)
+ {
+ host->h_addr_list[i] = p;
+ memcpy( host->h_addr_list[i], unix_host->h_addr_list[i], unix_host->h_length );
+ p += unix_host->h_length;
+ }
+
+ for (i = 0; i < alias_count; ++i)
+ {
+ size_t len = strlen( unix_host->h_aliases[i] ) + 1;
+
+ host->h_aliases[i] = p;
+ memcpy( host->h_aliases[i], unix_host->h_aliases[i], len );
+ p += len;
+ }
+
+ host->h_name = p;
+ strcpy( host->h_name, unix_host->h_name );
+
+ return 0;
+}
+
+
+static int CDECL unix_gethostbyaddr( const void *addr, int len, int family,
+ struct WS_hostent *const host, unsigned int *size )
+{
+ const struct in_addr loopback = { htonl( INADDR_LOOPBACK ) };
+ int unix_family = family_to_unix( family );
+ struct hostent *unix_host;
+ int ret;
+
+ if (family == WS_AF_INET && len == 4 && !memcmp( addr, magic_loopback_addr, 4 ))
+ addr = &loopback;
+
+#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
+ {
+ char *unix_buffer, *new_buffer;
+ struct hostent stack_host;
+ int unix_size = 1024;
+ int locerr;
+
+ if (!(unix_buffer = malloc( unix_size )))
+ return WSAENOBUFS;
+
+ while (gethostbyaddr_r( addr, len, unix_family, &stack_host, unix_buffer,
+ unix_size, &unix_host, &locerr ) == ERANGE)
+ {
+ unix_size *= 2;
+ if (!(new_buffer = realloc( unix_buffer, unix_size )))
+ {
+ free( unix_buffer );
+ return WSAENOBUFS;
+ }
+ unix_buffer = new_buffer;
+ }
+
+ if (!unix_host)
+ return (locerr < 0 ? errno_from_unix( errno ) : host_errno_from_unix( locerr ));
+
+ ret = hostent_from_unix( unix_host, host, size );
+
+ free( unix_buffer );
+ return ret;
+ }
+#else
+ pthread_mutex_lock( &host_mutex );
+
+ if (!(unix_host = gethostbyaddr( addr, len, unix_family )))
+ {
+ ret = (h_errno < 0 ? errno_from_unix( errno ) : host_errno_from_unix( h_errno ));
+ pthread_mutex_unlock( &host_mutex );
+ return ret;
+ }
+
+ ret = hostent_from_unix( unix_host, host, size );
+
+ pthread_mutex_unlock( &host_mutex );
+ return ret;
+#endif
+}
+
+
static const struct unix_funcs funcs =
{
unix_getaddrinfo,
+ unix_gethostbyaddr,
};
NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h
index 5c0f0af5bd9..f9224306a7c 100644
--- a/dlls/ws2_32/ws2_32_private.h
+++ b/dlls/ws2_32/ws2_32_private.h
@@ -200,6 +200,8 @@ struct unix_funcs
{
int (CDECL *getaddrinfo)( const char *node, const char *service, const struct WS(addrinfo) *hints,
struct WS(addrinfo) *info, unsigned int *size );
+ int (CDECL *gethostbyaddr)( const void *addr, int len, int family,
+ struct WS(hostent) *host, unsigned int *size );
};
extern const struct unix_funcs *unix_funcs;
More information about the wine-cvs
mailing list