Signed-off-by: Zebediah Figura zfigura@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