Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/Makefile.in | 1 + dlls/ws2_32/protocol.c | 812 ++++++++++++++++++++++++++++++++ dlls/ws2_32/socket.c | 890 +---------------------------------- dlls/ws2_32/ws2_32_private.h | 167 +++++++ 4 files changed, 988 insertions(+), 882 deletions(-) create mode 100644 dlls/ws2_32/protocol.c create mode 100644 dlls/ws2_32/ws2_32_private.h
diff --git a/dlls/ws2_32/Makefile.in b/dlls/ws2_32/Makefile.in index 9d7dfafeb3c..6312b20739d 100644 --- a/dlls/ws2_32/Makefile.in +++ b/dlls/ws2_32/Makefile.in @@ -6,6 +6,7 @@ EXTRALIBS = $(POLL_LIBS)
C_SRCS = \ async.c \ + protocol.c \ socket.c
RC_SRCS = version.rc diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c new file mode 100644 index 00000000000..7bf994b501f --- /dev/null +++ b/dlls/ws2_32/protocol.c @@ -0,0 +1,812 @@ +/* + * Protocol-level socket 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 + */ + +#include "config.h" + +#include "ws2_32_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winsock); +WINE_DECLARE_DEBUG_CHANNEL(winediag); + +#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 ), + MAP_OPTION( EAI_BADFLAGS ), + MAP_OPTION( EAI_FAIL ), + MAP_OPTION( EAI_FAMILY ), + MAP_OPTION( EAI_MEMORY ), +/* Note: 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 + MAP_OPTION( EAI_NODATA ), +#endif +#ifdef EAI_NONAME + { WS_EAI_NODATA, EAI_NONAME }, +#endif + MAP_OPTION( EAI_SERVICE ), + MAP_OPTION( EAI_SOCKTYPE ), + { 0, 0 } +}; + +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_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; + + if (!unixret) return 0; + + for (i = 0; ws_eai_map[i][0]; i++) + { + if (ws_eai_map[i][1] == unixret) + return ws_eai_map[i][0]; + } + + if (unixret == EAI_SYSTEM) + /* There are broken versions of glibc which return EAI_SYSTEM + * and set errno to 0 instead of returning EAI_NONAME. */ + return errno ? sock_get_error( errno ) : WS_EAI_NONAME; + + FIXME("Unhandled unix EAI_xxx ret %d\n", unixret); + return unixret; +} + +static char *get_fqdn(void) +{ + char *ret; + DWORD size = 0; + + GetComputerNameExA( ComputerNamePhysicalDnsFullyQualified, NULL, &size ); + if (GetLastError() != ERROR_MORE_DATA) return NULL; + if (!(ret = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL; + if (!GetComputerNameExA( ComputerNamePhysicalDnsFullyQualified, ret, &size )) + { + HeapFree( GetProcessHeap(), 0, ret ); + return NULL; + } + 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 ) +{ +#ifdef HAVE_GETADDRINFO + struct addrinfo *unixaires = NULL; + int result; + struct addrinfo unixhints, *punixhints = NULL; + char *nodev6 = NULL, *fqdn = NULL; + const char *node; + + *res = NULL; + if (!nodename && !servname) + { + 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 + { + 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) + { + char *close_bracket; + + if (node[0] == '[' && (close_bracket = strchr(node + 1, ']'))) + { + nodev6 = HeapAlloc( GetProcessHeap(), 0, close_bracket - node ); + if (!nodev6) return WSA_NOT_ENOUGH_MEMORY; + lstrcpynA( nodev6, node + 1, close_bracket - node ); + node = nodev6; + } + } + } + + /* 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 ); + + if (result && (!hints || !(hints->ai_flags & WS_AI_NUMERICHOST)) && node) + { + if (!fqdn && !(fqdn = get_fqdn())) + { + HeapFree( GetProcessHeap(), 0, nodev6 ); + return WSA_NOT_ENOUGH_MEMORY; + } + if (!strcmp( fqdn, node ) || (!strncmp( fqdn, node, strlen( node ) ) && fqdn[strlen( node )] == '.')) + { + /* If it didn't work it means the host name IP is not in /etc/hosts, try again + * 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) + { + freeaddrinfo( unixaires ); + result = 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) + { + 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 ); + + if (TRACE_ON(winsock)) + { + 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; + } + } + } + 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 +} + + +static ADDRINFOEXW *addrinfo_AtoW( const struct WS_addrinfo *ai ) +{ + ADDRINFOEXW *ret; + + if (!(ret = HeapAlloc( GetProcessHeap(), 0, sizeof(ADDRINFOEXW) ))) return NULL; + ret->ai_flags = ai->ai_flags; + ret->ai_family = ai->ai_family; + ret->ai_socktype = ai->ai_socktype; + ret->ai_protocol = ai->ai_protocol; + ret->ai_addrlen = ai->ai_addrlen; + ret->ai_canonname = NULL; + ret->ai_addr = NULL; + ret->ai_blob = NULL; + ret->ai_bloblen = 0; + ret->ai_provider = NULL; + ret->ai_next = NULL; + if (ai->ai_canonname) + { + int len = MultiByteToWideChar( CP_ACP, 0, ai->ai_canonname, -1, NULL, 0 ); + if (!(ret->ai_canonname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) + { + HeapFree( GetProcessHeap(), 0, ret ); + return NULL; + } + MultiByteToWideChar( CP_ACP, 0, ai->ai_canonname, -1, ret->ai_canonname, len ); + } + if (ai->ai_addr) + { + if (!(ret->ai_addr = HeapAlloc( GetProcessHeap(), 0, ai->ai_addrlen ))) + { + HeapFree( GetProcessHeap(), 0, ret->ai_canonname ); + HeapFree( GetProcessHeap(), 0, ret ); + return NULL; + } + memcpy( ret->ai_addr, ai->ai_addr, ai->ai_addrlen ); + } + return ret; +} + +static ADDRINFOEXW *addrinfo_list_AtoW( const struct WS_addrinfo *info ) +{ + ADDRINFOEXW *ret, *infoW; + + if (!(ret = infoW = addrinfo_AtoW( info ))) return NULL; + while (info->ai_next) + { + if (!(infoW->ai_next = addrinfo_AtoW( info->ai_next ))) + { + FreeAddrInfoExW( ret ); + return NULL; + } + infoW = infoW->ai_next; + info = info->ai_next; + } + return ret; +} + +static struct WS_addrinfo *addrinfo_WtoA( const struct WS_addrinfoW *ai ) +{ + struct WS_addrinfo *ret; + + if (!(ret = HeapAlloc( GetProcessHeap(), 0, sizeof(struct WS_addrinfo) ))) return NULL; + ret->ai_flags = ai->ai_flags; + ret->ai_family = ai->ai_family; + ret->ai_socktype = ai->ai_socktype; + ret->ai_protocol = ai->ai_protocol; + ret->ai_addrlen = ai->ai_addrlen; + ret->ai_canonname = NULL; + ret->ai_addr = NULL; + ret->ai_next = NULL; + if (ai->ai_canonname) + { + int len = WideCharToMultiByte( CP_ACP, 0, ai->ai_canonname, -1, NULL, 0, NULL, NULL ); + if (!(ret->ai_canonname = HeapAlloc( GetProcessHeap(), 0, len ))) + { + HeapFree( GetProcessHeap(), 0, ret ); + return NULL; + } + WideCharToMultiByte( CP_ACP, 0, ai->ai_canonname, -1, ret->ai_canonname, len, NULL, NULL ); + } + if (ai->ai_addr) + { + if (!(ret->ai_addr = HeapAlloc( GetProcessHeap(), 0, sizeof(struct WS_sockaddr) ))) + { + HeapFree( GetProcessHeap(), 0, ret->ai_canonname ); + HeapFree( GetProcessHeap(), 0, ret ); + return NULL; + } + memcpy( ret->ai_addr, ai->ai_addr, sizeof(struct WS_sockaddr) ); + } + return ret; +} + +struct getaddrinfo_args +{ + OVERLAPPED *overlapped; + LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine; + ADDRINFOEXW **result; + char *nodename; + char *servname; +}; + +static void WINAPI getaddrinfo_callback(TP_CALLBACK_INSTANCE *instance, void *context) +{ + struct getaddrinfo_args *args = context; + OVERLAPPED *overlapped = args->overlapped; + HANDLE event = overlapped->hEvent; + LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine = args->completion_routine; + struct WS_addrinfo *res; + int ret; + + ret = WS_getaddrinfo( args->nodename, args->servname, NULL, &res ); + if (res) + { + *args->result = addrinfo_list_AtoW(res); + overlapped->u.Pointer = args->result; + WS_freeaddrinfo(res); + } + + HeapFree( GetProcessHeap(), 0, args->nodename ); + HeapFree( GetProcessHeap(), 0, args->servname ); + HeapFree( GetProcessHeap(), 0, args ); + + overlapped->Internal = ret; + if (completion_routine) completion_routine( ret, 0, overlapped ); + if (event) SetEvent( event ); +} + +static int WS_getaddrinfoW( const WCHAR *nodename, const WCHAR *servname, + const struct WS_addrinfo *hints, ADDRINFOEXW **res, OVERLAPPED *overlapped, + LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine ) +{ + int ret = EAI_MEMORY, len, i; + char *nodenameA = NULL, *servnameA = NULL; + struct WS_addrinfo *resA; + WCHAR *local_nodenameW = (WCHAR *)nodename; + + *res = NULL; + if (nodename) + { + /* Is this an IDN? Most likely if any char is above the Ascii table, this + * is the simplest validation possible, further validation will be done by + * the native getaddrinfo() */ + for (i = 0; nodename[i]; i++) + { + if (nodename[i] > 'z') + break; + } + if (nodename[i]) + { + if (hints && (hints->ai_flags & WS_AI_DISABLE_IDN_ENCODING)) + { + /* Name requires conversion but it was disabled */ + ret = WSAHOST_NOT_FOUND; + SetLastError( ret ); + goto end; + } + + len = IdnToAscii( 0, nodename, -1, NULL, 0 ); + if (!len) + { + ERR("Failed to convert %s to punycode\n", debugstr_w(nodename)); + ret = EAI_FAIL; + goto end; + } + if (!(local_nodenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) goto end; + IdnToAscii( 0, nodename, -1, local_nodenameW, len ); + } + } + if (local_nodenameW) + { + len = WideCharToMultiByte( CP_ACP, 0, local_nodenameW, -1, NULL, 0, NULL, NULL ); + if (!(nodenameA = HeapAlloc( GetProcessHeap(), 0, len ))) goto end; + WideCharToMultiByte( CP_ACP, 0, local_nodenameW, -1, nodenameA, len, NULL, NULL ); + } + if (servname) + { + len = WideCharToMultiByte( CP_ACP, 0, servname, -1, NULL, 0, NULL, NULL ); + if (!(servnameA = HeapAlloc( GetProcessHeap(), 0, len ))) goto end; + WideCharToMultiByte( CP_ACP, 0, servname, -1, servnameA, len, NULL, NULL ); + } + + if (overlapped) + { + struct getaddrinfo_args *args; + + if (overlapped->hEvent && completion_routine) + { + ret = WSAEINVAL; + goto end; + } + + if (!(args = HeapAlloc( GetProcessHeap(), 0, sizeof(*args) ))) goto end; + args->overlapped = overlapped; + args->completion_routine = completion_routine; + args->result = res; + args->nodename = nodenameA; + args->servname = servnameA; + + overlapped->Internal = WSAEINPROGRESS; + if (!TrySubmitThreadpoolCallback( getaddrinfo_callback, args, NULL )) + { + HeapFree( GetProcessHeap(), 0, args ); + ret = GetLastError(); + goto end; + } + + if (local_nodenameW != nodename) + HeapFree( GetProcessHeap(), 0, local_nodenameW ); + SetLastError( ERROR_IO_PENDING ); + return ERROR_IO_PENDING; + } + + ret = WS_getaddrinfo( nodenameA, servnameA, hints, &resA ); + if (!ret) + { + *res = addrinfo_list_AtoW( resA ); + WS_freeaddrinfo( resA ); + } + +end: + if (local_nodenameW != nodename) + HeapFree( GetProcessHeap(), 0, local_nodenameW ); + HeapFree( GetProcessHeap(), 0, nodenameA ); + HeapFree( GetProcessHeap(), 0, servnameA ); + return ret; +} + + +/*********************************************************************** + * GetAddrInfoExW (ws2_32.@) + */ +int WINAPI GetAddrInfoExW( const WCHAR *name, const WCHAR *servname, DWORD namespace, + GUID *namespace_id, const ADDRINFOEXW *hints, ADDRINFOEXW **result, + struct WS_timeval *timeout, OVERLAPPED *overlapped, + LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine, HANDLE *handle ) +{ + int ret; + + TRACE( "name %s, servname %s, namespace %u, namespace_id %s)\n", + debugstr_w(name), debugstr_w(servname), namespace, debugstr_guid(namespace_id) ); + + if (namespace != NS_DNS) + FIXME( "Unsupported namespace %u\n", namespace ); + if (namespace_id) + FIXME( "Unsupported namespace_id %s\n", debugstr_guid(namespace_id) ); + if (hints) + FIXME( "Unsupported hints\n" ); + if (timeout) + FIXME( "Unsupported timeout\n" ); + if (handle) + FIXME( "Unsupported cancel handle\n" ); + + ret = WS_getaddrinfoW( name, servname, NULL, result, overlapped, completion_routine ); + if (ret) return ret; + if (handle) *handle = (HANDLE)0xdeadbeef; + return 0; +} + + +/*********************************************************************** + * GetAddrInfoExOverlappedResult (ws2_32.@) + */ +int WINAPI GetAddrInfoExOverlappedResult( OVERLAPPED *overlapped ) +{ + TRACE( "(%p)\n", overlapped ); + return overlapped->Internal; +} + + +/*********************************************************************** + * GetAddrInfoExCancel (ws2_32.@) + */ +int WINAPI GetAddrInfoExCancel( HANDLE *handle ) +{ + FIXME( "(%p)\n", handle ); + return WSA_INVALID_HANDLE; +} + + +/*********************************************************************** + * GetAddrInfoW (ws2_32.@) + */ +int WINAPI GetAddrInfoW(const WCHAR *nodename, const WCHAR *servname, const ADDRINFOW *hints, ADDRINFOW **res) +{ + struct WS_addrinfo *hintsA = NULL; + ADDRINFOEXW *resex; + int ret = EAI_MEMORY; + + TRACE( "nodename %s, servname %s, hints %p, result %p\n", + debugstr_w(nodename), debugstr_w(servname), hints, res ); + + *res = NULL; + if (hints) hintsA = addrinfo_WtoA( hints ); + ret = WS_getaddrinfoW( nodename, servname, hintsA, &resex, NULL, NULL ); + WS_freeaddrinfo( hintsA ); + if (ret) return ret; + + if (resex) + { + /* ADDRINFOEXW has a layout compatible with ADDRINFOW except for the + * ai_next field, so we may convert it in place */ + *res = (ADDRINFOW *)resex; + do + { + ((ADDRINFOW *)resex)->ai_next = (ADDRINFOW *)resex->ai_next; + resex = resex->ai_next; + } while (resex); + } + return 0; +} + + +/*********************************************************************** + * freeaddrinfo (ws2_32.@) + */ +void WINAPI WS_freeaddrinfo( struct WS_addrinfo *res ) +{ + while (res) + { + struct WS_addrinfo *next; + + HeapFree( GetProcessHeap(), 0, res->ai_canonname ); + HeapFree( GetProcessHeap(), 0, res->ai_addr ); + next = res->ai_next; + HeapFree( GetProcessHeap(), 0, res ); + res = next; + } +} + + +/*********************************************************************** + * FreeAddrInfoW (ws2_32.@) + */ +void WINAPI FreeAddrInfoW( ADDRINFOW *ai ) +{ + while (ai) + { + ADDRINFOW *next; + HeapFree( GetProcessHeap(), 0, ai->ai_canonname ); + HeapFree( GetProcessHeap(), 0, ai->ai_addr ); + next = ai->ai_next; + HeapFree( GetProcessHeap(), 0, ai ); + ai = next; + } +} + + +/*********************************************************************** + * FreeAddrInfoEx (ws2_32.@) + */ +void WINAPI FreeAddrInfoEx( ADDRINFOEXA *ai ) +{ + TRACE( "(%p)\n", ai ); + + while (ai) + { + ADDRINFOEXA *next; + HeapFree( GetProcessHeap(), 0, ai->ai_canonname ); + HeapFree( GetProcessHeap(), 0, ai->ai_addr ); + next = ai->ai_next; + HeapFree( GetProcessHeap(), 0, ai ); + ai = next; + } +} + + +/*********************************************************************** + * FreeAddrInfoExW (ws2_32.@) + */ +void WINAPI FreeAddrInfoExW( ADDRINFOEXW *ai ) +{ + TRACE( "(%p)\n", ai ); + + while (ai) + { + ADDRINFOEXW *next; + HeapFree( GetProcessHeap(), 0, ai->ai_canonname ); + HeapFree( GetProcessHeap(), 0, ai->ai_addr ); + next = ai->ai_next; + HeapFree( GetProcessHeap(), 0, ai ); + ai = next; + } +} diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index c2069198938..9e48fe256fd 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -29,138 +29,7 @@ #include "config.h" #include "wine/port.h"
-#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <limits.h> -#ifdef HAVE_SYS_IPC_H -# include <sys/ipc.h> -#endif -#ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif -#ifdef HAVE_SYS_FILIO_H -# include <sys/filio.h> -#endif -#ifdef HAVE_SYS_SOCKIO_H -# include <sys/sockio.h> -#endif - -#if defined(__EMX__) -# include <sys/so_ioctl.h> -#endif - -#ifdef HAVE_SYS_PARAM_H -# include <sys/param.h> -#endif - -#ifdef HAVE_SYS_MSG_H -# include <sys/msg.h> -#endif -#ifdef HAVE_SYS_WAIT_H -# include <sys/wait.h> -#endif -#ifdef HAVE_SYS_UIO_H -# include <sys/uio.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_NETINET_IN_H -# include <netinet/in.h> -#endif -#ifdef HAVE_NETINET_TCP_H -# include <netinet/tcp.h> -#endif -#ifdef HAVE_ARPA_INET_H -# include <arpa/inet.h> -#endif -#include <ctype.h> -#include <fcntl.h> -#include <errno.h> -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif -#include <stdlib.h> -#ifdef HAVE_ARPA_NAMESER_H -# include <arpa/nameser.h> -#endif -#ifdef HAVE_RESOLV_H -# include <resolv.h> -#endif -#ifdef HAVE_NET_IF_H -# include <net/if.h> -#endif -#ifdef HAVE_LINUX_FILTER_H -# include <linux/filter.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 - -#ifdef HAVE_POLL_H -#include <poll.h> -#endif -#ifdef HAVE_SYS_POLL_H -# include <sys/poll.h> -#endif -#ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -#endif - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "winnls.h" -#include "winsock2.h" -#include "mswsock.h" -#include "ws2tcpip.h" -#include "ws2spi.h" -#include "wsipx.h" -#include "wsnwlink.h" -#include "wshisotp.h" -#include "mstcpip.h" -#include "af_irda.h" -#include "winnt.h" -#define USE_WC_PREFIX /* For CMSG_DATA */ -#include "iphlpapi.h" -#include "ip2string.h" -#include "wine/afd.h" -#include "wine/server.h" -#include "wine/debug.h" -#include "wine/exception.h" -#include "wine/unicode.h" -#include "wine/heap.h" +#include "ws2_32_private.h"
#if defined(linux) && !defined(IP_UNICAST_IF) #define IP_UNICAST_IF 50 @@ -300,8 +169,6 @@ static const WSAPROTOCOL_INFOW supported_protocols[] = }, };
-#define IS_IPX_PROTO(X) ((X) >= WS_NSPROTO_IPX && (X) <= WS_NSPROTO_IPX + 255) - #if defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER) # define LINUX_BOUND_IF struct interface_filter { @@ -381,7 +248,7 @@ union generic_unix_sockaddr char data[128]; /* should be big enough for all families */ };
-static inline const char *debugstr_sockaddr( const struct WS_sockaddr *a ) +const char *debugstr_sockaddr( const struct WS_sockaddr *a ) { if (!a) return "(nil)"; switch (a->sa_family) @@ -896,34 +763,6 @@ static const int ws_socktype_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}, -}; - -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_niflag_map[][2] = { MAP_OPTION( NI_NOFQDN ), @@ -933,30 +772,6 @@ static const int ws_niflag_map[][2] = MAP_OPTION( NI_DGRAM ), };
-static const int ws_eai_map[][2] = -{ - MAP_OPTION( EAI_AGAIN ), - MAP_OPTION( EAI_BADFLAGS ), - MAP_OPTION( EAI_FAIL ), - MAP_OPTION( EAI_FAMILY ), - MAP_OPTION( EAI_MEMORY ), -/* Note: 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 - MAP_OPTION( EAI_NODATA ), -#endif -#ifdef EAI_NONAME - { WS_EAI_NODATA, EAI_NONAME }, -#endif - - MAP_OPTION( EAI_SERVICE ), - MAP_OPTION( EAI_SOCKTYPE ), - { 0, 0 } -}; - static const int ws_poll_map[][2] = { MAP_OPTION( POLLERR ), @@ -1103,7 +918,7 @@ static NTSTATUS sock_get_ntstatus( int err ) } }
-static UINT sock_get_error( int err ) +UINT sock_get_error( int err ) { switch(err) { @@ -1671,7 +1486,7 @@ static inline int do_block( int fd, int events, int timeout ) return pfd.revents; }
-static int +int convert_af_w2u(int windowsaf) { unsigned int i;
@@ -1682,7 +1497,7 @@ convert_af_w2u(int windowsaf) { return -1; }
-static int +int convert_af_u2w(int unixaf) { unsigned int i;
@@ -1693,40 +1508,7 @@ convert_af_u2w(int unixaf) { return -1; }
-static int -convert_proto_w2u(int windowsproto) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(ws_proto_map); i++) - if (ws_proto_map[i][0] == windowsproto) - return ws_proto_map[i][1]; - - /* check for extended IPX */ - if (IS_IPX_PROTO(windowsproto)) - return windowsproto; - - FIXME("unhandled Windows socket protocol %d\n", windowsproto); - return -1; -} - -static int -convert_proto_u2w(int unixproto) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(ws_proto_map); i++) - if (ws_proto_map[i][1] == unixproto) - 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(unixproto)) - return unixproto; - - FIXME("unhandled UNIX socket protocol %d\n", unixproto); - return -1; -} - -static int +int convert_socktype_w2u(int windowssocktype) { unsigned int i;
@@ -1737,7 +1519,7 @@ convert_socktype_w2u(int windowssocktype) { return -1; }
-static int +int convert_socktype_u2w(int unixsocktype) { unsigned int i;
@@ -2130,7 +1912,7 @@ static int is_fd_bound(int fd, union generic_unix_sockaddr *uaddr, socklen_t *ua }
/* Returns 0 if successful, -1 if the buffer is too small */ -static int ws_sockaddr_u2ws(const struct sockaddr* uaddr, struct WS_sockaddr* wsaddr, int* wsaddrlen) +int ws_sockaddr_u2ws(const struct sockaddr *uaddr, struct WS_sockaddr *wsaddr, int *wsaddrlen) { int res;
@@ -6430,37 +6212,6 @@ struct WS_servent* WINAPI WS_getservbyname(const char *name, const char *proto) return retval; }
-/*********************************************************************** - * freeaddrinfo (WS2_32.@) - */ -void WINAPI WS_freeaddrinfo(struct WS_addrinfo *res) -{ - while (res) { - struct WS_addrinfo *next; - - HeapFree(GetProcessHeap(),0,res->ai_canonname); - HeapFree(GetProcessHeap(),0,res->ai_addr); - next = res->ai_next; - HeapFree(GetProcessHeap(),0,res); - res = next; - } -} - -/* helper functions for getaddrinfo()/getnameinfo() */ -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_niflag_w2u(int winflags) { unsigned int i; int unixflags = 0; @@ -6475,631 +6226,6 @@ static int convert_niflag_w2u(int 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; -} - -static int convert_eai_u2w(int unixret) { - int i; - - if (!unixret) return 0; - - for (i=0;ws_eai_map[i][0];i++) - if (ws_eai_map[i][1] == unixret) - return ws_eai_map[i][0]; - - if (unixret == EAI_SYSTEM) - /* There are broken versions of glibc which return EAI_SYSTEM - * and set errno to 0 instead of returning EAI_NONAME. - */ - return errno ? sock_get_error( errno ) : WS_EAI_NONAME; - - FIXME("Unhandled unix EAI_xxx ret %d\n", unixret); - return unixret; -} - -static char *get_fqdn(void) -{ - char *ret; - DWORD size = 0; - - GetComputerNameExA( ComputerNamePhysicalDnsFullyQualified, NULL, &size ); - if (GetLastError() != ERROR_MORE_DATA) return NULL; - if (!(ret = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL; - if (!GetComputerNameExA( ComputerNamePhysicalDnsFullyQualified, ret, &size )) - { - HeapFree( GetProcessHeap(), 0, ret ); - return NULL; - } - 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(LPCSTR nodename, LPCSTR servname, const struct WS_addrinfo *hints, struct WS_addrinfo **res) -{ -#ifdef HAVE_GETADDRINFO - struct addrinfo *unixaires = NULL; - int result; - struct addrinfo unixhints, *punixhints = NULL; - char *nodeV6 = NULL, *fqdn = NULL; - const char *node; - - *res = NULL; - if (!nodename && !servname) - { - 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 - { - 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) - { - char *close_bracket; - - if (node[0] == '[' && (close_bracket = strchr(node + 1, ']'))) - { - nodeV6 = HeapAlloc(GetProcessHeap(), 0, close_bracket - node); - if (!nodeV6) return WSA_NOT_ENOUGH_MEMORY; - lstrcpynA(nodeV6, node + 1, close_bracket - node); - node = nodeV6; - } - } - } - - /* 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 SOCKET_ERROR; - } - - /* 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); - - if (result && (!hints || !(hints->ai_flags & WS_AI_NUMERICHOST)) && node) - { - if (!fqdn && !(fqdn = get_fqdn())) - { - HeapFree(GetProcessHeap(), 0, nodeV6); - return WSA_NOT_ENOUGH_MEMORY; - } - if (!strcmp(fqdn, node) || (!strncmp(fqdn, node, strlen(node)) && fqdn[strlen(node)] == '.')) - { - /* If it didn't work it means the host name IP is not in /etc/hosts, try again - * 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) - { - freeaddrinfo(unixaires); - result = 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) { - 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*len; - 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); - - if (TRACE_ON(winsock)) - { - 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; - } - } - } 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 buildtime.\n"); - return EAI_FAIL; -#endif -} - -static ADDRINFOEXW *addrinfo_AtoW(const struct WS_addrinfo *ai) -{ - ADDRINFOEXW *ret; - - if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ADDRINFOEXW)))) return NULL; - ret->ai_flags = ai->ai_flags; - ret->ai_family = ai->ai_family; - ret->ai_socktype = ai->ai_socktype; - ret->ai_protocol = ai->ai_protocol; - ret->ai_addrlen = ai->ai_addrlen; - ret->ai_canonname = NULL; - ret->ai_addr = NULL; - ret->ai_blob = NULL; - ret->ai_bloblen = 0; - ret->ai_provider = NULL; - ret->ai_next = NULL; - if (ai->ai_canonname) - { - int len = MultiByteToWideChar(CP_ACP, 0, ai->ai_canonname, -1, NULL, 0); - if (!(ret->ai_canonname = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)))) - { - HeapFree(GetProcessHeap(), 0, ret); - return NULL; - } - MultiByteToWideChar(CP_ACP, 0, ai->ai_canonname, -1, ret->ai_canonname, len); - } - if (ai->ai_addr) - { - if (!(ret->ai_addr = HeapAlloc(GetProcessHeap(), 0, ai->ai_addrlen))) - { - HeapFree(GetProcessHeap(), 0, ret->ai_canonname); - HeapFree(GetProcessHeap(), 0, ret); - return NULL; - } - memcpy(ret->ai_addr, ai->ai_addr, ai->ai_addrlen); - } - return ret; -} - -static ADDRINFOEXW *addrinfo_list_AtoW(const struct WS_addrinfo *info) -{ - ADDRINFOEXW *ret, *infoW; - - if (!(ret = infoW = addrinfo_AtoW(info))) return NULL; - while (info->ai_next) - { - if (!(infoW->ai_next = addrinfo_AtoW(info->ai_next))) - { - FreeAddrInfoExW(ret); - return NULL; - } - infoW = infoW->ai_next; - info = info->ai_next; - } - return ret; -} - -static struct WS_addrinfo *addrinfo_WtoA(const struct WS_addrinfoW *ai) -{ - struct WS_addrinfo *ret; - - if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct WS_addrinfo)))) return NULL; - ret->ai_flags = ai->ai_flags; - ret->ai_family = ai->ai_family; - ret->ai_socktype = ai->ai_socktype; - ret->ai_protocol = ai->ai_protocol; - ret->ai_addrlen = ai->ai_addrlen; - ret->ai_canonname = NULL; - ret->ai_addr = NULL; - ret->ai_next = NULL; - if (ai->ai_canonname) - { - int len = WideCharToMultiByte(CP_ACP, 0, ai->ai_canonname, -1, NULL, 0, NULL, NULL); - if (!(ret->ai_canonname = HeapAlloc(GetProcessHeap(), 0, len))) - { - HeapFree(GetProcessHeap(), 0, ret); - return NULL; - } - WideCharToMultiByte(CP_ACP, 0, ai->ai_canonname, -1, ret->ai_canonname, len, NULL, NULL); - } - if (ai->ai_addr) - { - if (!(ret->ai_addr = HeapAlloc(GetProcessHeap(), 0, sizeof(struct WS_sockaddr)))) - { - HeapFree(GetProcessHeap(), 0, ret->ai_canonname); - HeapFree(GetProcessHeap(), 0, ret); - return NULL; - } - memcpy(ret->ai_addr, ai->ai_addr, sizeof(struct WS_sockaddr)); - } - return ret; -} - -struct getaddrinfo_args -{ - OVERLAPPED *overlapped; - LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine; - ADDRINFOEXW **result; - char *nodename; - char *servname; -}; - -static void WINAPI getaddrinfo_callback(TP_CALLBACK_INSTANCE *instance, void *context) -{ - struct getaddrinfo_args *args = context; - OVERLAPPED *overlapped = args->overlapped; - HANDLE event = overlapped->hEvent; - LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine = args->completion_routine; - struct WS_addrinfo *res; - int ret; - - ret = WS_getaddrinfo(args->nodename, args->servname, NULL, &res); - if (res) - { - *args->result = addrinfo_list_AtoW(res); - overlapped->u.Pointer = args->result; - WS_freeaddrinfo(res); - } - - HeapFree(GetProcessHeap(), 0, args->nodename); - HeapFree(GetProcessHeap(), 0, args->servname); - HeapFree(GetProcessHeap(), 0, args); - - overlapped->Internal = ret; - if (completion_routine) completion_routine(ret, 0, overlapped); - if (event) SetEvent(event); -} - -static int WS_getaddrinfoW(const WCHAR *nodename, const WCHAR *servname, const struct WS_addrinfo *hints, ADDRINFOEXW **res, - OVERLAPPED *overlapped, LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine) -{ - int ret = EAI_MEMORY, len, i; - char *nodenameA = NULL, *servnameA = NULL; - struct WS_addrinfo *resA; - WCHAR *local_nodenameW = (WCHAR *)nodename; - - *res = NULL; - if (nodename) - { - /* Is this an IDN? Most likely if any char is above the Ascii table, this - * is the simplest validation possible, further validation will be done by - * the native getaddrinfo() */ - for (i = 0; nodename[i]; i++) - { - if (nodename[i] > 'z') - break; - } - if (nodename[i]) - { - if (hints && (hints->ai_flags & WS_AI_DISABLE_IDN_ENCODING)) - { - /* Name requires conversion but it was disabled */ - ret = WSAHOST_NOT_FOUND; - WSASetLastError(ret); - goto end; - } - - len = IdnToAscii(0, nodename, -1, NULL, 0); - if (!len) - { - ERR("Failed to convert %s to punycode\n", debugstr_w(nodename)); - ret = EAI_FAIL; - goto end; - } - if (!(local_nodenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto end; - IdnToAscii(0, nodename, -1, local_nodenameW, len); - } - } - if (local_nodenameW) - { - len = WideCharToMultiByte(CP_ACP, 0, local_nodenameW, -1, NULL, 0, NULL, NULL); - if (!(nodenameA = HeapAlloc(GetProcessHeap(), 0, len))) goto end; - WideCharToMultiByte(CP_ACP, 0, local_nodenameW, -1, nodenameA, len, NULL, NULL); - } - if (servname) - { - len = WideCharToMultiByte(CP_ACP, 0, servname, -1, NULL, 0, NULL, NULL); - if (!(servnameA = HeapAlloc(GetProcessHeap(), 0, len))) goto end; - WideCharToMultiByte(CP_ACP, 0, servname, -1, servnameA, len, NULL, NULL); - } - - if (overlapped) - { - struct getaddrinfo_args *args; - - if (overlapped->hEvent && completion_routine) - { - ret = WSAEINVAL; - goto end; - } - - if (!(args = HeapAlloc(GetProcessHeap(), 0, sizeof(*args)))) goto end; - args->overlapped = overlapped; - args->completion_routine = completion_routine; - args->result = res; - args->nodename = nodenameA; - args->servname = servnameA; - - overlapped->Internal = WSAEINPROGRESS; - if (!TrySubmitThreadpoolCallback(getaddrinfo_callback, args, NULL)) - { - HeapFree(GetProcessHeap(), 0, args); - ret = GetLastError(); - goto end; - } - - if (local_nodenameW != nodename) - HeapFree(GetProcessHeap(), 0, local_nodenameW); - WSASetLastError(ERROR_IO_PENDING); - return ERROR_IO_PENDING; - } - - ret = WS_getaddrinfo(nodenameA, servnameA, hints, &resA); - if (!ret) - { - *res = addrinfo_list_AtoW(resA); - WS_freeaddrinfo(resA); - } - -end: - if (local_nodenameW != nodename) - HeapFree(GetProcessHeap(), 0, local_nodenameW); - HeapFree(GetProcessHeap(), 0, nodenameA); - HeapFree(GetProcessHeap(), 0, servnameA); - return ret; -} - -/*********************************************************************** - * GetAddrInfoExW (WS2_32.@) - */ -int WINAPI GetAddrInfoExW(const WCHAR *name, const WCHAR *servname, DWORD namespace, GUID *namespace_id, - const ADDRINFOEXW *hints, ADDRINFOEXW **result, struct WS_timeval *timeout, OVERLAPPED *overlapped, - LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine, HANDLE *handle) -{ - int ret; - - TRACE("(%s %s %x %s %p %p %p %p %p %p)\n", debugstr_w(name), debugstr_w(servname), namespace, - debugstr_guid(namespace_id), hints, result, timeout, overlapped, completion_routine, handle); - - if (namespace != NS_DNS) - FIXME("Unsupported namespace %u\n", namespace); - if (namespace_id) - FIXME("Unsupported naemspace_id %s\n", debugstr_guid(namespace_id)); - if (hints) - FIXME("Unsupported hints\n"); - if (timeout) - FIXME("Unsupported timeout\n"); - if (handle) - FIXME("Unsupported cancel handle\n"); - - ret = WS_getaddrinfoW(name, servname, NULL, result, overlapped, completion_routine); - if (ret) return ret; - if (handle) *handle = (HANDLE)0xdeadbeef; - return 0; -} - -/*********************************************************************** - * GetAddrInfoExOverlappedResult (WS2_32.@) - */ -int WINAPI GetAddrInfoExOverlappedResult(OVERLAPPED *overlapped) -{ - TRACE("(%p)\n", overlapped); - return overlapped->Internal; -} - -/*********************************************************************** - * GetAddrInfoExCancel (WS2_32.@) - */ -int WINAPI GetAddrInfoExCancel(HANDLE *handle) -{ - FIXME("(%p)\n", handle); - return WSA_INVALID_HANDLE; -} - -/*********************************************************************** - * GetAddrInfoW (WS2_32.@) - */ -int WINAPI GetAddrInfoW(LPCWSTR nodename, LPCWSTR servname, const ADDRINFOW *hints, PADDRINFOW *res) -{ - struct WS_addrinfo *hintsA = NULL; - ADDRINFOEXW *resex; - int ret = EAI_MEMORY; - - TRACE("nodename %s, servname %s, hints %p, result %p\n", - debugstr_w(nodename), debugstr_w(servname), hints, res); - - *res = NULL; - if (hints) hintsA = addrinfo_WtoA(hints); - ret = WS_getaddrinfoW(nodename, servname, hintsA, &resex, NULL, NULL); - WS_freeaddrinfo(hintsA); - if (ret) return ret; - - if (resex) - { - /* ADDRINFOEXW has layout compatible with ADDRINFOW except for ai_next field, - * so we may convert it in place */ - *res = (ADDRINFOW*)resex; - do { - ((ADDRINFOW*)resex)->ai_next = (ADDRINFOW*)resex->ai_next; - resex = resex->ai_next; - } while (resex); - } - return 0; -} - -/*********************************************************************** - * FreeAddrInfoW (WS2_32.@) - */ -void WINAPI FreeAddrInfoW(PADDRINFOW ai) -{ - while (ai) - { - ADDRINFOW *next; - HeapFree(GetProcessHeap(), 0, ai->ai_canonname); - HeapFree(GetProcessHeap(), 0, ai->ai_addr); - next = ai->ai_next; - HeapFree(GetProcessHeap(), 0, ai); - ai = next; - } -} - -/*********************************************************************** - * FreeAddrInfoEx (WS2_32.@) - */ -void WINAPI FreeAddrInfoEx(ADDRINFOEXA *ai) -{ - TRACE("(%p)\n", ai); - - while (ai) - { - ADDRINFOEXA *next; - HeapFree(GetProcessHeap(), 0, ai->ai_canonname); - HeapFree(GetProcessHeap(), 0, ai->ai_addr); - next = ai->ai_next; - HeapFree(GetProcessHeap(), 0, ai); - ai = next; - } -} - -/*********************************************************************** - * FreeAddrInfoExW (WS2_32.@) - */ -void WINAPI FreeAddrInfoExW(ADDRINFOEXW *ai) -{ - TRACE("(%p)\n", ai); - - while (ai) - { - ADDRINFOEXW *next; - HeapFree(GetProcessHeap(), 0, ai->ai_canonname); - HeapFree(GetProcessHeap(), 0, ai->ai_addr); - next = ai->ai_next; - HeapFree(GetProcessHeap(), 0, ai); - ai = next; - } -} - int WINAPI WS_getnameinfo(const SOCKADDR *sa, WS_socklen_t salen, PCHAR host, DWORD hostlen, PCHAR serv, DWORD servlen, INT flags) { diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h new file mode 100644 index 00000000000..8af23b11ded --- /dev/null +++ b/dlls/ws2_32/ws2_32_private.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2021 Zebediah Figura for CodeWeavers + * + * 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 + */ + +#ifndef __WINE_WS2_32_PRIVATE_H +#define __WINE_WS2_32_PRIVATE_H + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <limits.h> +#ifdef HAVE_SYS_IPC_H +# include <sys/ipc.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif +#ifdef HAVE_SYS_FILIO_H +# include <sys/filio.h> +#endif +#ifdef HAVE_SYS_SOCKIO_H +# include <sys/sockio.h> +#endif + +#if defined(__EMX__) +# include <sys/so_ioctl.h> +#endif + +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +#endif + +#ifdef HAVE_SYS_MSG_H +# include <sys/msg.h> +#endif +#ifdef HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif +#ifdef HAVE_SYS_UIO_H +# include <sys/uio.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif +#ifdef HAVE_NETINET_TCP_H +# include <netinet/tcp.h> +#endif +#ifdef HAVE_ARPA_INET_H +# include <arpa/inet.h> +#endif +#include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <stdlib.h> +#ifdef HAVE_ARPA_NAMESER_H +# include <arpa/nameser.h> +#endif +#ifdef HAVE_RESOLV_H +# include <resolv.h> +#endif +#ifdef HAVE_NET_IF_H +# include <net/if.h> +#endif +#ifdef HAVE_LINUX_FILTER_H +# include <linux/filter.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 + +#ifdef HAVE_POLL_H +#include <poll.h> +#endif +#ifdef HAVE_SYS_POLL_H +# include <sys/poll.h> +#endif +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "winnls.h" +#include "winsock2.h" +#include "mswsock.h" +#include "ws2tcpip.h" +#include "ws2spi.h" +#include "wsipx.h" +#include "wsnwlink.h" +#include "wshisotp.h" +#include "mstcpip.h" +#include "af_irda.h" +#include "winnt.h" +#define USE_WC_PREFIX /* For CMSG_DATA */ +#include "iphlpapi.h" +#include "ip2string.h" +#include "wine/afd.h" +#include "wine/server.h" +#include "wine/debug.h" +#include "wine/exception.h" +#include "wine/unicode.h" +#include "wine/heap.h" + +int convert_af_u2w( int family ) DECLSPEC_HIDDEN; +int convert_af_w2u( int family ) DECLSPEC_HIDDEN; +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; + +const char *debugstr_sockaddr( const struct WS_sockaddr *addr ) DECLSPEC_HIDDEN; + +UINT sock_get_error( int err ) DECLSPEC_HIDDEN; + +#endif