[PATCH 2/5] ws2_32: Move getaddrinfo() support to a new Unix library.
Zebediah Figura
zfigura at codeweavers.com
Tue Aug 3 23:53:33 CDT 2021
Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
dlls/ws2_32/Makefile.in | 3 +-
dlls/ws2_32/protocol.c | 316 ++----------------
dlls/ws2_32/socket.c | 150 +--------
dlls/ws2_32/tests/protocol.c | 4 +-
dlls/ws2_32/unixlib.c | 618 +++++++++++++++++++++++++++++++++++
dlls/ws2_32/ws2_32_private.h | 12 +-
6 files changed, 673 insertions(+), 430 deletions(-)
create mode 100644 dlls/ws2_32/unixlib.c
diff --git a/dlls/ws2_32/Makefile.in b/dlls/ws2_32/Makefile.in
index 6312b20739d..77983bba66f 100644
--- a/dlls/ws2_32/Makefile.in
+++ b/dlls/ws2_32/Makefile.in
@@ -7,6 +7,7 @@ EXTRALIBS = $(POLL_LIBS)
C_SRCS = \
async.c \
protocol.c \
- socket.c
+ socket.c \
+ unixlib.c
RC_SRCS = version.rc
diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c
index 944f26912e6..7b6e68555b0 100644
--- a/dlls/ws2_32/protocol.c
+++ b/dlls/ws2_32/protocol.c
@@ -33,21 +33,6 @@ DECLARE_CRITICAL_SECTION(csWSgetXXXbyYYY);
#define MAP_OPTION(opt) { WS_##opt, opt }
-static const int ws_aiflag_map[][2] =
-{
- MAP_OPTION( AI_PASSIVE ),
- MAP_OPTION( AI_CANONNAME ),
- MAP_OPTION( AI_NUMERICHOST ),
-#ifdef AI_NUMERICSERV
- MAP_OPTION( AI_NUMERICSERV ),
-#endif
-#ifdef AI_V4MAPPED
- MAP_OPTION( AI_V4MAPPED ),
-#endif
- MAP_OPTION( AI_ALL ),
- MAP_OPTION( AI_ADDRCONFIG ),
-};
-
static const int ws_eai_map[][2] =
{
MAP_OPTION( EAI_AGAIN ),
@@ -82,21 +67,6 @@ static const int ws_af_map[][2] =
{FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
};
-static const int ws_proto_map[][2] =
-{
- MAP_OPTION( IPPROTO_IP ),
- MAP_OPTION( IPPROTO_TCP ),
- MAP_OPTION( IPPROTO_UDP ),
- MAP_OPTION( IPPROTO_IPV6 ),
- MAP_OPTION( IPPROTO_ICMP ),
- MAP_OPTION( IPPROTO_IGMP ),
- MAP_OPTION( IPPROTO_RAW ),
- {WS_IPPROTO_IPV4, IPPROTO_IPIP},
- {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
-};
-
-#define IS_IPX_PROTO(X) ((X) >= WS_NSPROTO_IPX && (X) <= WS_NSPROTO_IPX + 255)
-
static int convert_af_w2u( int family )
{
unsigned int i;
@@ -123,78 +93,6 @@ static int convert_af_u2w( int family )
return -1;
}
-static int convert_proto_w2u( int protocol )
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(ws_proto_map); i++)
- {
- if (ws_proto_map[i][0] == protocol)
- return ws_proto_map[i][1];
- }
-
- if (IS_IPX_PROTO(protocol))
- return protocol;
-
- FIXME( "unhandled Windows socket protocol %d\n", protocol );
- return -1;
-}
-
-static int convert_proto_u2w( int protocol )
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(ws_proto_map); i++)
- {
- if (ws_proto_map[i][1] == protocol)
- return ws_proto_map[i][0];
- }
-
- /* if value is inside IPX range just return it - the kernel simply
- * echoes the value used in the socket() function */
- if (IS_IPX_PROTO(protocol))
- return protocol;
-
- FIXME("unhandled UNIX socket protocol %d\n", protocol);
- return -1;
-}
-
-static int convert_aiflag_w2u( int winflags )
-{
- unsigned int i;
- int unixflags = 0;
-
- for (i = 0; i < ARRAY_SIZE(ws_aiflag_map); i++)
- {
- if (ws_aiflag_map[i][0] & winflags)
- {
- unixflags |= ws_aiflag_map[i][1];
- winflags &= ~ws_aiflag_map[i][0];
- }
- }
- if (winflags)
- FIXME( "Unhandled windows AI_xxx flags 0x%x\n", winflags );
- return unixflags;
-}
-
-static int convert_aiflag_u2w( int unixflags )
-{
- unsigned int i;
- int winflags = 0;
-
- for (i = 0; i < ARRAY_SIZE(ws_aiflag_map); i++)
- {
- if (ws_aiflag_map[i][1] & unixflags)
- {
- winflags |= ws_aiflag_map[i][0];
- unixflags &= ~ws_aiflag_map[i][1];
- }
- }
- if (unixflags)
- WARN( "Unhandled UNIX AI_xxx flags 0x%x\n", unixflags );
- return winflags;
-}
-
int convert_eai_u2w( int unixret )
{
int i;
@@ -232,62 +130,37 @@ static char *get_fqdn(void)
return ret;
}
-static BOOL addrinfo_in_list( const struct WS_addrinfo *list, const struct WS_addrinfo *ai )
-{
- const struct WS_addrinfo *cursor = list;
- while (cursor)
- {
- if (ai->ai_flags == cursor->ai_flags &&
- ai->ai_family == cursor->ai_family &&
- ai->ai_socktype == cursor->ai_socktype &&
- ai->ai_protocol == cursor->ai_protocol &&
- ai->ai_addrlen == cursor->ai_addrlen &&
- !memcmp(ai->ai_addr, cursor->ai_addr, ai->ai_addrlen) &&
- ((ai->ai_canonname && cursor->ai_canonname && !strcmp(ai->ai_canonname, cursor->ai_canonname))
- || (!ai->ai_canonname && !cursor->ai_canonname)))
- {
- return TRUE;
- }
- cursor = cursor->ai_next;
- }
- return FALSE;
-}
/***********************************************************************
* getaddrinfo (ws2_32.@)
*/
-int WINAPI WS_getaddrinfo( const char *nodename, const char *servname,
- const struct WS_addrinfo *hints, struct WS_addrinfo **res )
+int WINAPI WS_getaddrinfo( const char *node, const char *service,
+ const struct WS_addrinfo *hints, struct WS_addrinfo **info )
{
-#ifdef HAVE_GETADDRINFO
- struct addrinfo *unixaires = NULL;
- int result;
- struct addrinfo unixhints, *punixhints = NULL;
char *nodev6 = NULL, *fqdn = NULL;
- const char *node;
+ int ret;
- *res = NULL;
- if (!nodename && !servname)
+ TRACE( "node %s, service %s, hints %p\n", debugstr_a(node), debugstr_a(service), hints );
+
+ *info = NULL;
+
+ if (!node && !service)
{
- SetLastError(WSAHOST_NOT_FOUND);
+ SetLastError( WSAHOST_NOT_FOUND );
return WSAHOST_NOT_FOUND;
}
- if (!nodename)
- node = NULL;
- else if (!nodename[0])
- {
- if (!(fqdn = get_fqdn())) return WSA_NOT_ENOUGH_MEMORY;
- node = fqdn;
- }
- else
+ if (node)
{
- node = nodename;
-
- /* Check for [ipv6] or [ipv6]:portnumber, which are supported by Windows */
- if (!hints || hints->ai_family == WS_AF_UNSPEC || hints->ai_family == WS_AF_INET6)
+ if (!node[0])
{
+ if (!(fqdn = get_fqdn())) return WSA_NOT_ENOUGH_MEMORY;
+ node = fqdn;
+ }
+ else if (!hints || hints->ai_family == WS_AF_UNSPEC || hints->ai_family == WS_AF_INET6)
+ {
+ /* [ipv6] or [ipv6]:portnumber are supported by Windows */
char *close_bracket;
if (node[0] == '[' && (close_bracket = strchr(node + 1, ']')))
@@ -300,50 +173,9 @@ int WINAPI WS_getaddrinfo( const char *nodename, const char *servname,
}
}
- /* servname tweak required by OSX and BSD kernels */
- if (servname && !servname[0]) servname = "0";
-
- if (hints)
- {
- punixhints = &unixhints;
-
- memset( &unixhints, 0, sizeof(unixhints) );
- punixhints->ai_flags = convert_aiflag_w2u( hints->ai_flags );
-
- /* zero is a wildcard, no need to convert */
- if (hints->ai_family)
- punixhints->ai_family = convert_af_w2u( hints->ai_family );
- if (hints->ai_socktype)
- punixhints->ai_socktype = convert_socktype_w2u( hints->ai_socktype );
- if (hints->ai_protocol)
- punixhints->ai_protocol = max( convert_proto_w2u( hints->ai_protocol ), 0 );
-
- if (punixhints->ai_socktype < 0)
- {
- SetLastError( WSAESOCKTNOSUPPORT );
- HeapFree( GetProcessHeap(), 0, fqdn );
- HeapFree( GetProcessHeap(), 0, nodev6 );
- return -1;
- }
-
- /* windows allows invalid combinations of socket type and protocol, unix does not.
- * fix the parameters here to make getaddrinfo call always work */
- if (punixhints->ai_protocol == IPPROTO_TCP
- && punixhints->ai_socktype != SOCK_STREAM
- && punixhints->ai_socktype != SOCK_SEQPACKET)
- punixhints->ai_socktype = 0;
- else if (punixhints->ai_protocol == IPPROTO_UDP && punixhints->ai_socktype != SOCK_DGRAM)
- punixhints->ai_socktype = 0;
- else if (IS_IPX_PROTO(punixhints->ai_protocol) && punixhints->ai_socktype != SOCK_DGRAM)
- punixhints->ai_socktype = 0;
- else if (punixhints->ai_protocol == IPPROTO_IPV6)
- punixhints->ai_protocol = 0;
- }
-
- /* getaddrinfo(3) is thread safe, no need to wrap in CS */
- result = getaddrinfo( node, servname, punixhints, &unixaires );
+ ret = unix_funcs->getaddrinfo( node, service, hints, info );
- if (result && (!hints || !(hints->ai_flags & WS_AI_NUMERICHOST)) && node)
+ if (ret && (!hints || !(hints->ai_flags & WS_AI_NUMERICHOST)) && node)
{
if (!fqdn && !(fqdn = get_fqdn()))
{
@@ -356,115 +188,33 @@ int WINAPI WS_getaddrinfo( const char *nodename, const char *servname,
* 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" );
- result = getaddrinfo( NULL, servname ? servname : "0", punixhints, &unixaires );
- if (!result && punixhints && (punixhints->ai_flags & AI_CANONNAME) && unixaires && !unixaires->ai_canonname)
+ ret = unix_funcs->getaddrinfo( NULL, service, hints, info );
+ if (!ret && hints && (hints->ai_flags & WS_AI_CANONNAME) && *info && !(*info)->ai_canonname)
{
- freeaddrinfo( unixaires );
- result = EAI_NONAME;
+ WS_freeaddrinfo( *info );
+ *info = NULL;
+ return EAI_NONAME;
}
}
}
- TRACE( "%s, %s %p -> %p %d\n", debugstr_a(nodename), debugstr_a(servname), hints, res, result );
+
HeapFree( GetProcessHeap(), 0, fqdn );
HeapFree( GetProcessHeap(), 0, nodev6 );
- if (!result)
+ if (!ret && TRACE_ON(winsock))
{
- struct addrinfo *xuai = unixaires;
- struct WS_addrinfo **xai = res;
-
- *xai = NULL;
- while (xuai)
- {
- struct WS_addrinfo *ai = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct WS_addrinfo) );
- SIZE_T len;
-
- if (!ai)
- goto outofmem;
-
- ai->ai_flags = convert_aiflag_u2w( xuai->ai_flags );
- ai->ai_family = convert_af_u2w( xuai->ai_family );
- /* copy whatever was sent in the hints */
- if (hints)
- {
- ai->ai_socktype = hints->ai_socktype;
- ai->ai_protocol = hints->ai_protocol;
- }
- else
- {
- ai->ai_socktype = convert_socktype_u2w( xuai->ai_socktype );
- ai->ai_protocol = convert_proto_u2w( xuai->ai_protocol );
- }
- if (xuai->ai_canonname)
- {
- TRACE( "canon name - %s\n", debugstr_a(xuai->ai_canonname) );
- ai->ai_canonname = HeapAlloc( GetProcessHeap(), 0, strlen( xuai->ai_canonname ) + 1 );
- if (!ai->ai_canonname)
- goto outofmem;
- strcpy( ai->ai_canonname, xuai->ai_canonname );
- }
- len = xuai->ai_addrlen;
- ai->ai_addr = HeapAlloc( GetProcessHeap(), 0, len );
- if (!ai->ai_addr)
- goto outofmem;
- ai->ai_addrlen = len;
- do
- {
- int winlen = ai->ai_addrlen;
-
- if (!ws_sockaddr_u2ws( xuai->ai_addr, ai->ai_addr, &winlen ))
- {
- ai->ai_addrlen = winlen;
- break;
- }
- len *= 2;
- ai->ai_addr = HeapReAlloc( GetProcessHeap(), 0, ai->ai_addr, len );
- if (!ai->ai_addr)
- goto outofmem;
- ai->ai_addrlen = len;
- } while (1);
-
- if (addrinfo_in_list( *res, ai ))
- {
- HeapFree( GetProcessHeap(), 0, ai->ai_canonname );
- HeapFree( GetProcessHeap(), 0, ai->ai_addr );
- HeapFree( GetProcessHeap(), 0, ai );
- }
- else
- {
- *xai = ai;
- xai = &ai->ai_next;
- }
- xuai = xuai->ai_next;
- }
- freeaddrinfo( unixaires );
+ struct WS_addrinfo *ai;
- if (TRACE_ON(winsock))
+ for (ai = *info; ai != NULL; ai = ai->ai_next)
{
- struct WS_addrinfo *ai = *res;
- while (ai)
- {
- TRACE( "=> %p, flags %#x, family %d, type %d, protocol %d, len %ld, name %s, addr %s\n",
- ai, ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol, ai->ai_addrlen,
- ai->ai_canonname, debugstr_sockaddr(ai->ai_addr) );
- ai = ai->ai_next;
- }
+ TRACE( "=> %p, flags %#x, family %d, type %d, protocol %d, len %ld, name %s, addr %s\n",
+ ai, ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol, ai->ai_addrlen,
+ ai->ai_canonname, debugstr_sockaddr(ai->ai_addr) );
}
}
- else
- result = convert_eai_u2w( result );
-
- SetLastError( result );
- return result;
-outofmem:
- if (*res) WS_freeaddrinfo( *res );
- if (unixaires) freeaddrinfo( unixaires );
- return WSA_NOT_ENOUGH_MEMORY;
-#else
- FIXME( "getaddrinfo() failed, not found during build time.\n" );
- return EAI_FAIL;
-#endif
+ SetLastError( ret );
+ return ret;
}
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 2bcd15463f8..b52e0d37e90 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -41,6 +41,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
+const struct unix_funcs *unix_funcs = NULL;
+
static const WSAPROTOCOL_INFOW supported_protocols[] =
{
{
@@ -426,14 +428,6 @@ static int ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, in
#define MAP_OPTION(opt) { WS_##opt, opt }
-static const int ws_socktype_map[][2] =
-{
- MAP_OPTION( SOCK_DGRAM ),
- MAP_OPTION( SOCK_STREAM ),
- MAP_OPTION( SOCK_RAW ),
- {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
-};
-
UINT sock_get_error( int err )
{
switch(err)
@@ -626,38 +620,20 @@ static HANDLE get_sync_event(void)
return data->sync_event;
}
-/***********************************************************************
- * DllMain (WS2_32.init)
- */
+
BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
{
- if (reason == DLL_THREAD_DETACH)
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ return !__wine_init_unix_lib( instance, reason, NULL, &unix_funcs );
+
+ case DLL_THREAD_DETACH:
free_per_thread_data();
+ }
return TRUE;
}
-int
-convert_socktype_w2u(int windowssocktype) {
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(ws_socktype_map); i++)
- if (ws_socktype_map[i][0] == windowssocktype)
- return ws_socktype_map[i][1];
- FIXME("unhandled Windows socket type %d\n", windowssocktype);
- return -1;
-}
-
-int
-convert_socktype_u2w(int unixsocktype) {
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(ws_socktype_map); i++)
- if (ws_socktype_map[i][1] == unixsocktype)
- return ws_socktype_map[i][0];
- FIXME("unhandled UNIX socket type %d\n", unixsocktype);
- return -1;
-}
-
/***********************************************************************
* WSAStartup (WS2_32.115)
@@ -858,112 +834,6 @@ unsigned int ws_sockaddr_ws2u( const struct WS_sockaddr *wsaddr, int wsaddrlen,
return uaddrlen;
}
-/* Returns 0 if successful, -1 if the buffer is too small */
-int ws_sockaddr_u2ws(const struct sockaddr *uaddr, struct WS_sockaddr *wsaddr, int *wsaddrlen)
-{
- int res;
-
- switch(uaddr->sa_family)
- {
-#ifdef HAS_IPX
- case AF_IPX:
- {
- const struct sockaddr_ipx* uipx=(const struct sockaddr_ipx*)uaddr;
- struct WS_sockaddr_ipx* wsipx=(struct WS_sockaddr_ipx*)wsaddr;
-
- res=-1;
- switch (*wsaddrlen) /* how much can we copy? */
- {
- default:
- res=0; /* enough */
- *wsaddrlen = sizeof(*wsipx);
- wsipx->sa_socket=uipx->sipx_port;
- /* fall through */
- case 13:
- case 12:
- memcpy(wsipx->sa_nodenum,uipx->sipx_node,sizeof(wsipx->sa_nodenum));
- /* fall through */
- case 11:
- case 10:
- case 9:
- case 8:
- case 7:
- case 6:
- memcpy(wsipx->sa_netnum,&uipx->sipx_network,sizeof(wsipx->sa_netnum));
- /* fall through */
- case 5:
- case 4:
- case 3:
- case 2:
- wsipx->sa_family=WS_AF_IPX;
- /* fall through */
- case 1:
- case 0:
- /* way too small */
- break;
- }
- }
- break;
-#endif
-#ifdef HAS_IRDA
- case AF_IRDA: {
- const struct sockaddr_irda *uin = (const struct sockaddr_irda *)uaddr;
- SOCKADDR_IRDA *win = (SOCKADDR_IRDA *)wsaddr;
-
- if (*wsaddrlen < sizeof(SOCKADDR_IRDA))
- return -1;
- win->irdaAddressFamily = WS_AF_IRDA;
- memcpy( win->irdaDeviceID, &uin->sir_addr, sizeof(win->irdaDeviceID) );
- if (uin->sir_lsap_sel != LSAP_ANY)
- sprintf( win->irdaServiceName, "LSAP-SEL%u", uin->sir_lsap_sel );
- else
- memcpy( win->irdaServiceName, uin->sir_name,
- sizeof(win->irdaServiceName) );
- return 0;
- }
-#endif
- case AF_INET6: {
- const struct sockaddr_in6* uin6 = (const struct sockaddr_in6*)uaddr;
- struct WS_sockaddr_in6 *win6 = (struct WS_sockaddr_in6 *)wsaddr;
-
- if (*wsaddrlen < sizeof(struct WS_sockaddr_in6))
- return -1;
- win6->sin6_family = WS_AF_INET6;
- win6->sin6_port = uin6->sin6_port;
- win6->sin6_flowinfo = uin6->sin6_flowinfo;
- memcpy(&win6->sin6_addr, &uin6->sin6_addr, 16); /* 16 bytes = 128 address bits */
-#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
- win6->sin6_scope_id = uin6->sin6_scope_id;
-#else
- win6->sin6_scope_id = 0;
-#endif
- *wsaddrlen = sizeof(struct WS_sockaddr_in6);
- return 0;
- }
- case AF_INET: {
- const struct sockaddr_in* uin = (const struct sockaddr_in*)uaddr;
- struct WS_sockaddr_in* win = (struct WS_sockaddr_in*)wsaddr;
-
- if (*wsaddrlen < sizeof(struct WS_sockaddr_in))
- return -1;
- win->sin_family = WS_AF_INET;
- win->sin_port = uin->sin_port;
- memcpy(&win->sin_addr,&uin->sin_addr,4); /* 4 bytes = 32 address bits */
- memset(win->sin_zero, 0, 8); /* Make sure the null padding is null */
- *wsaddrlen = sizeof(struct WS_sockaddr_in);
- return 0;
- }
- case AF_UNSPEC: {
- memset(wsaddr,0,*wsaddrlen);
- return 0;
- }
- default:
- FIXME("Unknown address family %d\n", uaddr->sa_family);
- return -1;
- }
- return res;
-}
-
static INT WS_DuplicateSocket(BOOL unicode, SOCKET s, DWORD dwProcessId, LPWSAPROTOCOL_INFOW lpProtocolInfo)
{
HANDLE hProcess;
diff --git a/dlls/ws2_32/tests/protocol.c b/dlls/ws2_32/tests/protocol.c
index 99c78873d9a..1f039e509da 100644
--- a/dlls/ws2_32/tests/protocol.c
+++ b/dlls/ws2_32/tests/protocol.c
@@ -1740,7 +1740,7 @@ static void test_GetAddrInfoW(void)
result = NULL;
SetLastError(0xdeadbeef);
ret = GetAddrInfoW(localhost, NULL, &hint, &result);
- todo_wine_if (hinttests[i].error) ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
+ ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
if (!ret)
{
for (p = result; p; p = p->ai_next)
@@ -2293,7 +2293,7 @@ static void test_getaddrinfo(void)
result = NULL;
SetLastError(0xdeadbeef);
ret = getaddrinfo("localhost", NULL, &hint, &result);
- todo_wine_if (hinttests[i].error) ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
+ ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
if (!ret)
{
for (p = result; p; p = p->ai_next)
diff --git a/dlls/ws2_32/unixlib.c b/dlls/ws2_32/unixlib.c
new file mode 100644
index 00000000000..4b63e8e6415
--- /dev/null
+++ b/dlls/ws2_32/unixlib.c
@@ -0,0 +1,618 @@
+/*
+ * Unix library functions
+ *
+ * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
+ * Copyright (C) 2001 Stefan Leichter
+ * Copyright (C) 2004 Hans Leidekker
+ * Copyright (C) 2005 Marcus Meissner
+ * Copyright (C) 2006-2008 Kai Blin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#if 0
+#pragma makedep unix
+#endif
+
+#include "config.h"
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+
+#ifdef HAVE_NETIPX_IPX_H
+# include <netipx/ipx.h>
+#elif defined(HAVE_LINUX_IPX_H)
+# ifdef HAVE_ASM_TYPES_H
+# include <asm/types.h>
+# endif
+# ifdef HAVE_LINUX_TYPES_H
+# include <linux/types.h>
+# endif
+# include <linux/ipx.h>
+#endif
+#if defined(SOL_IPX) || defined(SO_DEFAULT_HEADERS)
+# define HAS_IPX
+#endif
+
+#ifdef HAVE_LINUX_IRDA_H
+# ifdef HAVE_LINUX_TYPES_H
+# include <linux/types.h>
+# endif
+# include <linux/irda.h>
+# define HAS_IRDA
+#endif
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winerror.h"
+#include "winternl.h"
+#include "winsock2.h"
+#include "ws2tcpip.h"
+#include "wsipx.h"
+#include "af_irda.h"
+#include "wine/debug.h"
+
+#include "ws2_32_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(winsock);
+
+#define MAP(x) {WS_ ## x, x}
+
+static const int addrinfo_flag_map[][2] =
+{
+ MAP( AI_PASSIVE ),
+ MAP( AI_CANONNAME ),
+ MAP( AI_NUMERICHOST ),
+#ifdef AI_NUMERICSERV
+ MAP( AI_NUMERICSERV ),
+#endif
+#ifdef AI_V4MAPPED
+ MAP( AI_V4MAPPED ),
+#endif
+ MAP( AI_ALL ),
+ MAP( AI_ADDRCONFIG ),
+};
+
+static const int family_map[][2] =
+{
+ MAP( AF_UNSPEC ),
+ MAP( AF_INET ),
+ MAP( AF_INET6 ),
+#ifdef AF_IPX
+ MAP( AF_IPX ),
+#endif
+#ifdef AF_IRDA
+ MAP( AF_IRDA ),
+#endif
+};
+
+static const int socktype_map[][2] =
+{
+ MAP( SOCK_STREAM ),
+ MAP( SOCK_DGRAM ),
+ MAP( SOCK_RAW ),
+};
+
+static const int ip_protocol_map[][2] =
+{
+ MAP( IPPROTO_IP ),
+ MAP( IPPROTO_TCP ),
+ MAP( IPPROTO_UDP ),
+ MAP( IPPROTO_IPV6 ),
+ MAP( IPPROTO_ICMP ),
+ MAP( IPPROTO_IGMP ),
+ MAP( IPPROTO_RAW ),
+ {WS_IPPROTO_IPV4, IPPROTO_IPIP},
+};
+
+#undef MAP
+
+static int addrinfo_flags_from_unix( int flags )
+{
+ int ws_flags = 0;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(addrinfo_flag_map); ++i)
+ {
+ if (flags & addrinfo_flag_map[i][1])
+ {
+ ws_flags |= addrinfo_flag_map[i][0];
+ flags &= ~addrinfo_flag_map[i][1];
+ }
+ }
+
+ if (flags)
+ FIXME( "unhandled flags %#x\n", flags );
+ return ws_flags;
+}
+
+static int addrinfo_flags_to_unix( int flags )
+{
+ int unix_flags = 0;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(addrinfo_flag_map); ++i)
+ {
+ if (flags & addrinfo_flag_map[i][0])
+ {
+ unix_flags |= addrinfo_flag_map[i][1];
+ flags &= ~addrinfo_flag_map[i][0];
+ }
+ }
+
+ if (flags)
+ FIXME( "unhandled flags %#x\n", flags );
+ return unix_flags;
+}
+
+static int family_from_unix( int family )
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(family_map); ++i)
+ {
+ if (family == family_map[i][1])
+ return family_map[i][0];
+ }
+
+ FIXME( "unhandled family %u\n", family );
+ return -1;
+}
+
+static int family_to_unix( int family )
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(family_map); ++i)
+ {
+ if (family == family_map[i][0])
+ return family_map[i][1];
+ }
+
+ FIXME( "unhandled family %u\n", family );
+ return -1;
+}
+
+static int socktype_from_unix( int type )
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(socktype_map); ++i)
+ {
+ if (type == socktype_map[i][1])
+ return socktype_map[i][0];
+ }
+
+ FIXME( "unhandled type %u\n", type );
+ return -1;
+}
+
+static int socktype_to_unix( int type )
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(socktype_map); ++i)
+ {
+ if (type == socktype_map[i][0])
+ return socktype_map[i][1];
+ }
+
+ FIXME( "unhandled type %u\n", type );
+ return -1;
+}
+
+static int protocol_from_unix( int protocol )
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ip_protocol_map); ++i)
+ {
+ if (protocol == ip_protocol_map[i][1])
+ return ip_protocol_map[i][0];
+ }
+
+ if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255)
+ return protocol;
+
+ FIXME( "unhandled protocol %u\n", protocol );
+ return -1;
+}
+
+static int protocol_to_unix( int protocol )
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ip_protocol_map); ++i)
+ {
+ if (protocol == ip_protocol_map[i][0])
+ return ip_protocol_map[i][1];
+ }
+
+ if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255)
+ return protocol;
+
+ FIXME( "unhandled protocol %u\n", protocol );
+ return -1;
+}
+
+static unsigned int errno_from_unix( int err )
+{
+ switch (err)
+ {
+ case EINTR: return WSAEINTR;
+ case EBADF: return WSAEBADF;
+ case EPERM:
+ case EACCES: return WSAEACCES;
+ case EFAULT: return WSAEFAULT;
+ case EINVAL: return WSAEINVAL;
+ case EMFILE: return WSAEMFILE;
+ case EINPROGRESS:
+ case EWOULDBLOCK: return WSAEWOULDBLOCK;
+ case EALREADY: return WSAEALREADY;
+ case ENOTSOCK: return WSAENOTSOCK;
+ case EDESTADDRREQ: return WSAEDESTADDRREQ;
+ case EMSGSIZE: return WSAEMSGSIZE;
+ case EPROTOTYPE: return WSAEPROTOTYPE;
+ case ENOPROTOOPT: return WSAENOPROTOOPT;
+ case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
+ case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
+ case EOPNOTSUPP: return WSAEOPNOTSUPP;
+ case EPFNOSUPPORT: return WSAEPFNOSUPPORT;
+ case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
+ case EADDRINUSE: return WSAEADDRINUSE;
+ case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
+ case ENETDOWN: return WSAENETDOWN;
+ case ENETUNREACH: return WSAENETUNREACH;
+ case ENETRESET: return WSAENETRESET;
+ case ECONNABORTED: return WSAECONNABORTED;
+ case EPIPE:
+ case ECONNRESET: return WSAECONNRESET;
+ case ENOBUFS: return WSAENOBUFS;
+ case EISCONN: return WSAEISCONN;
+ case ENOTCONN: return WSAENOTCONN;
+ case ESHUTDOWN: return WSAESHUTDOWN;
+ case ETOOMANYREFS: return WSAETOOMANYREFS;
+ case ETIMEDOUT: return WSAETIMEDOUT;
+ case ECONNREFUSED: return WSAECONNREFUSED;
+ case ELOOP: return WSAELOOP;
+ case ENAMETOOLONG: return WSAENAMETOOLONG;
+ case EHOSTDOWN: return WSAEHOSTDOWN;
+ case EHOSTUNREACH: return WSAEHOSTUNREACH;
+ case ENOTEMPTY: return WSAENOTEMPTY;
+#ifdef EPROCLIM
+ case EPROCLIM: return WSAEPROCLIM;
+#endif
+#ifdef EUSERS
+ case EUSERS: return WSAEUSERS;
+#endif
+#ifdef EDQUOT
+ case EDQUOT: return WSAEDQUOT;
+#endif
+#ifdef ESTALE
+ case ESTALE: return WSAESTALE;
+#endif
+#ifdef EREMOTE
+ case EREMOTE: return WSAEREMOTE;
+#endif
+ default:
+ FIXME( "unknown error: %s", strerror( err ) );
+ return WSAEFAULT;
+ }
+}
+
+static int addrinfo_err_from_unix( int err )
+{
+ switch (err)
+ {
+ case EAI_AGAIN: return WS_EAI_AGAIN;
+ case EAI_BADFLAGS: return WS_EAI_BADFLAGS;
+ case EAI_FAIL: return WS_EAI_FAIL;
+ case EAI_FAMILY: return WS_EAI_FAMILY;
+ case EAI_MEMORY: return WS_EAI_MEMORY;
+ /* EAI_NODATA is deprecated, but still used by Windows and Linux. We map
+ * the newer EAI_NONAME to EAI_NODATA for now until Windows changes too. */
+#ifdef EAI_NODATA
+ case EAI_NODATA: return WS_EAI_NODATA;
+#endif
+#ifdef EAI_NONAME
+ case EAI_NONAME: return WS_EAI_NODATA;
+#endif
+ case EAI_SERVICE: return WS_EAI_SERVICE;
+ case EAI_SOCKTYPE: return WS_EAI_SOCKTYPE;
+ case EAI_SYSTEM:
+ /* some broken versions of glibc return EAI_SYSTEM and set errno to
+ * 0 instead of returning EAI_NONAME */
+ return errno ? errno_from_unix( errno ) : WS_EAI_NONAME;
+
+ default:
+ FIXME( "unhandled error %d\n", err );
+ return err;
+ }
+}
+
+union unix_sockaddr
+{
+ struct sockaddr addr;
+ struct sockaddr_in in;
+ struct sockaddr_in6 in6;
+#ifdef HAS_IPX
+ struct sockaddr_ipx ipx;
+#endif
+#ifdef HAS_IRDA
+ struct sockaddr_irda irda;
+#endif
+};
+
+/* different from the version in ntdll and server; it does not return failure if
+ * given a short buffer */
+static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_sockaddr *wsaddr, socklen_t wsaddrlen )
+{
+ memset( wsaddr, 0, wsaddrlen );
+
+ switch (uaddr->addr.sa_family)
+ {
+ case AF_INET:
+ {
+ struct WS_sockaddr_in win = {0};
+
+ if (wsaddrlen >= sizeof(win))
+ {
+ win.sin_family = WS_AF_INET;
+ win.sin_port = uaddr->in.sin_port;
+ memcpy( &win.sin_addr, &uaddr->in.sin_addr, sizeof(win.sin_addr) );
+ memcpy( wsaddr, &win, sizeof(win) );
+ }
+ return sizeof(win);
+ }
+
+ case AF_INET6:
+ {
+ struct WS_sockaddr_in6 win = {0};
+
+ if (wsaddrlen >= sizeof(win))
+ {
+ win.sin6_family = WS_AF_INET6;
+ win.sin6_port = uaddr->in6.sin6_port;
+ win.sin6_flowinfo = uaddr->in6.sin6_flowinfo;
+ memcpy( &win.sin6_addr, &uaddr->in6.sin6_addr, sizeof(win.sin6_addr) );
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+ win.sin6_scope_id = uaddr->in6.sin6_scope_id;
+#endif
+ memcpy( wsaddr, &win, sizeof(win) );
+ }
+ return sizeof(win);
+ }
+
+#ifdef HAS_IPX
+ case AF_IPX:
+ {
+ struct WS_sockaddr_ipx win = {0};
+
+ if (wsaddrlen >= sizeof(win))
+ {
+ win.sa_family = WS_AF_IPX;
+ memcpy( win.sa_netnum, &uaddr->ipx.sipx_network, sizeof(win.sa_netnum) );
+ memcpy( win.sa_nodenum, &uaddr->ipx.sipx_node, sizeof(win.sa_nodenum) );
+ win.sa_socket = uaddr->ipx.sipx_port;
+ memcpy( wsaddr, &win, sizeof(win) );
+ }
+ return sizeof(win);
+ }
+#endif
+
+#ifdef HAS_IRDA
+ case AF_IRDA:
+ {
+ SOCKADDR_IRDA win;
+
+ if (wsaddrlen >= sizeof(win))
+ {
+ win.irdaAddressFamily = WS_AF_IRDA;
+ memcpy( win.irdaDeviceID, &uaddr->irda.sir_addr, sizeof(win.irdaDeviceID) );
+ if (uaddr->irda.sir_lsap_sel != LSAP_ANY)
+ snprintf( win.irdaServiceName, sizeof(win.irdaServiceName), "LSAP-SEL%u", uaddr->irda.sir_lsap_sel );
+ else
+ memcpy( win.irdaServiceName, uaddr->irda.sir_name, sizeof(win.irdaServiceName) );
+ memcpy( wsaddr, &win, sizeof(win) );
+ }
+ return sizeof(win);
+ }
+#endif
+
+ case AF_UNSPEC:
+ return 0;
+
+ default:
+ FIXME( "unknown address family %d\n", uaddr->addr.sa_family );
+ return 0;
+ }
+}
+
+static BOOL addrinfo_in_list( const struct WS_addrinfo *list, const struct WS_addrinfo *ai )
+{
+ const struct WS_addrinfo *cursor = list;
+ while (cursor)
+ {
+ if (ai->ai_flags == cursor->ai_flags &&
+ ai->ai_family == cursor->ai_family &&
+ ai->ai_socktype == cursor->ai_socktype &&
+ ai->ai_protocol == cursor->ai_protocol &&
+ ai->ai_addrlen == cursor->ai_addrlen &&
+ !memcmp( ai->ai_addr, cursor->ai_addr, ai->ai_addrlen ) &&
+ ((ai->ai_canonname && cursor->ai_canonname && !strcmp( ai->ai_canonname, cursor->ai_canonname ))
+ || (!ai->ai_canonname && !cursor->ai_canonname)))
+ {
+ return TRUE;
+ }
+ cursor = cursor->ai_next;
+ }
+ return FALSE;
+}
+
+static int CDECL unix_getaddrinfo( const char *node, const char *service,
+ const struct WS_addrinfo *hints, struct WS_addrinfo **info )
+{
+#ifdef HAVE_GETADDRINFO
+ struct addrinfo unix_hints = {0};
+ struct addrinfo *unix_info, *src;
+ struct WS_addrinfo *dst, *prev = NULL;
+ int ret;
+
+ *info = NULL;
+
+ /* servname tweak required by OSX and BSD kernels */
+ if (service && !service[0]) service = "0";
+
+ if (hints)
+ {
+ unix_hints.ai_flags = addrinfo_flags_to_unix( hints->ai_flags );
+
+ if (hints->ai_family)
+ unix_hints.ai_family = family_to_unix( hints->ai_family );
+
+ if (hints->ai_socktype)
+ {
+ if ((unix_hints.ai_socktype = socktype_to_unix( hints->ai_socktype )) < 0)
+ return WSAESOCKTNOSUPPORT;
+ }
+
+ if (hints->ai_protocol)
+ unix_hints.ai_protocol = max( protocol_to_unix( hints->ai_protocol ), 0 );
+
+ /* Windows allows some invalid combinations */
+ if (unix_hints.ai_protocol == IPPROTO_TCP
+ && unix_hints.ai_socktype != SOCK_STREAM
+ && unix_hints.ai_socktype != SOCK_SEQPACKET)
+ {
+ WARN( "ignoring invalid type %u for TCP\n", unix_hints.ai_socktype );
+ unix_hints.ai_socktype = 0;
+ }
+ else if (unix_hints.ai_protocol == IPPROTO_UDP && unix_hints.ai_socktype != SOCK_DGRAM)
+ {
+ WARN( "ignoring invalid type %u for UDP\n", unix_hints.ai_socktype );
+ unix_hints.ai_socktype = 0;
+ }
+ else if (unix_hints.ai_protocol >= WS_NSPROTO_IPX && unix_hints.ai_protocol <= WS_NSPROTO_IPX + 255
+ && unix_hints.ai_socktype != SOCK_DGRAM)
+ {
+ WARN( "ignoring invalid type %u for IPX\n", unix_hints.ai_socktype );
+ unix_hints.ai_socktype = 0;
+ }
+ else if (unix_hints.ai_protocol == IPPROTO_IPV6)
+ {
+ WARN( "ignoring protocol IPv6\n" );
+ unix_hints.ai_protocol = 0;
+ }
+ }
+
+ ret = getaddrinfo( node, service, hints ? &unix_hints : NULL, &unix_info );
+ if (ret)
+ return addrinfo_err_from_unix( ret );
+
+ *info = NULL;
+
+ for (src = unix_info; src != NULL; src = src->ai_next)
+ {
+ if (!(dst = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dst) )))
+ goto fail;
+
+ dst->ai_flags = addrinfo_flags_from_unix( src->ai_flags );
+ dst->ai_family = family_from_unix( src->ai_family );
+ if (hints)
+ {
+ dst->ai_socktype = hints->ai_socktype;
+ dst->ai_protocol = hints->ai_protocol;
+ }
+ else
+ {
+ dst->ai_socktype = socktype_from_unix( src->ai_socktype );
+ dst->ai_protocol = protocol_from_unix( src->ai_protocol );
+ }
+ 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 );
+ }
+
+ 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;
+ }
+ sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, 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 (prev)
+ prev->ai_next = dst;
+ else
+ *info = dst;
+ prev = dst;
+ }
+ }
+
+ 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;
+#endif
+}
+
+static const struct unix_funcs funcs =
+{
+ unix_getaddrinfo,
+};
+
+NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
+{
+ if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
+
+ *(const struct unix_funcs **)ptr_out = &funcs;
+ return STATUS_SUCCESS;
+}
diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h
index b70f4a1595d..5fd083eac31 100644
--- a/dlls/ws2_32/ws2_32_private.h
+++ b/dlls/ws2_32/ws2_32_private.h
@@ -172,10 +172,6 @@ union generic_unix_sockaddr
};
int convert_eai_u2w( int ret ) DECLSPEC_HIDDEN;
-int convert_socktype_u2w( int type ) DECLSPEC_HIDDEN;
-int convert_socktype_w2u( int type ) DECLSPEC_HIDDEN;
-int ws_sockaddr_u2ws( const struct sockaddr *unix_addr, struct WS_sockaddr *win_addr,
- int *win_addr_len ) DECLSPEC_HIDDEN;
unsigned int ws_sockaddr_ws2u( const struct WS_sockaddr *win_addr, int win_addr_len,
union generic_unix_sockaddr *unix_addr ) DECLSPEC_HIDDEN;
@@ -200,4 +196,12 @@ extern int num_startup;
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 );
+};
+
+extern const struct unix_funcs *unix_funcs;
+
#endif
--
2.32.0
More information about the wine-devel
mailing list