Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ws2_32/socket.c | 20 -------------------- 1 file changed, 20 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 40e4ecb9325..2bcd15463f8 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -727,26 +727,6 @@ void WINAPI WSASetLastError(INT iError) { SetLastError(iError); }
-static inline BOOL supported_pf(int pf) -{ - switch (pf) - { - case WS_AF_INET: - case WS_AF_INET6: - return TRUE; -#ifdef HAS_IPX - case WS_AF_IPX: - return TRUE; -#endif -#ifdef HAS_IRDA - case WS_AF_IRDA: - return TRUE; -#endif - default: - return FALSE; - } -} - /**********************************************************************/
/* Returns the length of the converted address if successful, 0 if it was too
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
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;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- 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;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ws2_32/protocol.c | 132 ++++++----------------------------- dlls/ws2_32/unixlib.c | 55 +++++++++++++++ dlls/ws2_32/ws2_32_private.h | 1 + 3 files changed, 77 insertions(+), 111 deletions(-)
diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c index 2a7200ee137..c65e6b9674e 100644 --- a/dlls/ws2_32/protocol.c +++ b/dlls/ws2_32/protocol.c @@ -53,33 +53,6 @@ static const int ws_eai_map[][2] = { 0, 0 } };
-static const int ws_af_map[][2] = -{ - MAP_OPTION( AF_UNSPEC ), - MAP_OPTION( AF_INET ), - MAP_OPTION( AF_INET6 ), -#ifdef HAS_IPX - MAP_OPTION( AF_IPX ), -#endif -#ifdef AF_IRDA - MAP_OPTION( AF_IRDA ), -#endif - {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO}, -}; - -static int convert_af_u2w( int family ) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(ws_af_map); i++) - { - if (ws_af_map[i][1] == family) - return ws_af_map[i][0]; - } - FIXME( "unhandled UNIX address family %d\n", family ); - return -1; -} - int convert_eai_u2w( int unixret ) { int i; @@ -706,24 +679,6 @@ int WINAPI GetNameInfoW( const SOCKADDR *addr, WS_socklen_t addr_len, WCHAR *hos }
-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 struct WS_hostent *get_hostent_buffer( unsigned int size ) { struct per_thread_data *data = get_per_thread_data(); @@ -791,37 +746,6 @@ static struct WS_hostent *create_hostent( char *name, int alias_count, int alias return p_to; }
-static struct WS_hostent *hostent_from_unix( const struct hostent *p_he ) -{ - int i, addresses = 0, alias_size = 0; - struct WS_hostent *p_to; - char *p; - - for (i = 0; p_he->h_aliases[i]; i++) - alias_size += strlen( p_he->h_aliases[i] ) + 1; - while (p_he->h_addr_list[addresses]) - addresses++; - - p_to = create_hostent( p_he->h_name, i + 1, alias_size, addresses + 1, p_he->h_length ); - - if (!p_to) return NULL; - p_to->h_addrtype = convert_af_u2w( p_he->h_addrtype ); - p_to->h_length = p_he->h_length; - - for (i = 0, p = p_to->h_addr_list[0]; p_he->h_addr_list[i]; i++, p += p_to->h_length) - memcpy( p, p_he->h_addr_list[i], p_to->h_length ); - - /* Fill the aliases after the IP data */ - for (i = 0; p_he->h_aliases[i]; i++) - { - p_to->h_aliases[i] = p; - strcpy( p, p_he->h_aliases[i] ); - p += strlen(p) + 1; - } - - return p_to; -} -
/*********************************************************************** * gethostbyaddr (ws2_32.51) @@ -987,16 +911,11 @@ cleanup: */ struct WS_hostent * WINAPI WS_gethostbyname( const char *name ) { - struct WS_hostent *retval = NULL; - struct hostent *host; -#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6 - char *extrabuf; - int ebufsize = 1024; - struct hostent hostentry; - int locerr = ENOBUFS; -#endif + struct WS_hostent *host = NULL; char hostname[100];
+ TRACE( "%s\n", debugstr_a(name) ); + if (!num_startup) { SetLastError( WSANOTINITIALISED ); @@ -1006,7 +925,7 @@ struct WS_hostent * WINAPI WS_gethostbyname( const char *name ) if (gethostname( hostname, 100 ) == -1) { SetLastError( WSAENOBUFS ); - return retval; + return NULL; }
if (!name || !name[0]) @@ -1015,45 +934,36 @@ struct WS_hostent * WINAPI WS_gethostbyname( const char *name ) /* If the hostname of the local machine is requested then return the * complete list of local IP addresses */ if (!strcmp( name, hostname )) - retval = get_local_ips( hostname ); + host = get_local_ips( hostname );
/* If any other hostname was requested (or the routing table lookup failed) * then return the IP found by the host OS */ - if (!retval) + if (!host) { -#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6 - host = NULL; - extrabuf = HeapAlloc( GetProcessHeap(), 0, ebufsize ); - while (extrabuf) + unsigned int size = 1024; + int ret; + + if (!(host = get_hostent_buffer( size ))) + return NULL; + + while ((ret = unix_funcs->gethostbyname( name, host, &size )) == ERROR_INSUFFICIENT_BUFFER) { - int res = gethostbyname_r( name, &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) SetLastError( (locerr < 0) ? sock_get_error( errno ) : host_errno_from_unix( locerr ) ); -#else - EnterCriticalSection( &csWSgetXXXbyYYY ); - host = gethostbyname( name ); - if (!host) SetLastError( (h_errno < 0) ? sock_get_error( errno ) : host_errno_from_unix( h_errno ) ); -#endif - if (host) retval = hostent_from_unix( host ); -#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6 - HeapFree( GetProcessHeap(), 0, extrabuf ); -#else - LeaveCriticalSection( &csWSgetXXXbyYYY ); -#endif + + SetLastError( ret ); + return ret ? NULL : host; }
- if (retval && retval->h_addr_list[0][0] == 127 && strcmp( name, "localhost" )) + if (host && host->h_addr_list[0][0] == 127 && strcmp( name, "localhost" )) { /* hostname != "localhost" but has loopback address. replace by our * special address.*/ - memcpy( retval->h_addr_list[0], magic_loopback_addr, 4 ); + memcpy( host->h_addr_list[0], magic_loopback_addr, 4 ); }
- TRACE( "%s ret %p\n", debugstr_a(name), retval ); - return retval; + return host; }
diff --git a/dlls/ws2_32/unixlib.c b/dlls/ws2_32/unixlib.c index 2423ef5aa2e..2a5fcd1b60d 100644 --- a/dlls/ws2_32/unixlib.c +++ b/dlls/ws2_32/unixlib.c @@ -735,10 +735,65 @@ static int CDECL unix_gethostbyaddr( const void *addr, int len, int family, }
+#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6 +static int CDECL unix_gethostbyname( const char *name, struct WS_hostent *const host, unsigned int *size ) +{ + struct hostent stack_host, *unix_host; + char *unix_buffer, *new_buffer; + int unix_size = 1024; + int locerr; + int ret; + + if (!(unix_buffer = malloc( unix_size ))) + return WSAENOBUFS; + + while (gethostbyname_r( name, &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 +static int CDECL unix_gethostbyname( const char *name, struct WS_hostent *const host, unsigned int *size ) +{ + struct hostent *unix_host; + int ret; + + pthread_mutex_lock( &host_mutex ); + + if (!(unix_host = gethostbyname( name ))) + { + 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, + unix_gethostbyname, };
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 f9224306a7c..38454e1a9ba 100644 --- a/dlls/ws2_32/ws2_32_private.h +++ b/dlls/ws2_32/ws2_32_private.h @@ -202,6 +202,7 @@ struct unix_funcs struct WS(addrinfo) *info, unsigned int *size ); int (CDECL *gethostbyaddr)( const void *addr, int len, int family, struct WS(hostent) *host, unsigned int *size ); + int (CDECL *gethostbyname)( const char *name, struct WS(hostent) *host, unsigned int *size ); };
extern const struct unix_funcs *unix_funcs;