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